|
|
|
|
|
|
| |
| |
|
|
|
|
| |
| |
|
|
You remember the 80 / 20 rule, right?
No, not the rule that 80% of the population falls within 2 standard
deviations of the mean; that one's actually baloney. It's only true *if*
the data follows a normal distribution - which is by no means always
true. And even then, it's 95.449%, not 80%. :-P
I'm talking about the rule that says that 80% of people only use 20% of
the available functionality. Or that 20% of the development effort
implements 80% of the functionality, and the last 80% of developer time
is required to do that last 20% of functionality.
So I'm writing a Haskell parser. The vast majority of Haskell code uses
very simple syntax. But it seems the language specification includes a
huge amount of flexibility that hardly anybody uses. Today I've
discovered things I didn't even know you could *do*!
For example, one way to do pattern matching in Haskell is with a case-block:
case list of
[x] -> x
[x, y] -> x + y
[x, y, z] -> x + y + z
_ -> 0
This takes a list and adds its elements, unless there's more than three
of them, in which case it returns 0. Simple enough, right? Well, you can
also add "guards" to a pattern:
case list of
[x, y, z]
| x < 0 -> ...
| x > 0 -> ...
| x == 0 -> ...
Well, it turns out you can have *multiple guards* on a single expression!
case list of
[x, y, z] | x > 0, y > 0, z > 0 -> ...
What does that even *do*?! <read the spec/> OK, so it seems it's the
logical-AND of all the conditions? So, um, why not just write it as an AND?
But it's worse. Apparently you can write local declarations *inside* a
guard. And the variables thus declared are in-scope for the rest of the
line. Wuh?!
case list of
[x, y, z] | let w = x + y + z -> w
WHY WOULD YOU DO THIS?!
But wait, it's worse: you can put a pattern *inside* a pattern guard...
case list of
[x, y, z] | [a, b, c] <- x, [d, e, f] <- y, [g, h, i] <- z -> ...
This mind-bending snippet does precisely the same thing as
case list of
[[a, b, c], [d, e, f], [g, h, i]] -> ...
Except that the latter is actually *readable*. (It matches a 3-element
list of 3-element lists.)
The only reason I can think of for this obscure feature is to allow
somebody to do something like
case mode of
ModeX info | let sub = decrypt info, SubmodeXK <- sub -> ...
In other words, pattern match, run a function on the result, and pattern
match again on the result of that. But, seriously, WHAT ARE YOU DOING
WITH YOUR LIFE?! That is *way* too much crazy to try to squeeze into one
equation. For the love of God, break that stuff into something smaller!
case mode of
ModeX info ->
case decrypt info of
SubmodeXK -> ...
There. That wasn't so hard, was it? :-P
Also slightly nauseating is that you're allowed to specify operator
fixity declarations inside a local variable block. But I guess that's
not really so bad; I suppose the *bad* thing is that you're allowed to
declare local operators in the first place!
let
x # y = x * cos y
infixl 7 #
in 1 # 2 # 3
This declares a new "#" operator, which exists only inside this one code
block, and has a precedence of 7 and is left-associative. If you were a
really sick human being with serious mental problems, you could create a
loop where an operator does something different on each pass through the
loop.
Oh God, wait... You can do all of this *inside* a pattern guard!
case list of
[a, b, c] | let {x # y = x * cos y, infixl 7 #}, a # b # c > 0 -> 1
MY EYES!!! >_<
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 17/10/2015 01:45 PM, Orchid Win7 v1 wrote:
> Well, it turns out you can have *multiple guards* on a single expression!
>
> case list of
> [x, y, z] | x > 0, y > 0, z > 0 -> ...
>
> What does that even *do*?! <read the spec/> OK, so it seems it's the
> logical-AND of all the conditions? So, um, why not just write it as an AND?
I've been a Haskell programmer for [at least] 10 years, and I've never
seen *anybody* do this!
...it turns out there's a reason for that. This is actually a *new*
language feature, added in the Haskell 2010 specification.
Let me say that again: Somebody thought this was a *good* idea. They
actually *added* this. On purpose.
So while the Haskell 2010 spec removed the much-hated N+K patterns
misfeature, they've added something arguably even worse as well. <sigh>
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
all of that certainly explains why there're just a few implementations for the
language. Having fun with significant whitespace?
One of the things that really attracts me to Lisp, or rather its clean and
minimalist variant Scheme, is the regularity of the language and homoiconicity
thing. There's very little actual syntax, just parenthesized prefixed function
application. There're loads of implementations for every platform. no
significant whitespace in sight, but that's traded for parentheses LOL. The
difference is that they actually help rather than get in the way
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 18/10/2015 12:01 AM, nemesis wrote:
> all of that certainly explains why there're just a few implementations for the
> language.
Actually, there used to be more. (NHC, YHC, Hugs, Helium, ...) It seems
that GHC is so good now, that nobody thinks they can beat it. All the
other implementations have gone quiet. (Also, GHC is the only one funded
by Microsoft. All the others were hobby projects.)
That and the fact that Haskell is an extremely unpopular language
anyway. How many implementations of Eiffel are there? Last time I
looked, there were 2. (One commercial and very expensive, one open-source.)
> Having fun with significant whitespace?
Actually, that was reasonably easy. I don't think my implementation is
perfect, but it currently passes all but 2 of the test cases.
> One of the things that really attracts me to Lisp, or rather its clean and
> minimalist variant Scheme, is the regularity of the language and homoiconicity
> thing. There's very little actual syntax, just parenthesized prefixed function
> application. There're loads of implementations for every platform. no
> significant whitespace in sight, but that's traded for parentheses LOL. The
> difference is that they actually help rather than get in the way
I would strongly disagree with that last statement. Unless you can find
some sort of editor which colour-codes all the braces, it's nearly
impossible to follow the insanely deeply nested brackets. Much like the
lambda calculus.
I can certainly see why the highly regular syntax would make
*implementing* the thing laughably easy. That and the fact that it's an
untyped language. Writing an interpreter ought to be really simple. I'm
unclear whether it's actually possible to write a *compiler* for a
language which supports self-modifying code...
Why are there so few implementations of Haskell? I think it's a
confluence of several things:
1. Language size. The syntax specification runs to 11 pages of A4. (I'm
looking at it!) I would imagine a *syntax* spec for Lisp is much
shorter. I don't even want to /know/ how big the spec for C++ is!
2. Significant whitespace. It's not that hard, but it's annoyingly
fiddly to get right, which probably puts people off.
3. Implicit types. No, you can't just ignore the type system, because
for some programs the types implicitly alter which code gets called. It
is legal for a Haskell program to contain no type signatures at all, and
yet still have compile-time polymorphism. Type-checking for (say) Java
is probably very much easier. Just check whether each value is a
subclass of the explicitly-declared type.
4. Laziness. It depends what you're compiling to, but if you compile to
some machine-level language, it's *really complicated* to implement
laziness! It 100% *requires* a garbage collection engine, and it's quite
fiddly to bind you mind around. If you're compiling to the JVM or
something, some of these problems go away.
5. Pattern matching. It's a fundamental language primitive, and it's
modestly non-trivial to implement.
6. Why bother? It's too hard to do in an afternoon, so you're not going
to do it for fun. It's a rare language, so nobody is going to use it.
Anything you can build will never be as excellent as GHC, a genuinely
*state of the art* optimising compiler with decades of R&D behind it. So
what's your point?
Having just said all that, I recall submitting a small Tcl program to
this very newsgroup about 10 years ago which implements a small subset
of Haskell. Implementing Haskell isn't hard; implementing *all* of
Haskell in a standards-compliant way is hard! I suspect the same goes
for many other languages... (E.g., it doesn't sound too hard to
implement the common parts of C. But implementing the entire thing,
"correctly"? That's way harder than most people think!)
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Am 18.10.2015 um 11:33 schrieb Orchid Win7 v1:
> Having just said all that, I recall submitting a small Tcl program to
> this very newsgroup about 10 years ago which implements a small subset
> of Haskell. Implementing Haskell isn't hard; implementing *all* of
> Haskell in a standards-compliant way is hard! I suspect the same goes
> for many other languages... (E.g., it doesn't sound too hard to
> implement the common parts of C. But implementing the entire thing,
> "correctly"? That's way harder than most people think!)
I would suspect that a fully /ANSI-compliant/ C compiler isn't really
that big of a deal to implement, given how much stuff in the standard is
explicitly "implementation specific" or "undefined".
Writing a C compiler that meets common /expectations/ about the C
language, now that would be an entirely different thing.
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 18/10/2015 11:00 AM, clipka wrote:
> I would suspect that a fully /ANSI-compliant/ C compiler isn't really
> that big of a deal to implement, given how much stuff in the standard is
> explicitly "implementation specific" or "undefined".
>
> Writing a C compiler that meets common /expectations/ about the C
> language, now that would be an entirely different thing.
I am not enough of a C expert to comment definitively. Implementing C++
sounds nightmarishly hard! (Template metaprogramming, anyone?)
And yet, since these are both extremely popular languages, there's
thousands of implementations...
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 18/10/2015 10:33 AM, Orchid Win7 v1 wrote:
> 5. Pattern matching. It's a fundamental language primitive, and it's
> modestly non-trivial to implement.
Really, I guess that's a minor niggle. Alone with things like arbitrary
user-defined operators with arbitrary user-defined precedence rules. Now
*that* makes parsing really "interesting"...
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Am 18.10.2015 um 12:03 schrieb Orchid Win7 v1:
> On 18/10/2015 11:00 AM, clipka wrote:
>> I would suspect that a fully /ANSI-compliant/ C compiler isn't really
>> that big of a deal to implement, given how much stuff in the standard is
>> explicitly "implementation specific" or "undefined".
>>
>> Writing a C compiler that meets common /expectations/ about the C
>> language, now that would be an entirely different thing.
>
> I am not enough of a C expert to comment definitively. Implementing C++
> sounds nightmarishly hard! (Template metaprogramming, anyone?)
Implementing C++ quite certainly /is/ nightmarishly hard. Implementing
C, not so much.
> And yet, since these are both extremely popular languages, there's
> thousands of implementations...
C, yes. C++, not so much. And I'd suspect the number of actively
maintained families of C++ compilers is actually dwindling as gcc is
ported to more and more platforms.
BTW, did you know that C++ was initially a metaprogramming language for C?
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Orchid Win7 v1 <voi### [at] devnull> wrote:
> Actually, there used to be more. (NHC, YHC, Hugs, Helium, ...) It seems
> that GHC is so good now, that nobody thinks they can beat it. All the
> other implementations have gone quiet. (Also, GHC is the only one funded
> by Microsoft. All the others were hobby projects.)
oh, yes
Microsoft, the eternal monopoly
they also hired the main researchers for the language and it gave fruits as
insights for C#'s LINQ and a couple of other features and F#
> > no significant whitespace in sight, but that's traded for parentheses LOL. The
> > difference is that they actually help rather than get in the way
>
> I would strongly disagree with that last statement. Unless you can find
> some sort of editor which colour-codes all the braces, it's nearly
> impossible to follow the insanely deeply nested brackets.
please don't tell me you use notepad, dude
any halfassed code editor ever since the 70's comes with some parentheses
matching and coloring resources. Even web editors in javascript. It allows for
quickly going up or down the nested structures as well as selecting a whole
large section with a single move.
> unclear whether it's actually possible to write a *compiler* for a
> language which supports self-modifying code...
that self-modifying thing old Lispers are all-to-proud of selling come from
their failed attempts at AI in the 70's. When it was clear it was going
nowhere, they turned to selling the whole Lisp stack as a cutting edge IDE
similar to the Smalltalk ones. Both were beaten by Microsoft's one for Basic:
Visual Studio. worse is better, ftw
anyway, the whole metalanguage thing in Lisps may be easier to implement because
of homoiconicity, but is no different than in other languages: expansion takes
place /before/ compilation. There is eval to construct real new code at
runtime, but as in javascript and a few others, it's shunned as the performance
hog it is and function composition is preferred.
there are quite a few notable optimizing compilers for both Common Lisp and
Scheme. They go as far in performance as possible as expected from bounds
checking and such permit, but usually allows for unsafe flags and type
annotations if one is really willing.
> 3. Implicit types. No, you can't just ignore the type system, because
> for some programs the types implicitly alter which code gets called. It
> is legal for a Haskell program to contain no type signatures at all, and
> yet still have compile-time polymorphism. Type-checking for (say) Java
> is probably very much easier. Just check whether each value is a
> subclass of the explicitly-declared type.
type inference no doubt is a real dog...
>
> 4. Laziness. It depends what you're compiling to, but if you compile to
> some machine-level language, it's *really complicated* to implement
> laziness! It 100% *requires* a garbage collection engine, and it's quite
> fiddly to bind you mind around. If you're compiling to the JVM or
> something, some of these problems go away.
which is funny, because I never heard of a haskell compiler for java. The JVM
used to have no tail-call optimization primitive, which is a necessity for
functional languages. The ones I knew used to be pretty limited in that aspect.
Now there're plenty of functional languages targetting, but I'm not sure the
JVM implements it or they found a trick around it...
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 18/10/2015 04:37 PM, nemesis wrote:
> Orchid Win7 v1<voi### [at] devnull> wrote:
>> Actually, there used to be more. (NHC, YHC, Hugs, Helium, ...) It seems
>> that GHC is so good now, that nobody thinks they can beat it. All the
>> other implementations have gone quiet. (Also, GHC is the only one funded
>> by Microsoft. All the others were hobby projects.)
>
> oh, yes
>
> Microsoft, the eternal monopoly
>
> they also hired the main researchers for the language and it gave fruits as
> insights for C#'s LINQ and a couple of other features and F#
Oh, you noticed?
It used to be possible to say "hey, look at this Java code. Now look at
the same thing in Haskell. See how it's 500% shorter and easier to
comprehend?" But now you can more or less do the same thing in C#, for
the *common cases* that are easy to demonstrate in a 3-line snippet.
Trust me, there's still plenty that's easier in Haskell than C#. It's
just not quite so easy to demo now. :-{
I'm just glad they don't meddle with the actual development of GHC. That
stays freeware and open-source.
> please don't tell me you use notepad, dude
>
> any halfassed code editor ever since the 70's comes with some parentheses
> matching and coloring resources. Even web editors in javascript. It allows for
> quickly going up or down the nested structures as well as selecting a whole
> large section with a single move.
Most editors will highlight the brace matching the one you're currently
pointing at. But if your source code is 85% braces, anything short of
colour-coding every single brace with a unique colour is pretty unreadable.
> anyway, the whole metalanguage thing in Lisps may be easier to implement because
> of homoiconicity, but is no different than in other languages: expansion takes
> place /before/ compilation. There is eval to construct real new code at
> runtime, but as in javascript and a few others, it's shunned as the performance
> hog it is and function composition is preferred.
OK. So eval actually goes slower. I was half expecting the entire
compiler to be included at run-time. (Mind you, for something as simple
as Lisp, maybe it's not that hard...)
>> 3. Implicit types.
>
> type inference no doubt is a real dog...
Actually, this is one of those joyful moments when you look at the
algorithm and go "oh... that sounds really simple!" It's quite elegant,
really. Don't get me wrong, there's a butt-load of obscure ways it can
go wrong, which will leave you scratching your head. But the main idea
is quite beautiful.
Doing this in a language with subtype polymorphism, OTOH, sounds
nightmarish. Just for giggles, go look up the Eiffel rules for when one
generic type is or isn't a subtype of another generic type. It's mental! ;-)
>> 4. Laziness. It depends what you're compiling to, but if you compile to
>> some machine-level language, it's *really complicated* to implement
>> laziness! It 100% *requires* a garbage collection engine, and it's quite
>> fiddly to bind you mind around. If you're compiling to the JVM or
>> something, some of these problems go away.
>
> which is funny, because I never heard of a haskell compiler for java.
I guess you haven't heard of Frege then.
(It's a language that's 98% like Haskell, but just different enough to
prevent all your existing Haskell code from working on it.)
Anyway, the compiler translates Frege into Java. Not JVM bytecode,
actual Java source code. And supports calling native Java as foreign
functions (much as GHC supports calling C).
> The JVM
> used to have no tail-call optimization primitive, which is a necessity for
> functional languages.
I suspect you can use a trampoline to get around that. I am not an
expert in such matters.
Oh, and there's the experimental GHCJS, which is a mod of GHC that
compiles to JavaScript. For realz.
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
|
|