bind可以由fmap和join组成,所以我们必须使用monadic函数a-> m b? [英] bind can be composed of fmap and join, so do we have to use monadic functions a -> m b?

查看:79
本文介绍了bind可以由fmap和join组成,所以我们必须使用monadic函数a-> m b?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不常使用Haskell,但我了解Monads的概念.

Kleisli三元组使我感到困惑,但是类别

fmap并加入

尽管Haskell根据return和bind函数定义了monad,但也可能根据return和另外两个操作joinfmap定义了monad.这种表述更符合范畴理论中单子的原始定义.类型为(t → u) → M t → M ufmap操作采用两种类型之间的函数,并产生对monad中的值执行相同操作"的函数. join操作(类型为M (M t) → M t)将两层单子信息平化"为一层.

帮助我了解Monads的背景原理.

这两个表述如下:

fmap f m = m >>= (return . f)
join n   = n >>= id

fmap :: (a -> b) -> (m a -> m b)
unit :: a -> m a
join :: m (m a) -> m a
>>=  :: m a -> (a -> m b) -> m b

m >>= f  =  join $ fmap f m

我的问题是: 我认为,由于>>=可以由fmapjoin组成,所以它的单子函数 a -> m b不是必需的,普通函数a -> b可以满足该操作,但是网络上的许多教程仍然坚持使用monadic函数,因为这是Kleisli三元组和monad-laws.

为简单起见,我们是否不应该仅使用非一元函数(只要它们是内函数)?我想念什么?

相关主题是

Monad连接功能

Haskell Monad绑定运算符混乱

fmap和bind之间的功能差异?

解决方案

从某种意义上说,你是对的.由于每个monad m都是函子,我们可以将fmap f与函数f :: a -> b结合使用,将m a转换为m b,但是有一个陷阱.什么是b?

我喜欢将m理解为计划获得"的意思,其中计划"涉及除纯计算之外的某种其他交互作用.如果您有计划获得Int"并且想要计划获得String",则可以将fmapInt -> String中的函数一起使用,但是该函数的类型告诉您您从Int获取String不需要进一步的交互.

并非总是如此:也许Int是学生注册号,而String是他们的名字,所以从一个转换为另一个的计划需要在某些表中进行外部查找.然后,我没有从IntString的纯函数,而是从Int到计划获取String"的纯函数.如果我在我的计划获得Int"中fmap表示满意,但是我最终得到了计划获得(plan-to-get String)",我需要外部和内部计划.

一般情况是,我们有足够的信息来计算计划以获得更多.这就是a -> m b的模型.尤其是,我们有return :: a -> m a,它使我们所拥有的信息变成了计划,而无需采取进一步的行动就可以为我们提供准确的信息,而我们有(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c),它构成了两件事.我们还认为(>=>)是关联的并且在左右吸收return,这与;是关联的并且吸收skip在经典命令式编程中一样.

使用这种组合方法从较小的计划中构建较大的计划更为方便,同时将计划获得"层的数量保持一致.否则,您需要使用fmap构建一个 n 层计划,然后在外部执行正确数量的join(这将是该计划的易碎属性). /p>

现在,由于Haskell是一种具有自由变量"和范围"概念的语言,因此 in

(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)

代表总体输入信息"只是从我们已经拥有的事物的范围出发而已,

(>>=) ::       m b  -> (b -> m c) ->       m c

然后我们得到"bind",它是一种以程序员最友好的形式呈现组成结构的工具,类似于本地定义.

总而言之,您可以使用a -> b,但是通常您需要b成为获得计划的东西",这对于选择组合构建计划是有帮助的选择.

I don't use Haskell a lot, but I understand the concept of Monads.

I had been confused by Kleisli triple, and the category, however,

fmap and join

Although Haskell defines monads in terms of the return and bind functions, it is also possible to define a monad in terms of return and two other operations, join and fmap. This formulation fits more closely with the original definition of monads in category theory. The fmap operation, with type (t → u) → M t → M u, takes a function between two types and produces a function that does the "same thing" to values in the monad. The join operation, with type M (M t) → M t, "flattens" two layers of monadic information into one.

helps me to the background principle of Monads.

The two formulations are related as follows:

fmap f m = m >>= (return . f)
join n   = n >>= id

fmap :: (a -> b) -> (m a -> m b)
unit :: a -> m a
join :: m (m a) -> m a
>>=  :: m a -> (a -> m b) -> m b

m >>= f  =  join $ fmap f m

My question is: I think that since >>= can be composed of fmap and join, a monadic function a -> m b is not required and normal functions a -> b will satisfy the operation, but so many tutorials around the web still insist to use a monadic functions since that is the Kleisli triple and the monad-laws.

Well, shouldn't we just use non-monadic functions, as long as they are endo-functions, for the simplicity? What do I miss?

Related topics are

Monad join function

Haskell Monad bind operator confusion

Difference in capability between fmap and bind?

解决方案

In a sense, you're right. As every monad m is a functor, we can use fmap f with a function f :: a -> b to turn an m a into an m b, but there's a catch. What's b?

I like to think of such an m as meaning "plan-to-get", where "plans" involve some sort of additional interaction beyond pure computation. If you have a "plan-to-get Int" and you want a "plan-to-get String", you can use fmap with a function in Int -> String, but the type of that function tells you that getting the String from the Int involves no further interaction.

That isn't always so: perhaps the Int is a student registration number and the String is their name, so the plan to convert from one to the other needs an external lookup in some table. Then I don't have a pure function from Int to String, but rather a pure function from Int to "plan-to-get String". If I fmap that across my "plan-to-get Int", that's fine, but I end up with "plan-to-get (plan-to-get String)" and I need to join the outer and inner plans.

The general situation is that we have enough information to compute the plan to get more. That's what a -> m b models. In particular, we have return :: a -> m a, which turns the information we have into the plan that gives us exactly that information by taking no further action, and we have (>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c) which composes two such things. We also have that (>=>) is associative and absorbs return on left and right, much the way ; is associative and absorbs skip in classic imperative programming.

It's more convenient to build larger plans from smaller ones using this compositional approach, keeping the number of "plan-to-get" layers a consistent one. Otherwise, you need to build up an n-layer plan with fmap, then do the right number of joins on the outside (which will be a brittle property of the plan).

Now, as Haskell is a language with a concept of "free variable" and "scope", the a in

(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)

representing the "overall input information" can just be taken to come from the scope of things we already have, leaving

(>>=) ::       m b  -> (b -> m c) ->       m c

and we get back "bind", which is the tool that presents the compositional structure in the most programmer-friendly form, resembling a local definition.

To sum up, you can work with a -> b, but often you need b to be "plan-to-get something", and that's the helpful thing to choose if you want to build plans compositionally.

这篇关于bind可以由fmap和join组成,所以我们必须使用monadic函数a-> m b?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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