将`do`表示`addStuff`转换为`>> =`

时间:2014-08-12 02:29:09

标签: haskell

Learn You a Haskell显示addStuff函数:

import Control.Monad.Instances

addStuff :: Int -> Int
addStuff = do
    a <- (*2)    -- binds (*2) to a
    b <- (+10)   -- binds (+10) to b
    return (a+b) -- return has type sig: 'Monad m => a -> m a'

abreturn (a+b)的所有类型Int -> Int是什么?我是这么认为的,但我不确定bind - 如何发挥作用。

我尝试使用>>=实现它,但我不确定如何完成它(因此...)。

addStuff' :: Int -> Int
addStuff' = (*2) >>= (+10) >>= ...

请给我一个提示来完成它,以及编辑我对do符号版本的理解。

据我了解,...需要包含Int -> Int类型。在do版本中,我可以使用ab,但我不确定如何使用>>=版本添加它们。

3 个答案:

答案 0 :(得分:7)

使用阅读器monad(a.k.a。函数monad)时,您的类型为a -> b,可以将其重写为(->) a b。这里的实际monad实例是

instance Monad ((->) r) where
    return x = const x
    f >>= g = \r -> g (f r) r

请注意,在>>=期间,类型为

(>>=) :: ((->) r a) -> (a -> ((->) r b)) -> ((->) r b)

可以改写为

(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b)

甚至

(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)

正如您所看到的,>>=执行的操作只需一个输入,将其应用于f,然后将该结果应用于g以生成新函数{{1 }}。因此,对于您的示例,您可以使用:

r -> b

所以addStuff' :: Int -> Int addStuff' = (*2) >>= (+) ,因为它执行计算addStuff' 10 == 30。请注意(10 * 2) + (10)10同时(*2)如何投放,(+)的结果也会投放到(10*2)。将它视为

可能会让事情变得更加清晰
(+)

结果将是

test :: Int -> (Int, Int, Int)
test = do
    x <- (*2)
    y <- (*3)
    z <- (*5)
    return (x, y, z)

这主要是做什么是在“它被应用之前将参数带到> test 1 (2, 3, 5) > test 10 (20, 30, 50) ”,将其提供给test右侧的每个函数,然后将其组合结果是<-


那么如何在没有记号的情况下编写这些内容?你可以做点什么

return

不可否认,即使是格式化,也不是很易读,但要点基本上是test :: Int -> (Int, Int, Int) test = (\r -> r * 2) >>= (\x -> (\r -> r * 3) >>= (\y -> (\r -> r * 5) >>= (\z -> return (x, y, z)))) 被送到每个中间函数,这会产生一个结果,而后面几个嵌套的lambda表达式会返回所有三个这些结果是一个元组。

通过一些简化,你也可以将每个嵌套的lambda都变成两个参数lambdas:

r

我还用等效的test = (\r -> r * 2) >>= (\x r -> r * 3) >>= (\y r -> r * 5) >>= (\z r -> const (x, y, z) r) =&gt;替换了上一个\z -> return (x, y, z)\z -> const (x, y, z),所以他们都有相同的形式。

答案 1 :(得分:4)

如果您想要手动desugar do-notation作为一个粗略的规则,首先擦除顶部的do并将左侧的绑定箭头(<-)翻转为{{1在右侧,左侧的变量作为右侧的lambda变量。所以:

(>>=)

变为:

addStuff :: Int -> Int
addStuff = do
    a <- (*2)
    ... rest ...

这是递归的,所以在do-notation中的下一个术语然后嵌套在它上面的desugared术语的lambda中,一直到最后一个表达式,它只是嵌套的lambda表达式的主体。

desugaring是非常机械的,它由以下重写定义,其中addStuff :: Int -> Int addStuff = (*2) >>= (\a -> ... rest ... ) 表示换行符。

;

do { a <- f ; m } ≡ f >>= \a -> do { m } do { f ; m } ≡ f >> do { m } do { m } ≡ m a都属于b类型,而Int的类型为return (a+b),这是填充符号中的最后一个术语,因此必须与顶级签名相同。使用-XScopedTypeVariables,我们可以手动注释子项:

Int -> Int

答案 2 :(得分:0)

感谢bheklilr。 我写了自己的代码。

nodes = post.subtree(:to_depth => 1).order(score: :desc).limit(6)
child_ids = nodes.ids