Maintaining haskell programs

You don’t need a Monad instance; you can write things like

baz :: Int
baz = do 5

I guess that if you don’t try to compose or sequence “statements”, the instance is not required at all.

In fairness, we are just used to read “$” as deliminator, nothing readable about it neither. When I first started Haskell, it was shockingly alien too.

Also, the “true” type of $ is kind of hairy:

($) :: forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r). (a -> b) -> a -> b

Upon reflection, it feels odd to deploy an operator with such a complex type out of mere syntactic convenience.

4 Likes

Also, does the BlockArgument works for lambda too ? In that case the first do should be redundant.

You are not alone:

1 Like

Adding on to that… linear-base has its own “$” and it doen’t jive well with base’s “$”… So I might actually also be using do + BlockAguments then :confused: Only thing bother me is how to read it aloud.

1 Like

I just tried, no, for obvious reason in hindsight.

So, no blockarguments:

example = fmap
    (\x -> x^2 + 1)
    [1, 2, 3]

example' = flip map
    [1,2,3]
    $ \x -> x+1

with blockarguments:

{-# LANGUAGE BlockArguments #-}

-- GHC says no
-- example = fmap
--    $ \x -> x^2 + 1
--    $ [1, 2, 3]

example' = fmap
    do \x ->
        x^2 + 1
    do [1, 2, 3]

example'' = fmap
    do \x ->
        x^2 + 1
    [1, 2, 3]
-- or other combinations

Actually I find example'' might be quite readoable.

Edit: fixed some compilation failures, and add one more example from maxigit. Make intentional multi-line lambda to highlight the fact that it can do that.

You shouldn’t need the do before the lambda

example = flip map 
        [1,2,3]
        \x -> x+1

example2 = map 
        do \x -> x+1
        [1,2,3]

work, but

example = map 
        \x -> x+1
        [1,2,3]

Doesn’t compile …

There is indeed something compeling about (ab)using a language keyword instead of calling an (external) function.
Basicall do acts as a $ until the end of the line

example3 = (,)
         do 3 + 3
         do 10 * 5

ghci> example3
(6,50)

1 Like

As with the lambda, do and lamba don’t close the same way

exampleLet = (,)
           do 10 * 5
           let x = 3 in x+x

compiles but

exampleLet2 = (,)
           let x = 3 in x+x
           do 10 * 5

doesn’t which excludes

exampleLet3 = (,)
       let x = 3 in x+x
       let y = 10 in y+5

The remaining question to be nitpicking would be… would they generate the exact same code?

exampleLet2' = (,)
           do let x = 3 in x+x
           do 10 * 5

?

Multiline-lambda without brackets was what I used blockarguments for though.

Edit:

Added an example:

exampleLet2' = (,)
            do \(me, a, favor) ->
                favor a me
            do 10 * 5

It does work, but let should work without the do (as it works in exampleLet).

In Haskell 2010, certain kinds of expressions can be used without parentheses as an argument to an operator, but not as an argument to a function. They include do , lambda, if , case , and let expressions.

do and let both starts a new expression, but do stops at the end of the line, whereas let at the total end …

Another potential “hairball” :

  • GADTs, Functoriality, Parametricity: Pick Two

3 Likes

Have read the books. I do wish though there were more “projects” and exercises. I find that’s ideas make sense when I read them but as I went I found myself having to constantly reread parts.

1 Like