Proposal: Non-recursive let

Andreas Abel andreas.abel at
Wed Jul 10 09:08:27 CEST 2013

Proposal: add a non-recursive let to the Haskell language.  In

   let' p = e in e'
   do { ... let' p = e ... }

the variables of pattern p are then *not* in scope in e.

Reasons for adding a non-recursive let:

1. recursive-let is the source for many non-termination bugs.

An instance of such a bug is in the state monad of mtl-2.1 (forgive me, 
Edward, for quoting this again): 

     state :: (s -> (a, s)) -> m a
     state f = do
       s <- get
       let ~(a, s) = f s
       put s
       return a

here, a non-recursive let was meant, the s bound by the let was supposed 
to be a new state, shadowing the old state.  However, since let is 
recursive, this actually causes a loop.

Another instance (cut-down) are let-guards like

   let Just x | x > 0 = e in x

The "x > 0" is understood as an assertion here, documenting an 
invariant.  However, Haskell reads this as

   let Just x = case () of { () | x > 0 -> e } in x

leading to non-termination.  A non-recursive version

   let' Just x | x > 0 = e in x

could be interpreted as

   case e of { Just x | x > 0 -> x }

instead, which is meaningful (in contrast to the current interpretation).

2.  Connected to 1., a non-recursive let allows for painless shadowing.

For instance, the hack

   do ...
      x <- return $ f x

exploiting non-recursiveness of the <- binding, would be unnecessary, 
instead we could write

   do ...
      let' x = f x

NB: In a do-Block, we could drop the keyword let' and simply write

   do ...
      x = f x

for a non-monadic binding, in accordance to x <- mf x,

See also

PS.:  I can work out the details of grammar and semantics if this 
proposal finds followers.


Andreas Abel  <><      Du bist der geliebte Mensch.

Theoretical Computer Science, University of Munich
Oettingenstr. 67, D-80538 Munich, GERMANY

andreas.abel at

More information about the Haskell-prime mailing list