Jason Hu
Jason Hu

Reputation: 6333

is there any syntax for non-recursive binding in Haskell, just like the difference between `let` and `let rec` in similar languages?

Non-recursive binding allows me to shadow bound value, for instance:

b a = let norec a = a + 10 in a

here let norec created by myself means a let binding but not recursive.

This is extremely helpful when using record wildcards:

data MyRecord = MyRecord{ {- vary huuuuuge set of definitions -} }

foo MyRecord{..} = let norec field1 = field1 + 1
                             field2 = modify field2
                             {- some other modifications to the fields -}
                    in MyRecord{..}

Is that achievable? Or how do you deal with it in your cases?

Upvotes: 5

Views: 712

Answers (4)

chi
chi

Reputation: 116174

One option is:

-- also available from the lens package
(&) :: a -> (a->b) -> b
(&) = flip ($)

f a = -- let norec a = a + 1 in a+a
      (a+1) & \a -> a + a

g x = -- let norec x = x+1 in
      (x+1) & \x ->
      -- let norec x = x+x in
      (x+x) & \x -> 
      -- 1000+x
      1000+x

Not terribly elegant, but at least it's concise. It will also generate a few "shadowing" warnings.

Upvotes: 0

sepp2k
sepp2k

Reputation: 370377

is there any syntax for non-recursive binding in Haskell

No, there is no way to refer to a previously defined variable of a given name while defining a new variable with the same name.

foo MyRecord{..} = let norec field1 = field1 + 1
                             field2 = modify field2
                             {- some other modifications to the fields -}
                    in MyRecord{..}

This can be achieved by spelling the modified fields out explicitly (while still covering the unchanged ones with the wildcard). Since you don't need local variables that way, it isn't even more code:

foo MyRecord{..} =
  MyRecord {
    field1 = field1 + 1,
    field2 = modify field2,
    ..
  }

Note that here the identifier left of the equals sign is a record label, not a variable, while the on the right side is a variable, so even though this looks recursive, it is not.

Upvotes: 4

leftaroundabout
leftaroundabout

Reputation: 120731

Not an answer to your question, but I'd like to point to the lens alternative. Lenses are really quite a good solution to the problems of Haskell's records, which become quite a pain with larger data definitions and which RecordWildcards does, alas, not really fix as nicely as we'd like.

{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Lens.TH (makeLenses)

data MyRecord = MyRecord{ _field1 :: ...
                        , _field2 :: ...
                        {- note the underscores -} }
makeLenses ''MyRecord

foo = (field1 %~ (+1))
    . (field2 %~ modify)
    . ...

Upvotes: 3

Daniel Wagner
Daniel Wagner

Reputation: 153102

Are record wildcards actually that useful here? The usual old way of doing things looks quite concise to me:

foo r = r { field1 = field1 r + 1, field2 = modify (field2 r) }

The direct answer to your question is that there is no non-recursive analog of let in Haskell; though you can use the Identity monad to sort of hack something into place:

foo MyRecord{..} = runIdentity $ do
    field1 <- return (field1 + 1)
    field2 <- return (modify field2)
    return MyRecord{..}

Upvotes: 10

Related Questions