[Haskell-cafe] Non-recursive let [Was: GHC bug? Let with guards loops]

Edward Z. Yang ezyang at MIT.EDU
Wed Jul 10 10:01:04 CEST 2013


In my opinion, when you are rebinding a variable with the same name,
there is usually another way to structure your code which eliminates
the variable.

If you would like to write:

    let x = foo input in
    let x = bar x in
    let x = baz x in

instead, write

    baz . bar . foo $ input

If you would like to write

    let (x,s) = foo 1 [] in
    let (y,s) = bar x s in
    let (z,s) = baz x y s in

instead, use a state monad.

Clearly this will not work in all cases, but it goes pretty far,
in my experience.

Edward

Excerpts from Andreas Abel's message of Wed Jul 10 00:47:48 -0700 2013:
> Hi Oleg,
> 
> just now I wrote a message to haskell-prime at haskell.org to propose a 
> non-recursive let.  Unfortunately, the default let is recursive, so we 
> only have names like let' for it.  I also mentioned the ugly workaround 
> (<- return $) that I was shocked to see the first time, but use myself 
> sometimes now.
> 
> Cheers,
> Andreas
> 
> On 10.07.2013 09:34, oleg at okmij.org wrote:
> > Andreas wrote:
> >> The greater evil is that Haskell does not have a non-recursive let.
> >> This is source of many non-termination bugs, including this one here.
> >> let should be non-recursive by default, and for recursion we could have
> >> the good old "let rec".
> >
> > Hear, hear! In OCaml, I can (and often do) write
> >
> >          let (x,s) = foo 1 [] in
> >          let (y,s) = bar x s in
> >          let (z,s) = baz x y s in ...
> >
> > In Haskell I'll have to uniquely number the s's:
> >
> >          let (x,s1)  = foo 1 [] in
> >          let (y,s2)  = bar x s1 in
> >          let (z,s3)  = baz x y s2 in ...
> >
> > and re-number them if I insert a new statement. BASIC comes to mind. I
> > tried to lobby Simon Peyton-Jones for the non-recursive let a couple
> > of years ago. He said, write a proposal. It's still being
> > written... Perhaps you might want to write it now.
> >
> > In the meanwhile, there is a very ugly workaround:
> >
> >      test = runIdentity $ do
> >       (x,s) <- return $ foo 1 []
> >       (y,s) <- return $ bar x s
> >       (z,s) <- return $ baz x y s
> >       return (z,s)
> >
> > After all, bind is non-recursive let.
> >
> >
> >
> 



More information about the Haskell-Cafe mailing list