POV-Ray : Newsgroups : povray.off-topic : My first C++ program : Re: (And in Haskell. Obviously.) Server Time
1 Oct 2024 05:16:33 EDT (-0400)
  Re: (And in Haskell. Obviously.)  
From: Orchid XP v8
Date: 20 Sep 2008 07:32:29
Message: <48d4df4d@news.povray.org>
Warp wrote:
> Orchid XP v8 <voi### [at] devnull> wrote:
>> I really can't figure out what everybody finds so confusing about 
>> Haskell. Is it just that it uses different syntax to other "common" 
>> programming languages? (E.g., no curly braces, no function call 
>> brackets.) Or is it something deeper?
> 
>   There are many things. For example, in what seems to be a common
> Haskell style of brevity, the lack of clear delimiters is confusing.

> It's often even hard to see where a command or
> definition or whatever *ends* and where a new one starts. The lack of
> clear delimiters makes it very confusing.

>   For example let's take these lines:
> 
>      "+" -> binary (+) stack
>      "-" -> binary (-) stack
> 
>   There's no ending delimiter for those commands.

>   Moreover, in Haskell, from a layman's point of view, you are not even
> guaranteed that you can read from left-to-right and get a concept of how
> the code is being executed. Sometimes code is executed left-to-right,
> sometimes right-to-left, sometimes in a wilder order, and seemingly very
> arbitrarily. It becomes very hard to follow what is going on there.

OK, now I see where you're coming from.



In the case alternatives, the line end *is* the delimiter. So if you 
were to "change only the spacing" then you could actually CHANGE THE 
MEANING of the program! (In fact, likely, cause it to no longer 
compile.) This is different from "curly bracket languages" where you use 
"{", "}" to delimit blocks, and ";" as a seperator. In Haskell, 
generally a newline is a seperator, and indentation delimits blocks.

So, this works:

   case foo of
     1 -> bar1
     2 -> bar2
     3 -> bar3

If the expressions are a bit bigger, you can say

   case foo of
     1 ->
       very_long_thing_1
     2 ->
       very_long_thing_2
     3 ->
       very_long_thing_3

And if they're really long, you can say

   case foo of
     1 ->
       multiline1
       multiline2
       multiline3
     2 ->
       another_block_1
       another_block_2
     3 ->
       yet_another_block

or some such. The case expression itself ends when we get to something 
less indented.

I presume it goes without saying that if you nest things too deeply, 
they end up scrolling off the right edge of the screen and/or becoming 
rather hard to visually untangle. Don't do that! But for the post part, 
it's like a normal curly-bracket language, but without the actual 
brackets. (It's normal practise to indent things anyway.)



Expression execution order is more complicated. First, you can say

   fn3 (fn2 (fn1 x))

which does... what you'd think it does. It calls the function fn1, and 
then passes its result to fn2, and finally passes that to fn3. You can 
also write

   fn3 $ fn2 $ fn1 $ x

which does exactly the same thing, but doesn't require you to match up 
the right number of brackets at the other end. Subtley different, you can do

   fn3 . fn2 . fn1

which yields a *function* that will do the same thing as the above, 
*when* you actually give it an argument. (Notice there's no "x" here. 
That's deliberate. This doesn't produce a result, it produces a 
function.) So

   (fn3 . fn2 . fn1) x

would be a needlessly wordy way to do the same thing as the previous two 
examples.

(As an aside, it should now be clear why the functions are listed 
"backwards". If you take a look at the very first expression, this is 
almost valid C or C++.)



I guess uttering

   mapM_ (\(n,v) -> putStrLn $ "[" ++ show n ++ "]: " ++ show v) (zip 
[0..] stack)

*is* pretty crazy. (It doesn't even fit on one line, for example.) But 
other than that, it should be *reasonably* clear that main_loop does... 
whatever the hell that line does, then it does (putStr "Calc> "), then 
it does (cmd <- getLine), and then it does that case expression.



If you've been paying attention, you may have spotted that the very last 
line of the program *does* in fact have some delimiters:

   _      -> do putStrLn "Stack underflow."; main_loop stack

Haskell does in fact permit you to use curly brackets and semicolons if 
you want to. It's just that most programmers don't. (And, in an amusing 
twist, curly brackets are also used for something completely unrelated 
as well, so it's probably best to _only_ use them for that. Less 
confusing that way...)

-- 
http://blog.orphi.me.uk/
http://www.zazzle.com/MathematicalOrchid*


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.