I got a question. Is there anything like a verbose functional language
that attempts to be easily readable?
What I am looking for would be something that looks kind of like
smalltalk, with an emphasis on easy to read code, but fully functional
with immutable data structures and a powerful type system.
I find that many people are confused by the very compact syntax of
existing functional languages such as haskell and ocaml and therefore
miss out on the big advantages of these languages such as referential
transparency.
regards,
Rüdiger
As a beginner, I find SML easily readable.
Michele Simionato
In case you don't insist on purity and can live with dynamic typing, try
Scheme and Common Lisp, especially Common Lisp or ISLISP.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
But there are people that run away screaming when seeing it. And let's
face it: you can write some very difficult to read code in SML that
looks almost as bad as an obfuscated perl contest.
I know quite a few people (mostly engineers) that e.g. prefer visual
basic to C# because of its verbose and "english-like" syntax. These
people are quite intelligent, but nevertheless are quite irritated
even by C-Style languages. So there is no chance at all to get these
people to use something like SML. Which is a shame.
Ho, yes... Sooo readable. What names like car, cdr or progn are supposed
to mean is pretty obvious, indeed.
'Obvious' is something different from being 'readable'.
Obvious is also kind of dangerous, since guessing meaning
from 'obvious' names is sometimes not a good idea.
Once one learn a certain base vocabulary, are the texts
written in that base vocabulary readable? How large
is that base vocabulary? Is the vocabulary based on words
or on other things (like special operators or funny characters (APL))?
How large is the base grammar of the language? Can you
parse the text easily? Are construct groups easily to
identify? Is the combination of constructs explicitly
written in the text?
'Readable' means something different for people with different
knowledge of a language. If one only knows few words in a language,
readable could mean that the used base vocabulary is small or that
some words can be guessed (though that is not always a good idea).
Readable would then also mean to have a simple grammar,
little or no precedence rules, all operations are explicitly
present in the textual presentation and so on.
If one knows more about a language and one is trained on large
amount of texts, then readable means again something different.
Easy to learn might be another criteria.
This is possible in any FPL, by using higher-order functions.
In most cases, that's because the code is getting more compact than what
people are used to.
> I know quite a few people (mostly engineers) that e.g. prefer visual
> basic to C# because of its verbose and "english-like" syntax. These
> people are quite intelligent, but nevertheless are quite irritated
> even by C-Style languages. So there is no chance at all to get these
> people to use something like SML. Which is a shame.
Erlang is somewhat verbose, but rather "non-English".
Dunno otherwise. Clean, maybe?
Regards,
Jo
CL does use quite explicit naming in standard macro names, and the style
of the standard library usually pervades third-party code, too, so CL
programs should indeed be quite "English-like".
And the set of ugly legacy names in Lisp is just a handful or two.
That's not optimal, but better than most.
I'm not sure that humoring the desire of those people is the right
approach though. There are a few techniques and conventions to be
learned for compact FPL code, but that's doable. Somebody really need to
write a book about design patterns in FPLs.
Regards,
Jo
Are they? I always find it difficult to convince people of the practical
utility of referential transparency. OTOH, few people who see an elegant
compact Haskell expression deny that it is a great advantage to express
things so concisely (that is, after they get it explained and understand
what it means). I wonder how a more verbose syntax could improve on the
readability of e.g.
map (+1)
for a function which increments all elements in a list.
Anyway if you are looking for something with a Java-like syntax, take a look
at Scala.
Cheers
Ben
> On Dec 2, 4:09 pm, "michele.simion...@gmail.com"
> <michele.simion...@gmail.com> wrote:
>> On Dec 2, 4:04 pm, "Rüdiger Klaehn" <r...@lambda-computing.com> wrote:
>>
>> > Hello everybody,
>>
>> > I got a question. Is there anything like a verbose functional language
>> > that attempts to be easily readable?
>>
>> As a beginner, I find SML easily readable.
>>
> Me too.
Not me. There are a lot of very good things about SML,
but I find the syntax to be a big stumbling block.
Maybe I'd get used to it if I programmed in SML a lot.
I'm not sure why I don't like SML syntax, but I think:
SML is too terse for my taste.
I have trouble seeing at a glance where syntactic
constructs end.
The parentheses end up in the "wrong" places
(compared to what I'm used to). This appears to be a
misguided attempt to avoid "too many" parens.
Constructs delimited by keywords get nested inside
constructs delimited by parentheses, which seems
inside-out to me.
Common practise is to use abbreviated names too
much for my taste.
I feel the same way about the syntax of OCaml and Haskell.
>...SML is similar to mathematical notation, so if you are
> familiar with college level math you will not have any problems with
> something like SML.
But programming is not math. That's why most programming languages
allow multi-character identifiers, whereas in math, we mostly use
single-letter names, perhaps adorned with overbars and squiggles
and whatnot. In math, if we run out of letters, we start using
greek letters and those squiggles and subscripts and ....
A program of 100,000 lines of code is not unusual, never mind the
programming language. I have never seen a math formula of 100,000
lines.
> But there are people that run away screaming when seeing it. And let's
> face it: you can write some very difficult to read code in SML that
> looks almost as bad as an obfuscated perl contest.
You can write unreadable junk in any language. The interesting
"readability" question must assume that the programmer is at least
_trying_ to write readable code.
> I know quite a few people (mostly engineers) that e.g. prefer visual
> basic to C# because of its verbose and "english-like" syntax. These
> people are quite intelligent, but nevertheless are quite irritated
> even by C-Style languages. So there is no chance at all to get these
> people to use something like SML. Which is a shame.
Indeed. Hence the original poster's question.
- Bob
> Pascal Costanza a écrit :
>> In case you don't insist on purity and can live with dynamic typing,
>> try Scheme and Common Lisp, especially Common Lisp or ISLISP.
>
> Ho, yes... Sooo readable. What names like car, cdr or progn are supposed
> to mean is pretty obvious, indeed.
I can memorize the meaning of car and cdr -- that's not a big hindrance
to me (although I think head and tail would be more civilized).
But most Lisp code uses pretty readable (longish) names for things,
which I like.
I'm not a huge fan of "Lots of Incredibly Silly Parentheses",
but the Lisp-style syntax seems far superior to the
syntax of ML-style languages. At least in Lisp I can tell
where the end of each thing is (perhaps with the help of
a fancy editor, but at worst, by counting parens).
And Lisp syntax has the advantage of being simple.
No need to memorize precedence rules and the like.
- Bob
> Rüdiger Klaehn wrote:
> > I find that many people are confused by the very compact syntax of
> > existing functional languages such as haskell and ocaml and therefore
> > miss out on the big advantages of these languages such as referential
> > transparency.
>
> Are they? I always find it difficult to convince people of the practical
> utility of referential transparency. OTOH, few people who see an elegant
> compact Haskell expression deny that it is a great advantage to express
> things so concisely (that is, after they get it explained and understand
> what it means). I wonder how a more verbose syntax could improve on the
> readability of e.g.
>
> map (+1)
>
> for a function which increments all elements in a list.
(lambda (a-list)
(mapcar (function 1+) a-list))
You explicitly see that it is
* an anonymous function
* takes exactly one argument
* calls MAPCAR with the function (!) 1+ and A-LIST as arguments
No magic going on.
You would even have standard places for documentation strings
and for declarations:
(lambda (a-list)
"Increment each element of a list by 1. Return a fresh list."
(declare (type list a-list))
(mapcar (function 1+) a-list))
>
> Anyway if you are looking for something with a Java-like syntax, take a look
> at Scala.
>
> Cheers
> Ben
> In article <fiv8id$479$1...@registered.motzarella.org>,
> Ben Franksen <ben.fr...@online.de> wrote:
>
>> Rüdiger Klaehn wrote:
>> > I find that many people are confused by the very compact syntax of
>> > existing functional languages such as haskell and ocaml and therefore
>> > miss out on the big advantages of these languages such as referential
>> > transparency.
>>
>> Are they? I always find it difficult to convince people of the practical
>> utility of referential transparency. OTOH, few people who see an elegant
>> compact Haskell expression deny that it is a great advantage to express
>> things so concisely (that is, after they get it explained and understand
>> what it means). I wonder how a more verbose syntax could improve on the
>> readability of e.g.
>>
>> map (+1)
>>
>> for a function which increments all elements in a list.
>
> (lambda (a-list)
> (mapcar (function 1+) a-list))
>
> You explicitly see that it is
>
> * an anonymous function
Good. But lambda's are so useful, that I'd like to have a
very concise syntax for it.
The whole point of using a greek letter is to be concise -- so taking a
greek letter and spelling it out in English is pretty silly, IMHO!
> * takes exactly one argument
Good. But I'd like to see the expected type of a-list,
which would require more syntax.
> * calls MAPCAR with the function (!) 1+ and A-LIST as arguments
Good.
> No magic going on.
Good.
> You would even have standard places for documentation strings
> and for declarations:
>
> (lambda (a-list)
> "Increment each element of a list by 1. Return a fresh list."
Good, but is that "a list of integers" or "a list of numbers"
or what?
- Bob
But sometimes I think that using a keyword instead of a special
character would make things easier to read.
> I have trouble seeing at a glance where syntactic
> constructs end.
> The parentheses end up in the "wrong" places
> (compared to what I'm used to). This appears to be a
> misguided attempt to avoid "too many" parens.
> Constructs delimited by keywords get nested inside
> constructs delimited by parentheses, which seems
> inside-out to me.
> Common practise is to use abbreviated names too
> much for my taste.
>
That is certainly true.
> I feel the same way about the syntax of OCaml and Haskell.
>
> >...SML is similar to mathematical notation, so if you are
> > familiar with college level math you will not have any problems with
> > something like SML.
>
> But programming is not math. That's why most programming languages
> allow multi-character identifiers, whereas in math, we mostly use
> single-letter names, perhaps adorned with overbars and squiggles
> and whatnot. In math, if we run out of letters, we start using
> greek letters and those squiggles and subscripts and ....
>
I guess that is partly because programming languages have had to use
ASCII characters. Sometimes I would love to use greek characters and
subscripts in programs.
> A program of 100,000 lines of code is not unusual, never mind the
> programming language. I have never seen a math formula of 100,000
> lines.
>
I have never seen a program with 100000 lines of code in the same
scope either. So the comparison is not completely fair. I have to
agree that I prefer long, descriptive identifiers though.
> > But there are people that run away screaming when seeing it. And let's
> > face it: you can write some very difficult to read code in SML that
> > looks almost as bad as an obfuscated perl contest.
>
> You can write unreadable junk in any language. The interesting
> "readability" question must assume that the programmer is at least
> _trying_ to write readable code.
>
I was refering to some examples in books I saw. The authors probably
thought they were really clever, but for me it was kind of hard to
follow.
So is english. There are a lot of words with greek letters
spelled out. If you don't like it use some other word.
Some people used the greek letter lambda in source code.
But that is rare and requires a lambda in the character
set and on the keyboard to be useful. I think the letter lambda
has been used before Lisp to denote functions. So the
benefit was to relate to a existing concept, but spelling
out the greek character.
> > * takes exactly one argument
>
> Good. But I'd like to see the expected type of a-list,
> which would require more syntax.
There was an example below.
>
> > * calls MAPCAR with the function (!) 1+ and A-LIST as arguments
>
> Good.
>
> > No magic going on.
>
> Good.
>
> > You would even have standard places for documentation strings
> > and for declarations:
> >
> > (lambda (a-list)
> > "Increment each element of a list by 1. Return a fresh list."
>
> Good, but is that "a list of integers" or "a list of numbers"
> or what?
Usually numbers. But whatever you have defined 1+ to do.
>
> - Bob
> OTOH, few people who see an elegant
> compact Haskell expression deny that it is a great advantage to express
> things so concisely (that is, after they get it explained and understand
> what it means). I wonder how a more verbose syntax could improve on the
> readability of e.g.
>
> map (+1)
>
> for a function which increments all elements in a list.
>
> Anyway if you are looking for something with a Java-like syntax, take a look
> at Scala.
>
I like scala. But I think one should be able to do even better.
Besides, I fear that scala will stay an academic language that is
constantly changing.
>>>>> "Robert" == Robert A Duff <bob...@shell01.TheWorld.com> writes:
Robert> I can memorize the meaning of car and cdr -- that's not a big hindrance
Robert> to me (although I think head and tail would be more civilized).
Well, then what about first and rest? Is that more to your liking?
It is part of CL after all.
'Andreas
--
Wherever I lay my .emacs, there's my $HOME.
How would you like:
{list|:ok list every {element|:ok element + 1}}
or - in a failsafe version:
{list|:try list every {element|:try element + 1}}
or - excluding non-incrementable elements:
{list|:ok list each {element|:try element + 1}}
or - passing non-incrementable elements unchanged:
{list|:ok list every {element|:ok element + 1 or: element}}
or - isolating the increment function:
;increment {element|:ok element + 1};
{list|:ok list every (increment)}
or - also isolating the map concept:
;increment {element|:ok element + 1};
;map {function|:ok {list|:ok list every (function)}};
(map) (increment)
(It's my own still unpublished PILS language - I need a Linux/GTK
version before I go public...)
I know of a famous CS guru, known by the name of E.W.Dijkstra, who violently
disagrees ;-) To quote:
"Programming = Mathematics + Murphy's Law"
Cheers
Ben
I work with people who do multithreaded programming the whole day and I
speak from experience when I tell you that such people are not easily
convinced.
BTW, the presence of multiple cores is (IMO) not necessarily best exploited
by writing multi-threaded code (threads = processes that communicate via
shared memory) but rather by annotating pure code with (semantically
transparent) hints for the compiler. However, maybe that was what you
meant, and internally the run-time system of course uses threads to
paralellize computations.
Cheers
Ben
On Mon, 3 Dec 2007, Ben Franksen wrote:
> > But programming is not math.
>
> I know of a famous CS guru, known by the name of E.W.Dijkstra, who violently
> disagrees ;-) To quote:
>
> "Programming = Mathematics + Murphy's Law"
Hmm, so if you say
"It is not true that programming is not math"
and
"Programming = Mathematics + Murphy's Law"
we get
Murphy's Law = 0
whatever that means :)
- Ville Oikarinen
I can write a correct program using fine grained locking when I
concentrate. But during normal everyday development, when the phone is
ringing every 30 minutes? No way.
> BTW, the presence of multiple cores is (IMO) not necessarily best exploited
> by writing multi-threaded code (threads = processes that communicate via
> shared memory) but rather by annotating pure code with (semantically
> transparent) hints for the compiler. However, maybe that was what you
> meant, and internally the run-time system of course uses threads to
> paralellize computations.
>
Indeed, that is what I meant. In the project I am currently involved
with, we try to avoid shared mutable state whenever possible.
Everything that is shared over multiple threads is immutable, and
everything that is mutable stays on one thread.
There is a mechanism to move state from one thread to another, but
other than that the threads are completely independent. They are
almost like processes, except that they share immutable data for
efficiency.
>
> Ho, yes... Sooo readable. What names like car, cdr or progn are supposed
> to mean is pretty obvious, indeed.
but you can always write a small helper function in Scheme:
(define (head x)
(car x))
Okay it is not very safe and assumes a list is being passed. But
anyway that is what I often do in my Scheme code.
And if you settle yourself down to something like Scheme its srfi-1
list facilities you almost get all the bells and whistles of nice
'functional list based programming'.
I am now waiting on the arrival of the guy who tells: "Scheme and
Common Lisp ist unreadable .. you guess all the (((((()))))))
Btw: Clean, though a pure tragedgy and never got the start off in any
community, would be first class first beginners 'genuine' functional
prohramming language. It has clean syntax.
The problem being that - extra function call overhead set aside - it's
*not* the standard. So when reading third-part material (either source
code, tutorials etc), you still have to remember all those somewhat
alien names...
(snip)
> I am now waiting on the arrival of the guy who tells: "Scheme and
> Common Lisp ist unreadable .. you guess all the (((((()))))))
That has never been a problem to me - my editor (emacs) does a good job
wrt/ parenthesis !-)
From my experience, it may greatly help.
> Obvious is also kind of dangerous, since guessing meaning
> from 'obvious' names is sometimes not a good idea.
When I started learning Python some years ago, one of the first things
that amazed me was that, 9 times out of 10, the feature I was looking
for had one of the most obvious names to me - it was almost a game :
writing the code *without* looking at the doc, and see if it worked. And
quite a lot of times, it *did* work.
As you may have guessed, my experience with Common Lisp has been quite
different...
In the context of the OP's question, I'd say that there's a strong
relationship between "obvious" and "readable", ie you don't have to
learn a whole brand new vocabulary for well known concepts.
(snip otherwise sensible considerations)
> klohm...@yahoo.de a écrit :
> > On Dec 2, 5:09 pm, Bruno Desthuilliers
> > <bdesth.quelquech...@free.quelquepart.fr> wrote:
> >
> >
> >>Ho, yes... Sooo readable. What names like car, cdr or progn are supposed
> >> to mean is pretty obvious, indeed.
> >
> >
> > but you can always write a small helper function in Scheme:
> >
> > (define (head x)
> > (car x))
> >
> > Okay it is not very safe and assumes a list is being passed. But
> > anyway that is what I often do in my Scheme code.
>
> The problem being that - extra function call overhead set aside
(define head car)
> - it's
> *not* the standard. So when reading third-part material (either source
> code, tutorials etc), you still have to remember all those somewhat
> alien names...
True. I prefer a standard vocabulary. But if the user group
is large enough or the code base is large enough,
having an optimized vocabulary might be useful.
>
> (snip)
>
> > I am now waiting on the arrival of the guy who tells: "Scheme and
> > Common Lisp ist unreadable .. you guess all the (((((()))))))
>
> That has never been a problem to me - my editor (emacs) does a good job
> wrt/ parenthesis !-)
Or just use 'first' and 'rest' which are already in Common Lisp.
> I am now waiting on the arrival of the guy who tells: "Scheme and
> Common Lisp ist unreadable .. you guess all the (((((()))))))
If you can still see the parentheses, you need to write a little
more Lisp. ;-)
Regards,
Patrick
------------------------------------------------------------------------
S P Engineering, Inc. | Large scale, mission-critical, distributed OO
| systems design and implementation.
p...@spe.com | (C++, Java, Common Lisp, Jini, middleware, SOA)
I have this problem with Haskell, sometimes. It isn't the
syntax, I believe, it's the extreme degree of abstraction.
It's a virtue of the language, that can be over-exercised.
I catch myself doing the same - paring down some code until
nothing remains that isn't essential. The problem with this
is that those inessential parameters and whatnot may carry
some information, cues that remind the reader why this function
exists.
I expect that with more exposure to this, I grow less dependent
on such cues, but in the end I do think it adds up to a loss
of readability. I don't know if programs are mathematical, but
I am fairly sure people aren't.
Donn Cave, do...@u.washington.edu
>Rainer Joswig <jos...@lisp.de> writes:
>
>> (lambda (a-list)
>> (mapcar (function 1+) a-list))
>>
>> You explicitly see that it is
>>
>> * an anonymous function
>
>Good. But lambda's are so useful, that I'd like to have a
>very concise syntax for it.
>
>The whole point of using a greek letter is to be concise -- so taking a
>greek letter and spelling it out in English is pretty silly, IMHO!
Well, I don't see a lambda on my keyboard - or any other Greek letters
for that matter. But all you need is an editor that supports them.
PLT Scheme has a graphic editor that inserts the lambda symbol in the
code when you press "ctrl-\" and expands it to "lambda" internally.
>> * takes exactly one argument
>
>Good. But I'd like to see the expected type of a-list,
>which would require more syntax.
Lists are generic - you want to know the type of the elements. But
what if the list is heterogeneous and the function to be mapped over
it is selective? Or have you never done that?
George
--
for email reply remove "/" from address
Erlang is verbose, compared to e.g. Haskell. Most find it readable.
It has strong dynamic typing, in the sense that types cannot be
subverted, but no compile-time type checking to speak of.
BR,
Ulf W
No language attempts to be unreadable so you're really only asking for
verbose FPLs, of which there are many. Look at Scala and Lisp, for example.
> I find that many people are confused by the very compact syntax of
> existing functional languages such as haskell and ocaml and therefore
> miss out on the big advantages of these languages such as referential
> transparency.
The value-add of Haskell and OCaml (and F#) is primarily their powerful
static type systems.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/products/?u
It is not that alien:
(define head car)
(define tail cdr)
or
(define first car)
(define rest cdr)
Have you ever looked at Ruby at looked at "Matz's law of least
surprise"?
Everything is guaranteed to just "intuitively" "make sense".... at
least to him! :)
But the same arguments holds for all the other langues too. I mean
sure Python will give you some nice to understand basic meanings but
once in all the object oriented programming battle in Python you are
still left with something only often the creater understood and had in
mind how to interpret it. Not to speak of C++.
Maybe it's necessary to spell this out:
There is no such thing as a 'natural' syntax. Every programming language
syntax needs practice, and once you get used to one (of the good ones),
you can probably work with pretty much everything.
Syntax is also a personal choice (as is programming style). It varies
how much time you're willing to invest to learn a new syntax, and it
also varies how much each one can get used to a new syntax (or a new
programming style).
It may very well be that what works very well for one person may not
work for another person at all (and this can depend on a lot of factors,
including problem domain, overall goals, etc.). [That's why claims about
single languages being the optimal choice for everyone, as for example
suggested by some gravitationally challenged amphibians, are highly
questionable.]
The OP asked for a functional language whose syntax is closer to
Smalltalk. I still believe that Scheme and Common Lisp fulfill that
criterion more than other functional languages, for a broad
interpretation of that term.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
> > I find that many people are confused by the very compact syntax of
> > existing functional languages such as haskell and ocaml and therefore
> > miss out on the big advantages of these languages such as referential
> > transparency.
>
> The value-add of Haskell and OCaml (and F#) is primarily their powerful
> static type systems.
>
True. The type system is a big plus. But for me another huge advantage
is that it is almost trivial to use multiple cores using functional
code.
I would say there are two trade-offs between brevity and clarity. If the
syntax is too terse then it becomes less readable but also if it is too
verbose then it becomes less readable. Experience lets you handle extreme
brevity but you cannot control verbosity.
> Or would you say that e.g. Perl attempts to be easily readable?
For its purpose it does, yet. How readable is this Perl regexp for an
identifier:
[a-zA-Z][a-zA-Z0-9]*
compared to the parser combinator equivalent from an FPL:
let digit c = '0' <= c && c <= '9';;
let alpha c = 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z';;
let alphanum c = digit c || alpha c;;
let rawident = some alpha ++ several alphanum >| (IDENT << collect)
The latter is certainly more verbose but is it really more readable? I would
say that the latter is so unreadable that it drove people to build regular
expression engines for almost all FPLs.
The same trade-off crops up everywhere:
Mathematica: {1, 2} /. {a_, b_} -> {b, a}
F#: (1, 2) |> fun (a, b) -> b, a
Lisp: ((lambda (pair) (cons (cdr pair) (car pair))) (cons 1 2))
The last one is more verbose but is it really more readable? Lisp's car and
cdr are no match for the pattern matchers found in all modern FPLs.
>> > I find that many people are confused by the very compact syntax of
>> > existing functional languages such as haskell and ocaml and therefore
>> > miss out on the big advantages of these languages such as referential
>> > transparency.
>>
>> The value-add of Haskell and OCaml (and F#) is primarily their powerful
>> static type systems.
>
> True. The type system is a big plus. But for me another huge advantage
> is that it is almost trivial to use multiple cores using functional
> code.
The Haskell community have been making a lot of noise about their new
parallel stuff lately but all I've seen is Fibonacci number generator that
was very slow and only used one of my two cores, i.e. is broken. There is
more use of parallelism in the OCaml world (particularly in industry) but I
would not call it easy. F# makes it easy but its implementation means
you'll need to run >5 cores flat out to beat a single core running OCaml.
hello JON: most of the time i am not agreeing with you. however, i
find your motivation always informative from some point of view.
But why the hell do you insisting on writing code always in some
weirad kind of a 1-liner?
I mean why not (I do not have an emacs editor right now):
==
((lambda (pair)
(cons (cdr pair) (car pair)))
(cons 1 2))
==
You often happen to post 1-liners (even in you favorite language
OCaml). I do not understand you why it is being important for you to
write code as compact as possible when there is no need for?
Thank you. I'm sure we'll all agree that this is a hopelessly subjective
discussion at any rate. :-)
> But why the hell do you insisting on writing code always in some
> weirad kind of a 1-liner?
>
> I mean why not (I do not have an emacs editor right now):
> ==
> ((lambda (pair)
> (cons (cdr pair) (car pair)))
> (cons 1 2))
> ==
>
> You often happen to post 1-liners (even in you favorite language
> OCaml). I do not understand you why it is being important for you to
> write code as compact as possible when there is no need for?
Simply because it is idiomatic in OCaml. Moreover, this is the way OCaml
itself prints OCaml code:
$ cat >foo.ml
let ( |> ) x f = f x;;
(1, 2) |> (fun (a, b) -> b, a);;
$ camlp4of foo.ml
let ( |> ) x f = f x
let _ = (1, 2) |> (fun (a, b) -> (b, a))
But why do want to force Scheme or Common Lisp stype into OCaml style?
This does not make sense to me.
Sure. We can draw the same comparison with the Lisp code spread across
several lines but I do not think it changes the outcome:
Mathematica: {1, 2} /. {a_, b_} -> {b, a}
F#: (1, 2) |> fun (a, b) -> b, a
Lisp: ((lambda (pair)
(cons (cdr pair) (car pair)))
(cons 1 2))
--
Now the lisp code is readable at least. if it is understandable is
another topic.
[snip]
> > True. The type system is a big plus. But for me another huge advantage
> > is that it is almost trivial to use multiple cores using functional
> > code.
>
> The Haskell community have been making a lot of noise about their new
> parallel stuff lately but all I've seen is Fibonacci number generator that
> was very slow and only used one of my two cores, i.e. is broken. There is
> more use of parallelism in the OCaml world (particularly in industry) but I
> would not call it easy. F# makes it easy but its implementation means
> you'll need to run >5 cores flat out to beat a single core running OCaml.
>
I was not talking about haskell but about referentially transparent
code in general. A current project of mine is written in C# using
mostly immutable data structures. Using immutable data structures in
C# can be somewhat painful, but multithreading is quite easy compared
to a lock-based approach.
By the way: The performance of F# will certainly improve significantly
with the next CLR update. The CLR currently has some very embarassing
limitations compared to the JVM. Most importantly this:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93858
If F# uses structs internally, it will certainly benefit from this.
What makes multithreading easier in F# than in OCAml? I thought it was
more or less the same language.
regards,
Rüdiger Klaehn
Yes.
> Everything is guaranteed to just "intuitively" "make sense".... at
> least to him! :)
Indeed. There's some equivalent joke in Python's Zen:
"""
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
"""
And I - of course - realize that what's "obvious" to me may not be
obvious to you...
Please reread my post with more attention.
Sorry, I never had much problems with Python's object model. And by
experience (most of my work is on OSS, so I tend to read quite a lot of
third-part code), the average Python code tend to be mostly readable
when compared to some other languages I have working experience with.
> Not to speak of C++.
Hem. I would not compare Python to C++ (is C++ comparable to anything,
anyway ?-)
Pascal, it has *nothing* to do with syntax - it's about the *names*.
(snip - we obviously agree on this part, but that's not what I'm talking
about)
> The OP asked for a functional language whose syntax is closer to
> Smalltalk.
While he mentions syntax too, that's not how I understood the question.
To me, it was more about overall readability - which includes syntax but
is no restricted to it. Hence my joke about lisp.
Now I may of course be totally wrong !-)
>No language attempts to be unreadable ...
You've obviously never seen BrainFuck.
http://en.wikipedia.org/wiki/Brainfuck
> Now I may of course be totally wrong !-)
Me too. :)
I justed wanted to make sure that Scheme and Lisp are also considered. I
have no problems if people decide against using them.
Well, for a sample of one, I now find it understandable (and gives me
some hint as to what the unknown operators /. and |> in the other two
languages is). If you further, change car and cdr to first and rest
or head and tail like in some other thread, then you get closer to
something that the "general English speaking public" is likely to
understand. Replacing cons with list (although that may change the
semantics in an undesired way) makes it even more understandable.
Since, this is relevant to the start/title of this thread, verbose
functional languages, here lisp appears to be the winner. I'd be
curious to see the same line translated into scala to see if that was
sufficiently understanable.
I think Donn Cave's insight is correct here, "I don't know if programs
are mathematical, but I am fairly sure people aren't." In fact,
although I was trained as a mathematician, I find the overly terse
mappings of most FP to be obfuscating more than it is elegant.
Perhaps, I'm just looking for the Cobol of FPs, something like
Evaluate
the list with elements 1 and 2
applied as a parameter to
the anonymous function that takes one parameter which
makes a list with elements
the second element of the parameter
and
the first element of the parameter.
I could probably give that to my wife, an Opera singer, and with her
English-Bulgarian dicitionary, she could probably tell me what it
meant. She would need the dictionary because terms like evaluate,
applied, anonymous function, parameter, and element are probably not
in her working vocabulary.
Now, I don't think the demand is for something quite that verbose, but
it was intended as an extreme example. Moreover, when I read the lisp,
that is essentialy what I read. Well, once I parsed the two parens at
the beginning and saw that we were applying the result of an
expression as a function.
And that gets to the verbosity point. Even in the lisp, one has to
recognize that we are using the result of an expression as a function,
and the syntax to do so is so terse that unless one regularly reads
that kind of lisp (and I don't), one is likely to miss it, and having
missed it, one then reads formulating gobbledy-gook until one gets to
the point, where one's internal parser says too many errors, go back
and determine what clue I missed. The indented version helped with
that, as which parts went together were more obvious.
Maybe what I'm looking for is an FP to English program like those
programs which translated C declarations to and from English.
Well,that would be a bit like AppleScript, which has a functional
flavor.
A sub-routine for replacing items in a list by matching (from Apple's
page on Applescript):
on replace_matches(this_list, match_item, replacement_item, replace_all)
repeat with i from 1 to the count of this_list
set this_item to item i of this_list
if this_item is the match_item then
set item i of this_list to the replacement_item
if replace_all is false then return this_list
end if
end repeat
return this_list
end replace_matches
>
> I could probably give that to my wife, an Opera singer, and with her
> English-Bulgarian dicitionary, she could probably tell me what it
> meant. She would need the dictionary because terms like evaluate,
> applied, anonymous function, parameter, and element are probably not
> in her working vocabulary.
>
> Now, I don't think the demand is for something quite that verbose, but
> it was intended as an extreme example. Moreover, when I read the lisp,
> that is essentialy what I read. Well, once I parsed the two parens at
> the beginning and saw that we were applying the result of an
> expression as a function.
>
> And that gets to the verbosity point. Even in the lisp, one has to
> recognize that we are using the result of an expression as a function,
> and the syntax to do so is so terse that unless one regularly reads
> that kind of lisp (and I don't), one is likely to miss it, and having
> missed it,
That's why in Common Lisp the full version is:
(funcall (function
(lambda (pair)
(cons (cdr pair) (car pair))))
(cons 1 2))
Which usually is written a bit shorter as:
(funcall #'(lambda (pair)
(cons (cdr pair) (car pair)))
(cons 1 2))
FUNCALL invokes the first parameter (a function object)
on the arguments.
That the funcall can be omitted is only a special case
that has been added to Common Lisp to please some people.
The default is to use FUNCALL. FUNCTION is a special
operator that says that the enclosed thing is a function.
> one then reads formulating gobbledy-gook until one gets to
> the point, where one's internal parser says too many errors, go back
> and determine what clue I missed. The indented version helped with
> that, as which parts went together were more obvious.
>
> Maybe what I'm looking for is an FP to English program like those
> programs which translated C declarations to and from English.
Not very idiomatic, though.
Not sure what this one-liner is supposed to mean. But you would rather
say something like this:
; Scheme & Lisp
((lambda (a b) (cons b a)) 1 2)
or
; Scheme & Lisp
(apply (lambda (a b) (cons b a)) (list 1 2))
or
; Common Lisp
(destructuring-bind (a . b) (cons 1 2)
(cons b a))
...and several other variations. Again, it depends on what you actually
want to do here...
keyboard !
This one is worth an entry in fortune...
> I'm not sure why I don't like SML syntax, but I think:
> SML is too terse for my taste.
That is a new one. Well, to be honest, I've heard that opinion from a
few programmers, but most people I know who actually know a little
SML, would likely agree that the syntax of SML is accurately described
as "baroque" (http://en.wikipedia.org/wiki/Baroque#Modern_usage , in
particular "excessive ornamentation"). There are a couple places in
the syntax where SML requires a keyword that could be easily dropped
without introducing any ambiguity to the grammar. There are also
several keywords used for specifying "blocks" that could also be
replaced to use simple parentheses without ambiguity. There are also
several relatively long keywords.
> I have trouble seeing at a glance where syntactic constructs end.
Funny, I've never had trouble with that in SML, in particular.
Here are a few notes on the syntax of SML (no attempt is made for
completeness). The expression that is typically considered difficult
to read (although I've never had major problems with it) due to the
lack of an explicit terminator is nested use of the case expression:
case ...
of ... => ...
[ | ... => ... ]*
Perhaps similarly surprising is the handle expression (typically "try"
in other languages):
... handle ... => ...
[ | ... => ... ]*
I use handle expressions rarely, as I usually use an implementation of
the try-in-unless construct of Benton and Kennedy for exception
handling purposes and other functions for scoped resource management.
Anonymous functions also do not have a terminating keyword, but they
are often written inside parentheses:
fn ... => ...
[ | ... => ... ]*
Other expression are simpler in that regard. Conditional expressions
always include the else part:
if ... then ... else ...
Local binding forms, whether at the declaration level or at the
expression level, have a terminator:
local ... in ... end (* declaration *)
let ... in ... [ ; ... ]* end (* expression *)
The same goes for sequential execution:
( ... [ ; ... ]* )
A declaration ends when the scope ends (keyword "in" or "end") or when
a new declaration begins (keywords "fun", "val", "structure",
"signature", "functor", "local", "type", "exception", "datatype",
"open", "infix", "nonfix", and "infixr").
The following page contains a few more notes on syntax:
http://mlton.org/StandardMLGotchas
> The parentheses end up in the "wrong" places (compared to what I'm
> used to). This appears to be a misguided attempt to avoid "too
> many" parens.
No, it is not. :-) Lightweight syntax for calling functions is crucial
for stuff like combinator libraries.
> Constructs delimited by keywords get nested inside constructs
> delimited by parentheses, which seems inside-out to me.
That is also something I consider an advantage and is shared by most
FP languages. The advantage is that constructs can be nested rather
freely, without arbitrary restrictions. In a typical imperative
language, there is a separation between statements and expressions,
which is often quite awkward and forces one to introduce additional
syntactic complexity.
> Common practise is to use abbreviated names too much for my taste.
This may be partially true, but certainly isn't a property of the
syntax. You can use as long names as you want.
-Vesa Karvonen
Can you do that with a destructuring bind? Something like:
((lambda ((a . b)) (b . a)) (1 . 2))
No.
Standard function parameters don't provide destructuring.
(b . a) is also not a valid expression, since b is not a function,
macro or special operator.
(1 . 2) is also not a valid expression, since 1 is not a function,
macro or special operator.
Destructuring is provided with DESTRUCTURING-BIND.
(destructuring-bind (a . b) (cons 1 2)
(cons b a))
You can easily add a version with a shorter name
or functions that do destructuring, but there is
nothing else by default.
Oh, ok, somehow I thought they did, it's been a while.
Python version: (lambda (a,b): (b,a)) (1,2)
Haskell: (\(a,b) -> (b,a)) (1,2)
Java: class FlipTwoItemsInATuple (500 lines of code snipped)
Vesa Karvonen <vesa.k...@cs.helsinki.fi> writes:
[snip]
> The following page contains a few more notes on syntax:
>
> http://mlton.org/StandardMLGotchas
I'll have to read that before commenting on the above snipped stuff.
I'll just make some comments on the stuff below:
>> The parentheses end up in the "wrong" places (compared to what I'm
>> used to). This appears to be a misguided attempt to avoid "too
>> many" parens.
>
> No, it is not. :-) Lightweight syntax for calling functions is crucial
> for stuff like combinator libraries.
Smiley noted. ;-)
But f(x) isn't exactly heavy! Why is f x so much better?
And then you end up having to write (f x) when it's nested
inside certain other things, which is what I meant by the "wrong"
place above. I freely admit this is heavily influenced by
what I'm used to.
>> Constructs delimited by keywords get nested inside constructs
>> delimited by parentheses, which seems inside-out to me.
>
> That is also something I consider an advantage and is shared by most
> FP languages. The advantage is that constructs can be nested rather
> freely, without arbitrary restrictions.
I agree with the "free nesting" idea. I just don't like the syntax.
This syntactic problem doesn't exist in Lisp, because every construct is
introduced by a paren, not a keyword. I'm not a big fan of Lisp, but I
find that from a syntactic point of view, Lisp is easier to read than
ML-style languages (for me!).
>...In a typical imperative
> language, there is a separation between statements and expressions,
> which is often quite awkward and forces one to introduce additional
> syntactic complexity.
Yes, I agree about that.
>> Common practise is to use abbreviated names too much for my taste.
>
> This may be partially true, but certainly isn't a property of the
> syntax. You can use as long names as you want.
Well, I can use long names myself, but I want to read _other_ people's
code. So common practise matters. And if I disobey common practise,
then others will have trouble reading _my_ code, which is equally bad.
- Bob
Because of currying, maybe. You'd have to write (f x y z) as
f(x)(y)(z) or even ((f(x))(y))(z).
> That's why in Common Lisp the full version is:
>
> (funcall (function
> (lambda (pair)
> (cons (cdr pair) (car pair))))
> (cons 1 2))
>
> Which usually is written a bit shorter as:
>
> (funcall #'(lambda (pair)
> (cons (cdr pair) (car pair)))
> (cons 1 2))
>
Good point. I personally like the more explicit Common Lisp version
even better, although not the version with #' (I presume thats a
shorthand for function quotation), but disliking special character
sequences is probably just me. There wouldn't be lots of languages
that have all sorts of different special character sequence operators,
macros, and what-have-you, if people didn't like the terseness they
provide.
My problem is that I find myself ever more dis-inclined to learn new
notation and syntax--new ideas, concepts, paradigms, patterns,
etc. yes, but new syntax not so much. And, that gets back to what is
nice about the full form Common Lisp version. It exposes with the
function and funcall forms parts of the process that is otherwise
hidden from view, and that exposes the concepts, and by doing it in
with words, it means one has some idea of what those concepts are.
Moreover, one can often look up the words if one wants to peruse
further. Special character sequences, while more compact don't
generally give one a name for the concept, I doubt I could google #'
and get any insight. In fact, just looking at this code, I can see
that in common lisp there is a distinction between a function and a
lambda. Now, at the moment I don't care, but if I were working with
some CL code, I might want to determine if that difference is
important.
So, thanks for that example....
F# basically implements its own versions of anything that the CLR does
suboptimally and inlining is one such thing.
After extensive benchmarking, we decided that complex numbers are the only
data structure that warrants being a struct in F# rather than a class.
> What makes multithreading easier in F# than in OCAml?
You can do threads in OCaml but they will never run concurrently because
OCaml's GC is not multithreaded.
> I thought it was more or less the same language.
The intersection of OCaml and F# is usefully large (bigger than the whole of
SML) but the languages are quite different in many ways. In this context,
F# provides native constructs and syntactic support for Erlang-style
message passing and asynchronous workflows. OCaml has libraries but they
are not part of the language (and I haven't played with them).
> The expression that is typically considered difficult
> to read (although I've never had major problems with it) due to the
> lack of an explicit terminator is nested use of the case expression:
> Local binding forms, whether at the declaration level or at the
> expression level, have a terminator:
It should have been the other way around: case with a terminator,
let without.
--
__("< Marcin Kowalczyk
\__/ qrc...@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Huh?
We've had that one before, but: F# is lacking most of the ML module
system, so you need to apply a very weird metric to make this
statement true (the module system being a major part of what defines
the ML language family of today).
- Andreas
> Evaluate
> the list with elements 1 and 2
> applied as a parameter to
> the anonymous function that takes one parameter which
> makes a list with elements
> the second element of the parameter
> and
> the first element of the parameter.
>
> I could probably give that to my wife, an Opera singer, and with her
> English-Bulgarian dicitionary, she could probably tell me what it
> meant. She would need the dictionary because terms like evaluate,
> applied, anonymous function, parameter, and element are probably not
> in her working vocabulary.
And that's exactly why the code is better *readable*, but reading and
understanding are different things, so it's not better understandable.
On the contrary, IMHO.
And remember that your 8 liner with ca. 40 words is an absolutely
trivial piece of code.
It would be not too long before users of that language demand
abbreviations for the verbose and self evident stuff:
- instead "evaluate X" write just "X"
- instead "X applied as a paramter to Y" write "Y X"
- instead "list with elements a,b, ... and z" write "[a,b,...,z]"
- instead "the anonymous function that takes one parameter which"
write "\x ->"
.... and so on.
But, if you really like to read such stuff, one could write a Haskell
(OCaml, Lisp or whatever) reader, that reads a program to you. Would
be nice to have when one can't get sleep :)
For example:
map (\(a,b) -> (b,a+1)) [(1, "foo"), (2, "bar")]
Evaluate the application of
an anonymous function that takes one parameter
that is a 2-tuple, which,
given that the first component of said tuple is called a
and the second component of the aforementioned tuple is called b,
evaluates
a tuple where the first component is b
and the second component is the result of
evaluation of the application of
a
and the constant one
to the function +
.....
> That is a new one. Well, to be honest, I've heard that opinion from a
> few programmers, but most people I know who actually know a little
> SML, would likely agree that the syntax of SML is accurately described
> as "baroque" (http://en.wikipedia.org/wiki/Baroque#Modern_usage , in
> particular "excessive ornamentation"). There are a couple places in
> the syntax where SML requires a keyword that could be easily dropped
> without introducing any ambiguity to the grammar. There are also
> several keywords used for specifying "blocks" that could also be
> replaced to use simple parentheses without ambiguity. There are also
> several relatively long keywords.
But, with one exception, core SML lacks keywords at the ends of blocks.
This bugs me a bit, too. I've also run into the
if condition then
something ();
else
somethingElse ();
oneMoreThing ();
continueProcessing ();
problem. 8-/
> But f(x) isn't exactly heavy! Why is f x so much better?
Without parentheses, you can write
val i : int = ...
...
printf S "The value of i is: " I i S ".\n" $;
The alternative would be:
printf (S ("The value of i is: " (I (i (S (".\n" ($)))))));
That may have been true ten years ago but the ML family of languages has
evolved better alternatives since then and the rest of the module system is
now vestigial.
Look at some of the features that are compatible between OCaml and F#:
. functional record update
. array expressions and patterns
. or-patterns
. guarded patterns
. Ad-hoc polymorphic printing (printf)
. Can export infix operator definitions from modules
. Module hierarchy can be reflected in source directory structure
. Extensive currying in the stdlib
. Mutable record fields
. Polymorphic structural hashing
. Marshalling
These are all far more widely exploited than functors and none of these
features are even in SML.
From my point of view, your statement is equivalent to claiming that C++ is
not of the C family of languages because it doesn't even have trigraphs.
Unless you count classes -- which are not in the common subset of
OCaml and C# -- I wouldn't know of an alternative to modules in any
current ML, not to mention a better one.
> [list of features that are mostly convenient syntactic sugar.]
You cannot work around the lack of functors half as easily as any of
this. More importantly, modules also provide generic type abstraction,
which I'd argue is used "more widely" than anything in your list.
- Andreas
Oops, should be F#, of course.
> I've also run into the
> if condition then
> something ();
> else
> somethingElse ();
> oneMoreThing ();
> continueProcessing ();
> problem. 8-/
I can see how that can happen, but, honestly, I don't recall ever been
tripped by that in SML, because I use automatic indentation. That is
probably also why I don't get tripped by the nested cases issue. I
notice issues like that when I press tab (or invoke indent-region,
etc...).
But, I agree that SML's syntax could be improved. However, I doubt
that there is any non-trivial group of SML programmers that could
agree on exactly how the syntax should be improved. I don't recall
ever discussing SML's syntax with anyone whose opinions regarding the
syntax would have matched with mine completely. Everyone has an
opinion on syntax. Perhaps SML needs a dictator. :-)
-Vesa Karvonen
> > The expression that is typically considered difficult
> > to read (although I've never had major problems with it) due to the
> > lack of an explicit terminator is nested use of the case expression:
> > Local binding forms, whether at the declaration level or at the
> > expression level, have a terminator:
> It should have been the other way around: case with a terminator,
> let without.
Yeah, one more case where I disagree with how the syntax of SML could
be improved. :-) I'm a sucker for brevity, and, frankly, I don't
particularly like the idea of adding a terminator to case. Below are
a couple of more radical ideas.
I might eliminate case completely. It doesn't really help. Consider
case a of b => c
| d => e
vs
a >| (fn b => c
| d => e)
I might also eliminate let-in-end and add declarations to sequence
expressions (like at the top-level). Consider
let open A val x = y in z end
vs
(open A val x = y ; z)
and, more interestingly, consider
let A in B ; let C in D end end
vs
(A ; B ; C ; D)
-Vesa Karvonen
Verbosity doesn't help, if it does not add meaning. Also, you can
add meaning without being verbose. For instance, I would say that
Haskell code is much more readable when you make good use of the
$ operator, which you can very well do without. For "a b c (d e f)"
may mean just the same as "a b c $ d e f", but "a b c (" does not
mean just the same as "a b c $" to the human reader. What I mean is
that when you encounter a $ sign, you immediately know that
everything you are going to read from now on, until the end of the
expression, is the last argument of the function application you are
currently trying to understand. When you see an opening parenthesis,
you only know that you are starting to read a subexpression, which
may or may not be the last one. In long expressions with lots
of subexpressions, $ really helps me, because I do not have to scan
forward to understand the structure of the whole. Extra meaning
really helps; extra verbosity without extra meaning may look
helpful to the beginner, but it just means more to read.
Dirk van Deun
--
Ceterum censeo Redmond delendum
They are not in the common subset, yes.
>> [list of features that are mostly convenient syntactic sugar.]
>
> You cannot work around the lack of functors half as easily as any of
> this.
Vesa only just posted a huge spawling mess of SML trying to work around the
absence of some of those features I cited by using functors.
Can you cite a single example of someone working around the absence of
functors?
> More importantly, modules also provide generic type abstraction,
> which I'd argue is used "more widely" than anything in your list.
You really think people use modules for generic type abstraction more often
than printf?
> On 4 Dez., 22:27, Chris F Clark <c...@shell01.TheWorld.com> wrote:
>
> And that's exactly why the code is better *readable*, but reading and
> understanding are different things, so it's not better understandable.
> On the contrary, IMHO.
Yes, but I suspect you don't read a lot of code in languages you don't
know. These days I spend most of my life reading and correcting
programming in languages I have never learned.
> And remember that your 8 liner with ca. 40 words is an absolutely
> trivial piece of code.
My experience is most code is actually trivial and the only problem
with it is that it is obfuscated by overly terse names and enigmatic
notations.
> But, if you really like to read such stuff, one could write a Haskell
> (OCaml, Lisp or whatever) reader, that reads a program to you. Would
> be nice to have when one can't get sleep :)
I think that is actually part of the solution. But, you have to
remember the title of this thread "verbose functional languages".
There are those of us who want functional languages: higher-order
functions, immutable data structures, garbage collectors, closures,
tail-recursion support, etc., but we want it in a notation that we can
take to audiences who are not mathematically adept (and perhaps not
even particularly programming literate).
I don't want to deny those who desire a terse notation their options,
but we already have plenty of terse fp languages. I'm looking for an
fp that I can take to the "unwashed" masses and which is subversively
simple, so that they start getting the advantanges without being
frightened off. For example, closures are trivial for "normal" people
to understand, but introducing them with "\x ->" (presumably meaning
lambda x maps to) is scary and off-putting for most people not
previously exposed to those notations, whereas "function (x) is" just
seems a lot less so.
A truly greatly language would transparently convert between the more
terse and more verbose notation. That way, when I'm reading code
where I don't understand some part of the notation I can expand it to
something that I can study without being a member of the internal
notational cabal. Whereas, once I understand it, I can collapse to
the more terse notation to become more sophisticated and compress more
content into less space.
> I'm a sucker for brevity, and, frankly, I don't
> particularly like the idea of adding a terminator to case. Below are
> a couple of more radical ideas.
>
> I might eliminate case completely. It doesn't really help. Consider
>
> case a of b => c
> | d => e
>
> vs
>
> a >| (fn b => c
> | d => e)
I don't find that any shorter: You replace two keywords with an
operator and two parentheses. O.K., the number of non-whitespace
characters is lower, but I find number of tokens to be more important
than number of characters.
> I might also eliminate let-in-end and add declarations to sequence
> expressions (like at the top-level). Consider
>
> let open A val x = y in z end
>
> vs
>
> (open A val x = y ; z)
>
> and, more interestingly, consider
>
> let A in B ; let C in D end end
>
> vs
>
> (A ; B ; C ; D)
I agree. Let-expressions are rather verbose, and by letting
semi-colon double as an infix "let-in", code is shorter and requires
less indentation. I would also like to avoid the "val" in bindings.
This would require distinguishing the binding symbol from comparison.
Otherwise, "x=y; x+y" can mean both a binding of x to y followed by an
addition or a comparison (whose result is discarded) followed by an
addition. I would probably add a requirement in the type-checker that
when ; separates two expressions, the first should have unit type.
That is already the case in most cases where you would use ; in SML,
so it shouldn't be much of a problem, and it would catch a lot of
silly mistakes in the type-checker. So (replacing the equality
operator by ==),
(x := y; z = !x+y; z==y)
would be legal and be an assignment through a reference (of unit
type), a binding of z (identified by the = binding operator) and a
comparison.
Torben
OK, so I remain puzzled how you justify your statement about modules
having become "vestigial" in ML.
> Vesa only just posted a huge spawling mess of SML trying to work around the
> absence of some of those features I cited by using functors.
Which post are you referring to?
> Can you cite a single example of someone working around the absence of
> functors?
In ML? No, why, you have functors. In languages that do not have
anything comparable? You fall back to copy & paste or to casting. I'm
sure you have seen plenty of examples of that before.
> > More importantly, modules also provide generic type abstraction,
> > which I'd argue is used "more widely" than anything in your list.
>
> You really think people use modules for generic type abstraction more often
> than printf?
Printf provides some local convenience. Modularity OTOH is fundamental
for programming in the large. You cannot compare them by nitpicking on
the number of occurrences of the words "printf" or "module" in average
code.
- Andreas
We were talking about parts of the module system not found in F#, i.e. not
modules themselves.
> having become "vestigial" in ML.
Note that we have different definitions of ML.
The main point of difference between these languages is functors because F#
doesn't have them. In OCaml, the main use of functors is working around the
lack of type classes. F# has a better solution to that problem and, hence,
has even less need for functors.
Even in OCaml, functors have a second-class implementation that
unnecessarily hampers optimization (no inlining across functor boundaries)
to the extent that functors are totally unsuitable for factoring over
numeric representation. For example, Vesa's post would be an awful idea in
OCaml. Unlike F#, OCaml provides no decent alternative so you must code up
such things manually.
>> Vesa only just posted a huge spawling mess of SML trying to work around
>> the absence of some of those features I cited by using functors.
>
> Which post are you referring to?
http://groups.google.co.uk/group/comp.lang.functional/msg/5a30908fdef3bcd7
>> Can you cite a single example of someone working around the absence of
>> functors?
>
> In ML? No, why, you have functors.
That is circular with your definition of ML ("must have functors").
> In languages that do not have
> anything comparable? You fall back to copy & paste or to casting. I'm
> sure you have seen plenty of examples of that before.
My experience is exactly the opposite.
Almost all of my uses of functors in OCaml derive from their use in the
OCaml stdlib, specifically the Set and Map modules. You can create a set of
strings with:
include Set.Make(String)
but only because the built-in String module happens to implement "t"
and "compare". If you want a map from ints then you must write your
own "Int" module:
module Int : Map.OrderedType =
type t = int
let compare (n:t) m = compare n m
end
and instantiate your map with it:
include Map.Make(Int)
That Int module is boiler-plate code that I am forced to cut'n'paste
everywhere.
F# relieves me of this burden by providing generic equality and hashing
functions that may be overridden if necessary (which is very rarely the
case in user code). This is a restricted form of type classes (never any
need for run-time dispatch to the appropriate function) and it works
beautifully.
So the primary use of functors in OCaml is no longer necessary in F#. My use
of functors in other settings is negligible, maybe one functor every
million lines of production code, and that is easily replaced with classes
even if the code is slightly different between OCaml and F#.
>> > More importantly, modules also provide generic type abstraction,
>> > which I'd argue is used "more widely" than anything in your list.
>>
>> You really think people use modules for generic type abstraction more
>> often than printf?
>
> Printf provides some local convenience.
Yes, this convenience and familiarity is the foundation of OCaml's
widespread use and is the reason F# copied it. SML would do well to follow.
> Modularity OTOH is fundamental
> for programming in the large. You cannot compare them by nitpicking on
> the number of occurrences of the words "printf" or "module" in average
> code.
We were talking about "generic type abstraction" and not "modularity".
Are you seriously suggesting that SML is better equipped for "programming in
the large" than .NET?
And how exxctly would it help you if the language looked like english,
but wasn't actually english?
> My experience is most code is actually trivial and the only problem
> with it is that it is obfuscated by overly terse names and enigmatic
> notations.
Have you ever considered the possibility that longer names can be more
easily confused? As I get older, it happens more often to me, that I
stumble across some compiler message saying that some name is unknown,
and sometimes I need quite some time to figure out that I actually
switched 2 letters somwehere in a long name.
The notion that longer names make programs more readable is
fundamentally mistaken, IMHO. I hope you'll never have to maintain a
program written by someone that believes in the blessings of long,
"speaking" names, for speaking are they only if you know the langugae.
Assuming you're not a german speaker, what do you think do the
following names mean?
DonauSchiffahrtKapitänsWitwenPension
DonauSchiffahrtsInspektionsIntervall
BergwachtVereinigungsVorsitzendenEntschädigung
BergwachtVereinigungsVorsitzendenEntscheidung
>
> > But, if you really like to read such stuff, one could write a Haskell
> > (OCaml, Lisp or whatever) reader, that reads a program to you. Would
> > be nice to have when one can't get sleep :)
>
> I think that is actually part of the solution. But, you have to
> remember the title of this thread "verbose functional languages".
> There are those of us who want functional languages: higher-order
> functions, immutable data structures, garbage collectors, closures,
> tail-recursion support, etc., but we want it in a notation that we can
> take to audiences who are not mathematically adept (and perhaps not
> even particularly programming literate).
I don't think this will work. This is my opinion only, of course.
On the ground of each PL lie exactness and formal rigor as well as
certain fundamental concepts. I doubt the possibility to make the
required understanding easier through relaxed syntax.
An illsutration: Take for example cooking receipts. If it were so that
merely use of natural language does the trick, we all could be great
cooks by just working down the receipt. Yet, the fact is that many of
us are miserable cooks (or do not cook at all), despite having access
to the finest receipts.
>
> I don't want to deny those who desire a terse notation their options,
> but we already have plenty of terse fp languages. I'm looking for an
> fp that I can take to the "unwashed" masses and which is subversively
> simple, so that they start getting the advantanges without being
> frightened off. For example, closures are trivial for "normal" people
> to understand, but introducing them with "\x ->" (presumably meaning
> lambda x maps to) is scary and off-putting for most people not
> previously exposed to those notations, whereas "function (x) is" just
> seems a lot less so.
Is this so? How about anonymous functions with two arguments?
"function (x) is function (y) is" perhaps? And for what reason do we
need the () parentheses?
I personally think that especially the Haskell syntax is so terse
because it abandons lots of braces, semicolons and parens that
dominate the look of program texts in other languages. And I think
it's a good thing.
>
> A truly greatly language would transparently convert between the more
> terse and more verbose notation. That way, when I'm reading code
> where I don't understand some part of the notation I can expand it to
> something that I can study without being a member of the internal
> notational cabal.
I don't see that. The "more verbose notation" would still have to
convey the exact meaning. From our experiments here in this thread we
know, that expressing functional programs in "natural" like languages
is not per se promoting understanding. You'll have to have some formal
notation anyway. Once we realise this, we can as well choose one that
is consistent and easy in itself, i.e. governed by few rules only. (I
know this is vague, for this also applies to languages like brainf*ck
or unlambda. Perhaps in the latter cases there are too few rules.)
Yet, I admit, such a program reader could be a useful tool for
beginners.
?
Still much better than BVVE or BrgVrVorsEnts.
Minor detail: In Lisp you would write:
Bergwacht-Vereinigungs-Vorsitzenden-Entscheidung
For typing these long identifiers, one usually uses
completion or some other help (like mouse-copy).
When one write these names, one types
B-V-V-E and press completion. Then it expands to
above name ro gives the choice of the possibilities.
> > > But, if you really like to read such stuff, one could write a Haskell
> > > (OCaml, Lisp or whatever) reader, that reads a program to you. Would
> > > be nice to have when one can't get sleep :)
> >
> > I think that is actually part of the solution. But, you have to
> > remember the title of this thread "verbose functional languages".
> > There are those of us who want functional languages: higher-order
> > functions, immutable data structures, garbage collectors, closures,
> > tail-recursion support, etc., but we want it in a notation that we can
> > take to audiences who are not mathematically adept (and perhaps not
> > even particularly programming literate).
>
> I don't think this will work. This is my opinion only, of course.
> On the ground of each PL lie exactness and formal rigor as well as
> certain fundamental concepts. I doubt the possibility to make the
> required understanding easier through relaxed syntax.
He does not want relaxed syntax. He wants explicit code with
named constructs that appear in the code.
Not syntax by white space or cryptic letter combinations.
...
The term "ML modules" is generally understood to mean a system with
type abstraction (sealing), nested namespaces, functors, structural
signature subtyping, composition (open, include). What remains if you
remove all those is basically Modula-2.
So what is there that can replace that?
> The main point of difference between these languages is functors because F#
> doesn't have them.
Note that F# also removes most of the above, or severely restricts it
(e.g. sealing and signature subtyping).
> In OCaml, the main use of functors is working around the
> lack of type classes.
> F# has a better solution to that problem and, hence,
> has even less need for functors.
First, modules are more general than type classes. And second, you are
now extrapolating from F# to ML as a whole?
> Even in OCaml, functors have a second-class implementation that
> unnecessarily hampers optimization (no inlining across functor boundaries)
> to the extent that functors are totally unsuitable for factoring over
> numeric representation. For example, Vesa's post would be an awful idea in
> OCaml.
I know somebody who in such cases would usually flame the outdated
compiler technology and claim that the whole language is useless.
> >> Vesa only just posted a huge spawling mess of SML trying to work around
> >> the absence of some of those features I cited by using functors.
>
> > Which post are you referring to?
>
> http://groups.google.co.uk/group/comp.lang.functional/msg/5a30908fdef...
Then I have no idea what you are talking about. This code defines
vector operators, plus (secondary) some helper generics for sequences.
And it is making straightforward use of the module system to structure
the code for good.
If you can show me how any of the features you listed would avoid
writing much of this code I'd be impressed.
> >> Can you cite a single example of someone working around the absence of
> >> functors?
>
> > In ML? No, why, you have functors.
>
> That is circular with your definition of ML ("must have functors").
Huh? How do you expect me to give an example in a language where you
don't need to work around it?
> Almost all of my uses of functors in OCaml derive from their use in the
> OCaml stdlib, specifically the Set and Map modules. You can create a set of
> strings with:
>
> include Set.Make(String)
>
> but only because the built-in String module happens to implement "t"
> and "compare". If you want a map from ints then you must write your
> own "Int" module:
>
> module Int : Map.OrderedType =
> type t = int
> let compare (n:t) m = compare n m
> end
>
> and instantiate your map with it:
>
> include Map.Make(Int)
>
> That Int module is boiler-plate code that I am forced to cut'n'paste
> everywhere.
Maybe you should consider a less verbose language then. ;-) For
example, in SML you'd just write
Map.Make(open Int type t = int)
But more seriously, I think that you tend to vastly overemphasize
minor syntactic annoyances. Again, this is just a local thing. If you
do not have functors or something equivalent, you potentially have to
duplicate code on a much larger scale.
> F# relieves me of this burden by providing generic equality and hashing
> functions that may be overridden if necessary (which is very rarely the
> case in user code). This is a restricted form of type classes (never any
> need for run-time dispatch to the appropriate function) and it works
> beautifully.
I certainly agree that type classes are useful. But they do not
substitute modules.
> So the primary use of functors in OCaml is no longer necessary in F#. My use
> of functors in other settings is negligible, maybe one functor every
> million lines of production code, and that is easily replaced with classes
> even if the code is slightly different between OCaml and F#.
And what about abstract types? You never define any?
> > Modularity OTOH is fundamental
> > for programming in the large. You cannot compare them by nitpicking on
> > the number of occurrences of the words "printf" or "module" in average
> > code.
>
> We were talking about "generic type abstraction" and not "modularity".
>
> Are you seriously suggesting that SML is better equipped for "programming in
> the large" than .NET?
Not necessarily (depending on your needs), but it is certainly better
equipped than the intersection of OCaml and F# -- which you claimed
otherwise before in a way that I had to take issues with.
- Andreas
> Can you cite a single example of someone working around the absence of
> functors?
>
I went to quite spectacular lengths to do it in some Haskell code that was
subsequently used by Galois to prototype an internal wiki system.
"I think you mean Philippa. I believe Phillipa is the one from an
alternate universe, who has a beard and programs in BASIC, using only
gotos for control flow." -- Anton van Straaten on Lambda the Ultimate
> In ML? No, why, you have functors. In languages that do not have
> anything comparable? You fall back to copy & paste or to casting.
Or to a whole pile of variants on factory patterns and the like, encoding
modules as objects.
There is no magic bullet. There are, however, plenty of bullets that
magically home in on feet when not used in exactly the right circumstances.
Hey, that would be ultra-cool!
Target audience 1: programmers who don't know the language in question
well enough to say for sure what the syntax du jour is. (E.g. Erlang
programmers trying to understand a piece of OCaml code given on the
newsgroup.)
Target audience 2: programmers trying to learn an FPL. When reading
really terse code (as is typical for, say, the Haskel Prelude), it's all
too easy to miss or misread the decisive symbol when reading terse code,
and you get mental gobbledigook. Having an Expression Reader would allow
you to to double-check that your interpretation of the syntax is correct
so you can concentrate on the semantics.
E.g. in the above code, I'd have missed that the lambda takes a single
parameter, simply because those traditional parameter list syntaxes are
too deeply engraved in my brain.
Extra points if the Expression Reader deals well with runaway
indentation ;-)
Regards,
Jo
May I ask what the signature of the functor's argument was?
Exactly, yes. Just as Homo sapiens have an appendix that is severely
restricted in what it can do.
>> In OCaml, the main use of functors is working around the
>> lack of type classes.
>> F# has a better solution to that problem and, hence,
>> has even less need for functors.
>
> First, modules are more general than type classes.
We were talking about functors, not modules.
> And second, you are now extrapolating from F# to ML as a whole?
I'm saying that anyone who fixes these deficiencies in SML or OCaml might as
well not bother with functors either, which is exactly what has happened
with F#.
>> Even in OCaml, functors have a second-class implementation that
>> unnecessarily hampers optimization (no inlining across functor
>> boundaries) to the extent that functors are totally unsuitable for
>> factoring over numeric representation. For example, Vesa's post would be
>> an awful idea in OCaml.
>
> I know somebody who in such cases would usually flame the outdated
> compiler technology and claim that the whole language is useless.
Statements that widely used things are useless should stay in academia.
>> >> Vesa only just posted a huge spawling mess of SML trying to work
>> >> around the absence of some of those features I cited by using
>> >> functors.
>>
>> > Which post are you referring to?
>>
>> http://groups.google.co.uk/group/comp.lang.functional/msg/5a30908fdef...
>
> Then I have no idea what you are talking about. This code defines
> vector operators, plus (secondary) some helper generics for sequences.
> And it is making straightforward use of the module system to structure
> the code for good.
Look at the original code as well:
http://mlton.org/pipermail/mlton/2005-October/028127.html
These gems are nothing more than polished turds in the big picture.
The authors gallantly try to work around the deficiencies of the SML
language and arrive at a solution that creates more problems than it
solves:
. Inextensible: you can't overload "+" for your own numeric types later.
. Unscalable: All numeric code must be wrapped in the same functor
instantiation to keep the abstract type compatible.
. Invasive: you must manually box each and every constant and can no longer
pattern match over numeric types (!).
. Inefficient: in all other SML implementations this will incur boxing,
unboxing and indirection at every use of every number.
In the process they were forced to use functors because SML provides
absolutely no alternatives.
That is not a killer reason to stuff functors into every new ML derivative:
it is a killer reason to fix the problems correctly in the first place by
creating languages that have extensible operator overloading built in.
> If you can show me how any of the features you listed would avoid
> writing much of this code I'd be impressed.
Exportable infix operators. No need to wrap your numeric code in a functor
(a technique that doesn't even scale anyway).
>> >> Can you cite a single example of someone working around the absence of
>> >> functors?
>>
>> > In ML? No, why, you have functors.
>>
>> That is circular with your definition of ML ("must have functors").
>
> Huh? How do you expect me to give an example in a language where you
> don't need to work around it?
Can you cite a single example of someone working around the absence of
functors in F#?
>> That Int module is boiler-plate code that I am forced to cut'n'paste
>> everywhere.
>
> Maybe you should consider a less verbose language then. ;-) For
> example, in SML you'd just write
>
> Map.Make(open Int type t = int)
That doesn't work in SML/NJ:
- Map.Make(open Int type t = int);
stdIn:1.10 Error: syntax error found at OPEN
In F# you write no code at all. Maybe you should consider a less verbose
language.
> But more seriously, I think that you tend to vastly overemphasize
> minor syntactic annoyances.
Absolutely not. If you fixed these problems with your own implementation
then you could garner users who would use it to do great work. I can think
of nothing more gratifying, but making the language familiar and easy is
absolutely essential for that to happen and, I suspect, would require you
to break SML compatibility (but who cares when there are no SML users).
> Again, this is just a local thing. If you
> do not have functors or something equivalent, you potentially have to
> duplicate code on a much larger scale.
The F# solution is better in every respect.
>> F# relieves me of this burden by providing generic equality and hashing
>> functions that may be overridden if necessary (which is very rarely the
>> case in user code). This is a restricted form of type classes (never any
>> need for run-time dispatch to the appropriate function) and it works
>> beautifully.
>
> I certainly agree that type classes are useful. But they do not
> substitute modules.
By all means keep the obscure parts of the module system when you implement
extensible operator overloading. All I'm saying is that few people will use
them compared to the number of people who will use operator overloading
(and any other the other features I listed).
>> So the primary use of functors in OCaml is no longer necessary in F#. My
>> use of functors in other settings is negligible, maybe one functor every
>> million lines of production code, and that is easily replaced with
>> classes even if the code is slightly different between OCaml and F#.
>
> And what about abstract types? You never define any?
I use abstract types all the time in both OCaml and F#. Perhaps you mean
type aliases parameterized over phantom types?
>> Are you seriously suggesting that SML is better equipped for "programming
>> in the large" than .NET?
>
> Not necessarily (depending on your needs), but it is certainly better
> equipped than the intersection of OCaml and F# -- which you claimed
> otherwise before in a way that I had to take issues with.
Do you think there are bigger projects in SML that OCaml+F#?
> Philippa Cowderoy wrote:
> > On Wed, 5 Dec 2007, Jon Harrop wrote:
> >> Can you cite a single example of someone working around the absence of
> >> functors?
> >
> > I went to quite spectacular lengths to do it in some Haskell code that was
> > subsequently used by Galois to prototype an internal wiki system.
>
> May I ask what the signature of the functor's argument was?
>
It was a collection of IO operations for accessing the wiki's page
database.
Ivanova is always right.
I will listen to Ivanova.
I will not ignore Ivanova's recomendations.
Ivanova is God.
And, if this ever happens again, Ivanova will personally rip your lungs out!
Just values then, and no types? Why not use a record of function values?
Sorry I'm being dense, but your point is?
> > First, modules are more general than type classes.
>
> We were talking about functors, not modules.
Not at all. /You/ have been trying to restrict the discussion to
functors. I am not. I have been talking about the whole module
language from the beginning.
> Statements that widely used things are useless should stay in academia.
Who made such a statement?
In any case, popularity certainly is no metric for usefulness.
>>http://groups.google.co.uk/group/comp.lang.functional/msg/5a30908fdef...
>
> > Then I have no idea what you are talking about. This code defines
> > vector operators, plus (secondary) some helper generics for sequences.
> > And it is making straightforward use of the module system to structure
> > the code for good.
>
> Look at the original code as well:
>
> http://mlton.org/pipermail/mlton/2005-October/028127.html
I fail to see what this code has to do with the other. In fact, the
latter is showing that you can actually simulate overloading in MLton
at zero runtime cost -- if you really want to. Vesa's post on the
other hand explicitly is intended to show that such overloading often
is unnecessary to start with.
> > If you can show me how any of the features you listed would avoid
> > writing much of this code I'd be impressed.
>
> Exportable infix operators. No need to wrap your numeric code in a functor
> (a technique that doesn't even scale anyway).
As far as I can see, the first would avoid the initial two lines of
Vesa's code -- for the price of not having natural precedences among
the operators he chose, or having to choose less uniform operator
names.
I don't see how anything in your feature list would replace the
functors in his code.
> Can you cite a single example of someone working around the absence of
> functors in F#?
In F# I suppose you'd use classes. But as I said before, my point was
all about the intersection of OCaml and F#. What would you use there?
You sort of said already that you use classes and have different
versions of the code. That sounds like a workaround to me.
> >> That Int module is boiler-plate code that I am forced to cut'n'paste
> >> everywhere.
>
> > Maybe you should consider a less verbose language then. ;-) For
> > example, in SML you'd just write
>
> > Map.Make(open Int type t = int)
>
> That doesn't work in SML/NJ:
>
> - Map.Make(open Int type t = int);
> stdIn:1.10 Error: syntax error found at OPEN
No, of course not. Like in Ocaml it is a module expression, so you can
only use it in a module declaration:
structure M = Map.Make(open Int type t = int)
> In F# you write no code at all. Maybe you should consider a less verbose
> language.
At the same time, you loose the ability to employ the type system to
easily distinguish different types of maps.
> > But more seriously, I think that you tend to vastly overemphasize
> > minor syntactic annoyances.
>
> Absolutely not. If you fixed these problems with your own implementation
> then you could garner users who would use it to do great work. I can think
> of nothing more gratifying, but making the language familiar and easy is
> absolutely essential for that to happen
Familiar relative to what? That is entirely subjective, unless you are
targetting a particular community.
> > And what about abstract types? You never define any?
>
> I use abstract types all the time in both OCaml and F#. Perhaps you mean
> type aliases parameterized over phantom types?
I mean abstract types not defined by wrapping the representation into
constructors -- like F# requires (and thereby essentially falling back
to the state-of-the art of Modula-2).
> Do you think there are bigger projects in SML that OCaml+F#?
I would make any bet that there are far bigger projects in SML than in
the intersection OCaml/\F#. I never meant to claim anything else.
Do you commonly try to keep your code within it?
Just to clarify again: I criticise neither OCaml nor F#, both of which
I have much respect for and sometimes enjoy using myself. Your
repeated suggestive claim that it would somehow be easier to write
programs that work on both than it would be for multiple SMLs is what
I consider unsound.
- Andreas
>
> Still much better than BVVE or BrgVrVorsEnts.
"much better" in what sense?
Let's rephrase a bit:
BergwachtVereinigungsVorsitzendenEntschaedigung
BergwachtVereinigungsVorsitzendenEntschuldidung
Why is it "better" to being forced to scan endless words to see a tiny
difference?
> Minor detail: In Lisp you would write:
>
> Bergwacht-Vereinigungs-Vorsitzenden-Entscheidung
No way.
> For typing these long identifiers, one usually uses
> completion or some other help (like mouse-copy).
Isn't that interesting.
We use technical help to write such beasts, but there is none to help
us in reading them.
> When one write these names, one types
> B-V-V-E and press completion. Then it expands to
> above name ro gives the choice of the possibilities.
I prefer writing and reading "bvve" without pressing completion.
> Not syntax by white space
Why not?
> Extra points if the Expression Reader deals well with runaway
> indentation ;-)
>
I think it would be fairly easy to make one that is correct (i.e.
utters grammatical sentences) but I wonder how hard it would be to
make one that is really good.
For example, given
map (+1) as
it would be correct to say aomething like:
evaluate the application of
the anonymous function which
evaluates the application of
its arguement
and 1
to the function "+"
and "as"
to the function "map"
but it would be more desirable to hear: the list of all elements of
"as", in the same order, but incremented
Another difficulty would be "point free style" definitions, i.e.
notEmpty = not . empty
Here, perhaps one should do some form of epsilon conversion.
> On 6 Dez., 11:17, Rainer Joswig <jos...@lisp.de> wrote:
>
> >
> > Still much better than BVVE or BrgVrVorsEnts.
>
> "much better" in what sense?
>
> Let's rephrase a bit:
>
> BergwachtVereinigungsVorsitzendenEntschaedigung
> BergwachtVereinigungsVorsitzendenEntschuldidung
>
> Why is it "better" to being forced to scan endless words to see a tiny
> difference?
The purpose of long words is not to create tiny difference.
The purpose is to have descriptive identifiers.
When you read text, it is not much of a difference if
you have small words or long words. Remember,
everyone trained to read does not look much
at individual words or characters - that's much too
slow. Most trained people look at chucks of
words and shape. So for them it would not make
much difference if the text contains has the error
in small, medium sized or long words. 'more' vs.
'mere' vs. 'moer' does not make much a difference
if you look at some piece of code.
> > Minor detail: In Lisp you would write:
> >
> > Bergwacht-Vereinigungs-Vorsitzenden-Entscheidung
>
> No way.
Yes.
> > For typing these long identifiers, one usually uses
> > completion or some other help (like mouse-copy).
>
> Isn't that interesting.
> We use technical help to write such beasts, but there is none to help
> us in reading them.
No, I have help.
Well, there is light ;-) , source coloring, interactive help on symbols,
code browsers, and so on. When I have a symbol I don't know, I usually
place a cursor on it and press a show documentation command.
If that does not help, I inspect it with another key.
If that does not help I try to locate the source, M-. .
It helps me while reading to make the meanings of symbols
clearer.
> > When one write these names, one types
> > B-V-V-E and press completion. Then it expands to
> > above name ro gives the choice of the possibilities.
>
> I prefer writing and reading "bvve" without pressing completion.
Really? I would make it 'verboten' by a coding style guideline. ;-)
Encryption and compression of symbols would be discouraged.
Do you talk with abbreviated words to other people?
You could say BVVE instead of the word above.
How is BVVE not easily to misunderstand? It has no correspondence
to natural language. If you read it in code, there is no
way to say if it is right or wrong by staring at it.
For the long word, you could at least recover
some meaning.
> > Not syntax by white space
>
> Why not?
I like explicit constructs. Constructs that have a descriptive
name and can be spotted in the source code. I'm not a fan
of terse code with tiny abbreviated identifiers. This really
gets problematic, if a language has many identifiers.
Then the small ones are quickly gone. Unix shell scripts have so many
one to four letter commands - this is extremely ugly.
Gerald J. Sussman had a talk about readability in books,
formulas and programs:
http://video.google.com/videoplay?docid=-2726904509434151616
He describes his struggle finding out what math in classical mechanics
was meaning when writing the book SICM (Structure and Interpretation
of Classical Mechanics, http://mitpress.mit.edu/SICM/book.html ).
He was trying to use Scheme to write down some of the formulas
and detected that the terse math notation often made things
unclear or was hiding lots of errors.
> And how exxctly would it help you if the language looked like english,
> but wasn't actually english?
The same way knowing a smattering of Bulgarian helps me listen to
Russian, Czech, and Polish dialogue (all Slavic languanges, but each
distinct enough that speaking one does not let one *speak* another).
Some words are cognates and they help--especially since they are all
languages suited to the same purposes. One forms a thesis with the
words one recognizes (or thinks one recognizes), and looks up unknown
words to see what they mean. Eventually, if the two sides are *trying
to communicate*, they find a pigeon language with a subset of the
meanings that both can understand that gets across the barrier and
conveys the intended meaning. If the meaning is all tied up in subtle
declensions, inflections, word order tricks, homonyms, puns, etc., it
will get lost--so jokes don't generally translate well. And that's
the spoken equivalent of enigmatic notation. If you want to speak to
just a closed group, use a complex notation. If you want to address a
wide audience, use simple forms and simple concepts and let the
message carry itself.
"Ich bin ein Berliner." was incorrect, but it got the message across.
I don't speak enough Deutsch to correct it, but if I saw a similarly
short and correct version of the sentence, I would understand it.
And, so all reading goes. If the writer is attempting to communicate,
the reader needs to know less of the subtleties of the language to
understand. But if one hides the meaning in subtleties, e.g. if the
statement would have been correct as "Ich werde ein Berliner" or "Ich
wunsch ein Berliner" and then written "IWEB" and "IweB", you are
quickly likely to lose ones readers.
> BergwachtVereinigungsVorsitzendenEntschädigung
> BergwachtVereinigungsVorsitzendenEntscheidung
I *can* look up Entschädigung and Entscheidung. I cannot look up BVVE
and know which of those two you mean. If it makes a difference, and
you wish to communicate, you make the difference clear and obvious.
If it doesn't make a difference, then no one cares.
> I don't think this will work. This is my opinion only, of course.
> On the ground of each PL lie exactness and formal rigor as well as
> certain fundamental concepts. I doubt the possibility to make the
> required understanding easier through relaxed syntax.
As Rainer Joswig understood:
R> He does not want relaxed syntax. He wants explicit code with
R> named constructs that appear in the code.
R> Not syntax by white space or cryptic letter combinations.
Yes, I do not want to abandon formality. Formality is good. I would
much rather communicate in grammatically correct sentences, because
doing so helps me convey my meanings better. Moreover, I like
explicitness. I often have to correct my wife when she uses a pronoun
in a sentence with no obvious referent "that???, that what?, what
'that' are you talking about?". I know she knows her topic, but I
don't know the stuff in her mind and if she doesn't tell me, I'm lost
in the conversation.
> An illsutration: Take for example cooking receipts. If it were so that
> merely use of natural language does the trick, we all could be great
> cooks by just working down the receipt. Yet, the fact is that many of
> us are miserable cooks (or do not cook at all), despite having access
> to the finest receipts.
Perfect example. You right we are all not natural cooks, never will
happen. I don't expect everyone to "write" fp programs. However, a
good French cook can read a recipe for a Chinese dish and probably
make a passable rendition, despite not being familiar with the
cuisine. That's the reading skill I'm interested in. The French cook
is unlikely to succeed if the Chinese recipe hides its assumptions,
e.g. when I say chicken, everyone knows I mean hang the chicken out in
the window with these spices for three days before starting.
Especially if that is encoded as "Chicken" as opposed to "chicken".
> Is this so? How about anonymous functions with two arguments?
> "function (x) is function (y) is" perhaps? And for what reason do we
> need the () parentheses?
Because a naive reader will expect them, a naive reader may never have
seen a function without the arguments enclosed in parenthesis.
Removing the parenthesis is excessive terseness in my book. Making
them optional, allows those of us who want to communicate with a wide
audience put them in, and that's ok in my book. I want to be able to
write verbose programs so that I can reach an audience who may not
understand my field. You may not have that goal.
> I personally think that especially the Haskell syntax is so terse
> because it abandons lots of braces, semicolons and parens that
> dominate the look of program texts in other languages. And I think
> it's a good thing.
Good for you. Not good for me.
> I don't see that. The "more verbose notation" would still have to
> convey the exact meaning.
Yes, the exact smae meaning.
> From our experiments here in this thread we
> know, that expressing functional programs in "natural" like languages
> is not per se promoting understanding.
We do not "know" this, and I reject this claim. In fact, the
axiomatic basis of this thread is that verbose languages have a use.
You may not need that use, but I do.
> You'll have to have some formal notation anyway.
Formal is good. Terse is what is not good in my book.
> Once we realise this, we can as well choose one that
> is consistent and easy in itself, i.e. governed by few rules only. (I
> know this is vague, for this also applies to languages like brainf*ck
> or unlambda. Perhaps in the latter cases there are too few rules.)
Consistent is good too. Simple in general is good. Simple is not
necessarily terse. More characters is not necessarily more complex.
> Yet, I admit, such a program reader could be a useful tool for
> beginners.
Or those of us who just want to read a text in a language we don't
know.
>> Not syntax by white space
> Why not?
I'd say whitespace-sensitive syntax is not in itself bad, if it's
uniform and the rest of the syntax isn't too bloated with other stuff*.
Most languages with whitespace-sensitive syntax also drag in lots of
other things (e.g. python, haskell), but you can e.g. replace lisp
parens by layout and leave the rest pretty much alone - see:
http://srfi.schemers.org/srfi-49/srfi-49.html
- not significantly different to paren-sexp scheme to read, just
using indentation rules and one additional keyword instead of parens.
Not particularly annoying to parse/read IMO (though maybe could be more
annoying than parens for long functions)- still no horrible irregular
(can only be rote learned and tend to be different for all but the most
trivial ops in different languages according to the inscrutable whims
of the language creators) infix operator precedences etc.
One problem is that people know how to (and typically invest a
significant amount of their undergrad time in learning how to, wouldn't
want to "waste" that time, eh?) write parsers for much more complex
syntaxes. But that doesn't mean you should use a complex syntax if you
can avoid it...
* Similarly, I don't even mind infix, if it's one of the few rules
in the syntax, and other complicated rules aren't simultaneously
introduced. See: APL, which is infix but has a very simple
right-to-left interpretation except where explicitly parenthesised.
(People exposed to other languages before APL sometimes think
it's harder than it really is, because they're used to infix operators
having diverse precedences+associativities, and APL has lots of
single-character infix operators - However, they don't have complicated
rules associated with them, though there is a monadic (one-arg prefix)
vs. dyadic (two-arg infix) overloading...)
Ok, knowing Bulgarian you can listen to a Russion speaker and have
some idea what he is talking about. No doubt.
The same would hold for language families like ML, so if you speak
OCaml you probalby get some idea when you read an F# program.
But I think the diversity of computer languages is too big on the one
hand and you do not read program texts just for fun but to set a base
for some informed decision (I suppose) on the other hand.
Thus, for example, you might think you understand a Haskell program
(as ML literate), but, actually, you don't, since a language is not
only syntax. The lazy Haskell semantics is nowhere mentioned in the
progam text, yet it is crucial for understanding. Otherwise, you could
get tempted to "repair" the following code:
iterate f x = x : iterate f (f x)
> > BergwachtVereinigungsVorsitzendenEntschädigung
> > BergwachtVereinigungsVorsitzendenEntscheidung
>
> I *can* look up Entschädigung and Entscheidung. I cannot look up BVVE
> and know which of those two you mean.
Yes, you can look it up at the declaration site, where in a good
program the introduction of the variable is commented:
var bvve = 0 // compensation for the president of the
// alpine emergency team, in EUR/h
> > An illsutration: Take for example cooking receipts. If it were so that
> > merely use of natural language does the trick, we all could be great
> > cooks by just working down the receipt. Yet, the fact is that many of
> > us are miserable cooks (or do not cook at all), despite having access
> > to the finest receipts.
>
> Perfect example. You right we are all not natural cooks, never will
> happen. I don't expect everyone to "write" fp programs. However, a
> good French cook can read a recipe for a Chinese dish and probably
> make a passable rendition, despite not being familiar with the
> cuisine. That's the reading skill I'm interested in. The French cook
> is unlikely to succeed if the Chinese recipe hides its assumptions,
Exactly, and this is what any text does. It "hides", so to speak, the
cultural background. I understand english because I learned
(unconsciously) the language culture (which was not too hard, since
it's not so far apart from the german one).
You can't learn a language just by reading a dictionary and some
grammar rules. According to our great philosopher Wittgenstein, you
have to learn how the language (or certain constructs thereof) is
being used.
You can't learn a programming language just by looking at a syntax
chart, even for passive use only.
So, more verbosity or even imitating natural language will buy you
absolutely nothing.
COBOL is a particularly good example. I've never managed to grasp it
fully because, despite being verbose, it has lots of hidden "cultural
background" that is totally different from mine. For example I
remember that I was looking for the concept of a "local variable" and
was then told that one declares it in the "working storage section" of
some "division" I forgot the name of, but one had to be sure to write
77 at a certain position. Brrrr. (Or was it 99? Never mind.)
> e.g. when I say chicken, everyone knows I mean hang the chicken out in
> the window with these spices for three days before starting.
This could well be the cultural background I mentioned. "Anybody ever
heard of some barbarian that would not hang out the chicken for 3
days? So, when I say chicken, I mean of course a chicken ready for
cooking, which implies this and that, of course!"
> > Is this so? How about anonymous functions with two arguments?
> > "function (x) is function (y) is" perhaps? And for what reason do we
> > need the () parentheses?
>
> Because a naive reader will expect them, a naive reader may never have
> seen a function without the arguments enclosed in parenthesis.
So what?
I do not understand the argument. Do you tell us that "naive readers"
may only be confronted with things they know already?
There's no justification for this.
> Removing the parenthesis is excessive terseness in my book. Making
> them optional, allows those of us who want to communicate with a wide
> audience put them in, and that's ok in my book. I want to be able to
> write verbose programs so that I can reach an audience who may not
> understand my field. You may not have that goal.
This is correct, but it doesn't matter what my goal is. I simply deny
the claim that "more verbose" means "better to understand".
> > I don't see that. The "more verbose notation" would still have to
> > convey the exact meaning.
>
> Yes, the exact smae meaning.
>
> > From our experiments here in this thread we
> > know, that expressing functional programs in "natural" like languages
> > is not per se promoting understanding.
>
> We do not "know" this, and I reject this claim.
I see. But in your own example you used terms that are chinese to
"naive readers" like "list", "parameter", "anonymous function" etc.
etc.
Therefore, you'd better used real chinese words instead of words that
sound familiar. For, familiar words may suggest understanding where
there is none.
> Consistent is good too. Simple in general is good. Simple is not
> necessarily terse.
Granted. But the reverse may well be true. Convoluted is most likely
not simple to understand. Half a page long nested sentences like
"evaluate the application of an anonymous function, which ..." are
verbose, but surely not simple.
Disagree.
> Remember,
> everyone trained to read does not look much
> at individual words or characters - that's much too
> slow. Most trained people look at chucks of
> words and shape. So for them it would not make
> much difference if the text contains has the error
> in small, medium sized or long words. 'more' vs.
> 'mere' vs. 'moer' does not make much a difference
> if you look at some piece of code.
Thats exactly my point.
For example, when reading a novel translated from a foreign language
(i.e. russian) it happened to me, that I confused the characters (i.e.
named persons in the novel), since I take "Nikolajewitsch" on first
reading as "that long name starting with N" and "Nikoforowitsch" also
as "that long name starting with N".
Therefore, I suggest to avoid variable names longer than 1 character,
whenever possible.
> Well, there is light ;-) , source coloring, interactive help on symbols,
> code browsers, and so on. When I have a symbol I don't know, I usually
> place a cursor on it and press a show documentation command.
> If that does not help, I inspect it with another key.
A key? Really? Why not type: please-inspect-that-word-that-I-am-not-
understanding? I wonder how a naive beginner will master those tools
with their cryptic, one-letter abbrevations!
> > I prefer writing and reading "bvve" without pressing completion.
>
> Really? I would make it 'verboten' by a coding style guideline. ;-)
And I would cite Götz von Berlichingen to you, or better yet, increase
my hourly rate. :)
> Do you talk with abbreviated words to other people?
> You could say BVVE instead of the word above.
This happens all the time.
Do you ever ride the S-Bahn? Or the Stadtbahn? Same holds for U-Bahn
and Untergrundbahn. The workers of the GDL strike, so no ICEs are
running. And so forth.
> How is BVVE not easily to misunderstand?
A single word is not to misunderstand at all. A variable name is only
menaingful in a context, ie.e
bvve *= 1.05; // raise by 5%
And before, I read the comment saying that bvve was the compensation
of the president of the alpine emrgency troop, in euros per week.
> It has no correspondence
> to natural language.
Not true. Abbrevations are daily bread and butter. See above.
> If you read it in code, there is no
> way to say if it is right or wrong by staring at it.
> For the long word, you could at least recover
> some meaning.
But you couldn't be sure, since you know, that the only real meaning
of a variable name is to uniqely identify some language defined item.
No more, no less.
> > When you read text, it is not much of a difference if
> > you have small words or long words.
>
> Disagree.
>
> > Remember,
> > everyone trained to read does not look much
> > at individual words or characters - that's much too
> > slow. Most trained people look at chucks of
> > words and shape. So for them it would not make
> > much difference if the text contains has the error
> > in small, medium sized or long words. 'more' vs.
> > 'mere' vs. 'moer' does not make much a difference
> > if you look at some piece of code.
>
> Thats exactly my point.
> For example, when reading a novel translated from a foreign language
> (i.e. russian) it happened to me, that I confused the characters (i.e.
> named persons in the novel), since I take "Nikolajewitsch" on first
> reading as "that long name starting with N" and "Nikoforowitsch" also
> as "that long name starting with N".
>
> Therefore, I suggest to avoid variable names longer than 1 character,
> whenever possible.
You are kidding, right?
>
> > Well, there is light ;-) , source coloring, interactive help on symbols,
> > code browsers, and so on. When I have a symbol I don't know, I usually
> > place a cursor on it and press a show documentation command.
> > If that does not help, I inspect it with another key.
>
> A key? Really? Why not type: please-inspect-that-word-that-I-am-not-
> understanding? I wonder how a naive beginner will master those tools
> with their cryptic, one-letter abbrevations!
>
> > > I prefer writing and reading "bvve" without pressing completion.
> >
> > Really? I would make it 'verboten' by a coding style guideline. ;-)
>
> And I would cite Götz von Berlichingen to you, or better yet, increase
> my hourly rate. :)
I guess you would not make it into the team. :)
> > Do you talk with abbreviated words to other people?
> > You could say BVVE instead of the word above.
>
> This happens all the time.
> Do you ever ride the S-Bahn? Or the Stadtbahn? Same holds for U-Bahn
> and Untergrundbahn. The workers of the GDL strike, so no ICEs are
> running. And so forth.
I live in Hamburg and there is a Containerschiff still a Containerschiff
and not a C-Ship. A Hafenfähre is not a F-Bahn and the Elbtunnel
is not 'et'.
> > How is BVVE not easily to misunderstand?
>
> A single word is not to misunderstand at all. A variable name is only
> menaingful in a context, ie.e
> bvve *= 1.05; // raise by 5%
> And before, I read the comment saying that bvve was the compensation
> of the president of the alpine emrgency troop, in euros per week.
Oh, you need added comments. That's even worse. A recipe for disaster.
>
> > It has no correspondence
> > to natural language.
>
> Not true. Abbrevations are daily bread and butter. See above.
-. Abr r d br + bu. s ^.
I see that you write full words here.
> > If you read it in code, there is no
> > way to say if it is right or wrong by staring at it.
> > For the long word, you could at least recover
> > some meaning.
>
> But you couldn't be sure, since you know, that the only real meaning
> of a variable name is to uniqely identify some language defined item.
> No more, no less.
The real meaning of a variable is to name something:
SICP:
Programs must be written for people to read, and only incidentally
for machines to execute.
For me a well written program reads like a good novel.
Sure, but the purpose of an Expression Reader would be to point out
where the reader's interpretation went off-track, so the simpler
solution is actually preferrable.
I.e. "don't interpret, just decode".
Interpretation would be a lifetime project anyway, I'd think.
> Another difficulty would be "point free style" definitions, i.e.
>
> notEmpty = not . empty
>
> Here, perhaps one should do some form of epsilon conversion.
Maybe "first get it right, then make it good"?
Regards,
Jo
I don't miss functors and I don't miss my appendix.
>> Look at the original code as well:
>>
>> http://mlton.org/pipermail/mlton/2005-October/028127.html
>
> I fail to see what this code has to do with the other.
They are both working around deficiencies in the language using functors.
Having to work around design flaws in the price you must pay for using a
mainstream language. Users of languages like SML and OCaml should not have
to suffer that burden. Getting it right has now been done before. It isn't
hard. Let's just agree that it needs to be done and do it.
>> Exportable infix operators. No need to wrap your numeric code in a
>> functor (a technique that doesn't even scale anyway).
>
> As far as I can see, the first would avoid the initial two lines of
> Vesa's code -- for the price of not having natural precedences among
> the operators he chose, or having to choose less uniform operator
> names.
That isn't actually true because you can add arbitrary syntax extensions in
OCaml. That's missing the point anyway. Decorating operator names like that
just to satisfy the language at the expense of clarity is poor software
engineering.
> I don't see how anything in your feature list would replace the
> functors in his code.
Just rewrite his code in OCaml: you won't use any functors. The first
half-a-dozen lines of my ray tracer does exactly that.
>> Can you cite a single example of someone working around the absence of
>> functors in F#?
>
> In F# I suppose you'd use classes.
If you're parameterizing over modules, yes. In practice, most uses of
functors in OCaml are not doing that though.
> You sort of said already that you use classes and have different
> versions of the code. That sounds like a workaround to me.
The "workaround" basically consists of removing the unnecessary boiler-plate
that OCaml's functors require.
>> That doesn't work in SML/NJ:
>>
>> - Map.Make(open Int type t = int);
>> stdIn:1.10 Error: syntax error found at OPEN
>
> No, of course not. Like in Ocaml it is a module expression, so you can
> only use it in a module declaration:
>
> structure M = Map.Make(open Int type t = int)
That doesn't work either:
# sml
Standard ML of New Jersey v110.65 [built: Mon Aug 6 04:27:45 2007]
- structure M = Map.Make(open Int type t = int);
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[autoloading done]
stdIn:1.15-1.46 Error: unbound structure: Map in path Map.Make
Incidentally, your statement about OCaml is incorrect. Module expressions
can be used without a module declaration:
include Map.Make(String)
>> In F# you write no code at all. Maybe you should consider a less verbose
>> language.
>
> At the same time, you loose the ability to employ the type system to
> easily distinguish different types of maps.
In practice, that doesn't matter.
>> Absolutely not. If you fixed these problems with your own implementation
>> then you could garner users who would use it to do great work. I can
>> think of nothing more gratifying, but making the language familiar and
>> easy is absolutely essential for that to happen
>
> Familiar relative to what? That is entirely subjective, unless you are
> targetting a particular community.
Far more people are familiar with printf than with all functional
programming languages combined, let alone the weird higher-order combinator
library with its function called ` that the SML community advocate as a
workaround for not having printf.
>> > And what about abstract types? You never define any?
>>
>> I use abstract types all the time in both OCaml and F#. Perhaps you mean
>> type aliases parameterized over phantom types?
>
> I mean abstract types not defined by wrapping the representation into
> constructors -- like F# requires (and thereby essentially falling back
> to the state-of-the art of Modula-2).
I never noticed so I guess I don't use abstract type aliases very often.
>> Do you think there are bigger projects in SML that OCaml+F#?
>
> I would make any bet that there are far bigger projects in SML than in
> the intersection OCaml/\F#. I never meant to claim anything else.
I'd be absolutely amazed if that were true. What is the biggest project in
SML?
> Do you commonly try to keep your code within it?
Most of my code happens to be in it.
> Just to clarify again: I criticise neither OCaml nor F#, both of which
> I have much respect for and sometimes enjoy using myself. Your
> repeated suggestive claim that it would somehow be easier to write
> programs that work on both than it would be for multiple SMLs is what
> I consider unsound.
I said that the intersection of the OCaml and F# languages is larger than
SML. I didn't say anything about ease of use.
Just to set the matter straight: that sentence is, in fact,
syntactically valid German. The English translation would be "I am an
inhabitant of Berlin", probably with a more concise wording for
"inhabitant of Berlin".
(It could also have meant "I am a jam doughnut", since these are sold as
"Berliners" in Germany, but almost no native German speaker would mix
that up.)
Regards,
Jo