我正在尝试对 Haskell 中的 do 语句进行脱糖处理。我在 SO 上找到了一些示例,但无法将它们应用于我的案例。我唯一能想到的是一个沉重的嵌套 let 语句,这看起来很丑陋。
应将 do 表示法替换为 bind 的语句:
do num <- numberNode x
nt1 <- numberTree t1
nt2 <- numberTree t2
return (Node num nt1 nt2)
非常感谢任何输入=)
我正在尝试对 Haskell 中的 do 语句进行脱糖处理。我在 SO 上找到了一些示例,但无法将它们应用于我的案例。我唯一能想到的是一个沉重的嵌套 let 语句,这看起来很丑陋。
应将 do 表示法替换为 bind 的语句:
do num <- numberNode x
nt1 <- numberTree t1
nt2 <- numberTree t2
return (Node num nt1 nt2)
非常感谢任何输入=)
numberNode x >>= \num ->
numberTree t1 >>= \nt1 ->
numberTree t2 >>= \nt2 ->
return (Node num nt1 nt2)
请注意,如果您使用 Applicatives,这会更简单:
Node <$> numberNode x <*> numberTree t1 <*> numberTree t2
这是applicative style的一个很好的用例。您可以将整个代码段(导入后Control.Applicative
)替换为
Node <$> numberNode x <*> numberTree t1 <*> numberTree t2
将应用风格(使用<$>
and <*>
)视为“提升”功能应用程序,因此它也适用于函子。如果您在精神上忽略它<$>
,<*>
它看起来很像正常的功能应用程序!
只要你有一个纯函数并且你想给它不纯的参数(或任何函子参数,真的),应用风格就很有用——基本上当你想做你在问题中指定的事情时!
的类型签名<$>
是
(<$>) :: Functor f => (a -> b) -> f a -> f b
这意味着它需要一个纯函数(在这种情况下Node
)和一个函子值(在这种情况下numberNode x
),它会创建一个包装在函子“内部”的新函数。<*>
您可以使用具有类型签名的向此函数添加更多参数
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
正如你所看到的,这非常类似于<$>
只有当函数被包装在函子“内部”时它才有效。
我想在上面关于 Applicative 的帖子中添加..
考虑类型<$>
:
(<$>) :: Functor f => (a -> b) -> f a -> f b
它看起来就像 fmap:
fmap :: Functor f => (a -> b) -> f a -> f b
这也很像 Control.Monad.liftM:
liftM :: Monad m => (a -> b) -> m a -> m b
我认为这是“我需要将数据构造函数提升为这种类型”
在相关说明中,如果您发现自己这样做:
action >>= return . f
你可以这样做:
f `fmap` action
第一个例子是使用 bind 从任何类型的 action 中取出值,用它调用 f,然后重新打包结果。相反,我们可以提升 f 以便它将动作类型作为参数。