非递归绑定允许我对绑定值进行阴影处理,例如:
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>
答案 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
不是非常优雅,但至少它简洁明了。它还会产生一些“阴影”警告。