我正试图在Haskell中去做一个do语句。我在这里找到了一些例子但是不能将它们应用到我的案例中。 我唯一能想到的是一个沉重的嵌套let语句,看起来很难看。
应该用bind替换表示法的语句:
do num <- numberNode x
nt1 <- numberTree t1
nt2 <- numberTree t2
return (Node num nt1 nt2)
高度赞赏任何输入=)
答案 0 :(得分:13)
numberNode x >>= \num ->
numberTree t1 >>= \nt1 ->
numberTree t2 >>= \nt2 ->
return (Node num nt1 nt2)
请注意,如果您使用Applicatives,这会更简单:
Node <$> numberNode x <*> numberTree t1 <*> numberTree t2
答案 1 :(得分:8)
这是applicative style的一个很好的用例。您可以使用
替换整个代码段(在导入Control.Applicative
之后)
Node <$> numberNode x <*> numberTree t1 <*> numberTree t2
将应用样式(使用<$>
和<*>
)视为“提升”函数应用程序,以便它也适用于仿函数。如果你在心理上忽略<$>
和<*>
,它看起来就像普通的功能应用程序一样!
只要你有一个纯函数并且你想给它不纯的参数(或任何函子参数,实际上),应用风格很有用 - 基本上当你想要做你在问题中指定的内容时!
<$>
的类型签名是
(<$>) :: Functor f => (a -> b) -> f a -> f b
这意味着它需要一个纯函数(在本例中为Node
)和一个函子值(在本例中为numberNode x
),它会创建一个包含在“函数内部”的新函数。您可以使用<*>
向此函数添加更多参数,其中包含类型签名
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
正如您所看到的,这与<$>
非常相似,只有当函数被“包含在”函数内部时才会起作用。
答案 2 :(得分: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从任何类型的动作中取出值,用它调用f,然后重新打包结果。相反,我们可以解除f,以便将行动类型作为其论据。