views:

505

answers:

5

This is about syntactic sugar in Haskell. A simple Haskell program:

main = do
  args <- getArgs
  let first = head args
  print first

I use binding in the first line (args <- getArgs) and a pure assignment in the second one (let first = ...). Is it possible to merge them together into a readable one-liner?

I understand that I can rewrite binding “de-sugared”:

main = do
  first <- getArgs >>= ( return . head )
  print first

But is there a nicer way, without cluttering the line with (>>=) and return?

+7  A: 

How about this?

import Control.Monad

main = do
   first <- liftM head getArgs
   print first
cthulahoops
D'oh! 19 seconds faster than me.
ephemient
and a lot faster than me :)
Jonas
Yes, this is much nicier. Thank you!
jetxee
Even nicer: `main = liftM head getArgs >>= print`. :)
Porges
+6  A: 

It is also possible to use the ap function (with type Monad m => m (a -> b) -> m a -> m b) like this:

import System
import Control.Monad

main :: IO ()
main = do line <- return head `ap` getArgs
          putStrLn line

This has the simple advantage that if your function requires several arguments you can use ap between each of them and you don't need to use liftM2, liftM3 etc. For a function f::a -> b -> c -> d you write

return f `ap` arg1 `ap` arg2 `ap` arg3
Jonas
Thank you. I did'n know about `ap`.
jetxee
+1  A: 

How are bind and return clutter?

main = getArgs >>= (return.head) >>= print

or

main = liftM head getArgs >>= print

ja
I usually think about return as “wrap into monad”, and (>>=) as “unwrap and substitute”. So reading the code is something like “unwrap and substitute, and wrap again, and unwrap and substitute”. So, liftM is more readable for me, because it is simply “make function monadic”. So, I like option 2.
jetxee
+11  A: 

liftM and head are all very well, but let us not forget pattern matching:

main = do { arg:_ <- getArgs; print arg }

or if you like layout

main = do
    arg : _ <- getArgs
    print arg

When possible, most Haskellers prefer pattern matching over head and tail.

Norman Ramsey
This is really nice and readable. Thanks!
jetxee
~[arg] <- getArgs
Dario
+6  A: 

Yet another possibility:

main = putStr . head =<< getArgs
Jonas
Well, it's nice. I didn't think about reversed version. Thank you.
jetxee