将`do`符号`addStuff`转换为`>> =` [英] Converting `do` Notation `addStuff` to `>>=`

查看:155
本文介绍了将`do`符号`addStuff`转换为`>> =`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

学习你一个Haskell 介绍 addStuff
$ p $ import Control.Monad.Instances

addStuff :: Int - > (* 2) - 绑定(* 2)到
b < - (+10) - 绑定(+10)到b
return(a + b) - return有类型sig:'Monad m => a - > m a'

类型是 a b return(a + b) all Int - >诠释?我想是的,但我不确定绑定 -ing是如何起作用的。



我试图执行它使用>> = ,但我不知道如何完成它(因此 ... ) 。

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

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

据我所知, ... 需要包含一种 Int - > INT 。在 do 版本中,我可以使用 a b ,但我不确定如何将它们添加到>> = 版本。

解决方案

当使用monad读写器(又名函数monad)时,您可以输入 a - > b ,可以改写为( - >)a b 。这里的实际monad实例是

pre $实例Monad(( - >)r)其中
return x = const x
f>> = g = \ r - > g(fr)r

请注意,在>> = ,类型是

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

可以改写为

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

甚至

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

因此,您可以看到> ;> = does是接受一个输入,将其应用于 f ,然后将结果应用于 g 生成一个新函数 r - > B'/ code>。因此,对于您的示例,您可以使用:

  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)
返回(x,y,z)

结果会是

 >测试1 
(2,3,5)
>测试10
(20,30,50)

实际上,参数 test 之前应用它,将它提供给< - s,然后将结果合并到 return 中。






那么,你怎么能不写这些符号呢?你可以做一些像


  test :: Int  - > (Int,Int,Int)
test =
(\r - > r * 2)>> =(\ x - >
(\r - > ($ \\ $ - $> $> $> $> $> $> $> $> $> $> $ x,y,z))))

即使格式化,但其要点基本上是将 r 传递给每个产生结果的中间函数,然后将一对嵌套的lambda表达式传递给一个元组,然后将所有这三个结果返回给一个元组。

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



<$ ($ \\ r - > r * 3)>> ; =
(\yr→r * 5)>> =
(\zr--> const(x,y,z)r)

我也取代了最后一个 \z - >返回(x,y,z)及其等价的 \ z - > const(x,y,z) => \ z r - > const(x,y,z)r ,所以它们都具有相同的形式。


Learn You a Haskell presents the addStuff function:

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'

Are the types of a, b, and return (a+b) all Int -> Int? I think so, but I'm not sure how bind-ing plays a role.

I tried to implement it using >>=, but I'm not sure how to complete it (hence ...).

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

Please give me a hint to complete it, as well as edit my understanding of the do notation version.

As I understand, the ... needs to include a type of Int -> Int. In the do version, I could use a and b, but I'm not sure how to add them with the >>= version.

解决方案

When working with the reader monad (a.k.a. the function monad), you have the type a -> b, which can be rewritten as (->) a b. The actual monad instance here is

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

Notice that during >>=, the type is

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

Which can be rewritten as

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

Or even

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

So as you can see, what >>= does is take a single input, apply that to f, and then apply that result to g to produce a new function r -> b. So for your example, you could use:

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

And so addStuff' 10 == 30, since it performs the computation (10 * 2) + (10). Note how 10 is fed both to (*2) and (+), and the result of (10*2) is fed to (+) as well. It might make things a little more clear to see it as

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

And it's result would be

> test 1
(2, 3, 5)
> test 10
(20, 30, 50)

What this essentially is doing is taking the argument to test "before" it's been applied, feeding it to each of the functions on the right hand side of the <-s, and then combining that result in the return.


So how can you write these without do notation? You could do something like

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

Which, admittedly, is not very readable, even with formatting, but the gist is basically that r gets fed to each intermediate function, which produces a result, and a couple nested lambda expressions later you return all three of those results in a tuple.

With a bit of simplification, you could also make each of those nested lambdas into two arguments lambdas:

test =
    (\r -> r * 2) >>=
        (\x r -> r * 3) >>=
            (\y r -> r * 5) >>=
                (\z r -> const (x, y, z) r)

I've also replaced the last \z -> return (x, y, z) with its equivalent \z -> const (x, y, z) => \z r -> const (x, y, z) r, just so they all have the same form.

这篇关于将`do`符号`addStuff`转换为`&gt;&gt; =`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆