[Haskell-begin] some basic syntax questions

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[Haskell-begin] some basic syntax questions

Anatoly Vorobey
Hello Haskell-beginners,

I'm trying to work through the "Write Yourself a Scheme in 48 Hours"
tutorial. One of the
first exercises calls for writing code to sum up arguments on command line
and display
the sum.

After a few tries, this worked for me:

module Main where
import System.Environment

main :: IO ()
main = do args <- getArgs
          putStrLn ("Hello, " ++ show (sumIt args))
       where sumIt x = sum $ map read x

However, I have two basic questions:

1. I initially tried putStrLn("Hello, " ++ show $ sumIt args), but that
didn't compile. Why not?
If I wrap (show $ sumIt args) in parens, it works, but should I have to, if
I didn't have to in
the original code above?

2. I initially tried

where sumIt = sum $ map read

(the "point-free" style, I believe it's called?) but that didn't compile.
Why not? A friend suggested

where sumIt = sum . map read

and that does work; I guess my real problem, then, is that I don't really
understand the difference
between the two and why the former doesn't work.

Thanks in advance,
Anatoly.

--
Anatoly Vorobey, [hidden email]
http://avva.livejournal.com (Russian)
http://www.lovestwell.org (English)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/beginners/attachments/20080725/fc8fd05c/attachment.htm
Reply | Threaded
Open this post in threaded view
|

[Haskell-begin] some basic syntax questions

Felipe Lessa
On Fri, Jul 25, 2008 at 4:45 PM, Anatoly Vorobey <[hidden email]> wrote:
> 1. I initially tried putStrLn("Hello, " ++ show $ sumIt args), but that
> didn't compile. Why not?

You see,

Prelude> :i (++)
(++) :: [a] -> [a] -> [a] -- Defined in GHC.Base
infixr 5 ++
Prelude> :i ($)
($) :: (a -> b) -> a -> b -- Defined in GHC.Base
infixr 0 $

so

   "Hello, " ++ show $ sumIt args

is parsed as

   ("Hello, " ++ show) $ sumIt args

which is an obvious error.

> 2. I initially tried
>
> where sumIt = sum $ map read
>
> (the "point-free" style, I believe it's called?) but that didn't compile.
> Why not? A friend suggested
>
> where sumIt = sum . map read
>
> and that does work; I guess my real problem, then, is that I don't really
> understand the difference
> between the two and why the former doesn't work.

It helps to see the types and the definitions

   ($) :: (a -> b) -> a -> b
   f $ x = f x

   (.) :: (b -> c) -> (a -> b) -> (a -> c)
   f . g = \x -> f (g x)

so ($) applies an argument, while (.) composes functions. For example,

   sumIt x = sum (map read x)

so

   sumIt x = sum $ map read x

by ($)'s definition. On the other hand

   sum $ map read    is    sum (map read)   [by ($)'s definition again]

which is, again, a mistake. However, we may write sumIt as

   sumIt = \x -> sum (map read x)

so it becames clear that

   sumIt = sum . map read



Did I help at all? =)

--
Felipe.
Reply | Threaded
Open this post in threaded view
|

[Haskell-begin] some basic syntax questions

Alexander Dunlap
In reply to this post by Anatoly Vorobey
On Fri, Jul 25, 2008 at 12:45 PM, Anatoly Vorobey <[hidden email]> wrote:

> Hello Haskell-beginners,
>
> I'm trying to work through the "Write Yourself a Scheme in 48 Hours"
> tutorial. One of the
> first exercises calls for writing code to sum up arguments on command line
> and display
> the sum.
>
> After a few tries, this worked for me:
>
> module Main where
> import System.Environment
>
> main :: IO ()
> main = do args <- getArgs
>           putStrLn ("Hello, " ++ show (sumIt args))
>        where sumIt x = sum $ map read x
>
> However, I have two basic questions:
>
> 1. I initially tried putStrLn("Hello, " ++ show $ sumIt args), but that
> didn't compile. Why not?
> If I wrap (show $ sumIt args) in parens, it works, but should I have to, if
> I didn't have to in
> the original code above?
>
> 2. I initially tried
>
> where sumIt = sum $ map read
>
> (the "point-free" style, I believe it's called?) but that didn't compile.
> Why not? A friend suggested
>
> where sumIt = sum . map read
>
> and that does work; I guess my real problem, then, is that I don't really
> understand the difference
> between the two and why the former doesn't work.
>
> Thanks in advance,
> Anatoly.
>
> --
> Anatoly Vorobey, [hidden email]
> http://avva.livejournal.com (Russian)
> http://www.lovestwell.org (English)
>
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/beginners
>
>

Hello,

The difference between (.) and ($) is that (.) is composition and ($)
is application. What this means is that (.) takes two /functions/ and
generates a /function/ that is like applying the first function after
the second function:

(f . g) (x) = f (g x)

Where f and g are functions and x is a value. ($), on the other hand,
takes a /function/ and a /value/ and applies the function to the
value:

f $ x = f x

So the reason you can't do sum $ map read is because map read is a
function and sum is a function, so you need to compose the two
functions. If you wanted to use application, you could make a lambda
expression like \x -> sum $ map read x, because now map is fully
applied and is a value for sum.

(Note that I'm oversimplifying a bit here; Haskell doesn't actually
make a distinction between functions and values, but it's easier to
think about like this for simple cases.)

Alex
Reply | Threaded
Open this post in threaded view
|

[Haskell-begin] some basic syntax questions

Niels Aan de Brugh-3
In reply to this post by Anatoly Vorobey
On Fri, 2008-07-25 at 22:45 +0300, Anatoly Vorobey wrote:

> 2. I initially tried
>
> where sumIt = sum $ map read
>
> (the "point-free" style, I believe it's called?) but that didn't
> compile. Why not? A friend suggested
>
> where sumIt = sum . map read
>
> and that does work; I guess my real problem, then, is that I don't
> really understand the difference
> between the two and why the former doesn't work.
>

The $ is an operator that performs function application. So for example:
  show $ "Hello"
is equivalent to
  show "Hello"

You don't need an operator for function application, normally you just
type your arguments after the function. But $ just happens to be
right-associative, which means it will "evaluate" (modulo lazy semantics
of course) its right-hand-side argument before applying it to its
left-hand-side argument. So your expression
  sum $ map read
First "evaluates" (map read) then applies it to sum. That is, it's the
same as:
  sum (map read)
This is a type error, as the compiler will tell you.

The function composition operator (.) takes two functions f :: (b->c)
and g :: (a->b) and returns a function (a->c) that effectively first
applies g (yielding a 'b') and then f (yielding a 'c'). That is: f after
g. So:
  sum . map read
which should be read as:
  sum . (map read)
which is equivalent to:
  (\x -> sum ((map read) x))
which is itself a new function that reads a list of strings and sums the
result.

In my opinion it's often helpful to look at the function types using :t
in ghci, e.g. ":t (.)" and ":t ($)" (don't forget the brackets around
the operators).

I'm not an experienced Haskell programmer myself but I'd suggest not
using point free style if you find it confusing, but rather write out
parameter names and lambdas explicitly. You style will change as you get
more comfortable with the language.

Regards,
Niels