11

我正在尝试对 Haskell 中的 do 语句进行脱糖处理。我在 SO 上找到了一些示例,但无法将它们应用于我的案例。我唯一能想到的是一个沉重的嵌套 let 语句,这看起来很丑陋。

应将 do 表示法替换为 bind 的语句:

do num <- numberNode x
   nt1 <- numberTree t1
   nt2 <- numberTree t2
   return (Node num nt1 nt2)

非常感谢任何输入=)

4

3 回答 3

14
numberNode x >>= \num ->
  numberTree t1 >>= \nt1 ->
    numberTree t2 >>= \nt2 ->
      return (Node num nt1 nt2)

请注意,如果您使用 Applicatives,这会更简单:

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2
于 2013-06-06T14:44:51.713 回答
8

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

正如你所看到的,这非常类似于<$>只有当函数被包装在函子“内部”时它才有效。

于 2013-06-06T14:50:52.753 回答
2

我想在上面关于 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 以便它将动作类型作为参数。

于 2013-06-06T15:13:27.193 回答