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'
a
,b
和return (a+b)
的所有类型Int -> Int
是什么?我是这么认为的,但我不确定bind
- 如何发挥作用。
我尝试使用>>=
实现它,但我不确定如何完成它(因此...
)。
addStuff' :: Int -> Int
addStuff' = (*2) >>= (+10) >>= ...
请给我一个提示来完成它,以及编辑我对do
符号版本的理解。
据我了解,...
需要包含Int -> Int
类型。在do
版本中,我可以使用a
和b
,但我不确定如何使用>>=
版本添加它们。
答案 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