在Haskell中是否存在非递归绑定的语法,就像在类似语言中`let`和`let rec`之间的区别一样?

时间:2015-08-04 18:46:34

标签: haskell

非递归绑定允许我对绑定值进行阴影处理,例如:

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

此处let norec由我自己创建,意味着let绑定,但不是递归。

使用记录通配符时非常有用:

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{..}

这可以实现吗?或者你如何在你的情况下处理它?<​​/ p>

4 个答案:

答案 0 :(得分:10)

记录通配符实际上在这里有用吗?通常陈旧的做事方式对我来说非常简洁:

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

你问题的直接答案是Haskell中没有let的非递归模拟;虽然你可以使用Identity monad来解决某些问题:

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

答案 1 :(得分:4)

  

在Haskell

中是否有任何非递归绑定的语法

不,在定义具有相同名称的新变量时,无法引用先前定义的给定名称变量。

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

这可以通过明确拼写修改后的字段来实现(同时仍然用通配符覆盖未更改的字段)。由于您不需要这样的局部变量,因此代码更多:

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

请注意,此处等号的左侧标识符是记录标签,而不是变量,而右侧的标识符是变量,因此即使这看起来是递归的,也不是。

答案 2 :(得分:3)

不是您问题的答案,但我想指出lens替代方案。对于Haskell记录的问题来说,镜头确实是一个非常好的解决方案,对于更大的数据定义会变得非常痛苦,而且RecordWildcards确实很难解决我们喜欢的问题。

{-# 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)
    . ...

答案 3 :(得分:0)

一个选项是:

-- 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

不是非常优雅,但至少它简洁明了。它还会产生一些“阴影”警告。