bind可以由fmap和join组成,所以我们必须使用monadic函数a - > mb吗?

7 math monads haskell functional-programming functor

我不太多使用Haskell,但我理解Monads的概念.

我被Kleisli三重混淆了,然而,类别,

fmap和加入

虽然Haskell中在返回和绑定功能方面限定单子,但也可以在以下方面,以限定一个单子return和其它两个操作,joinfmap.该公式更符合类别理论中monad的原始定义.fmap具有类型的操作(t ? u) ? M t ? M u在两种类型之间采用函数,并生成一个函数,该函数对monad中的值执行"相同的操作".该join类型的操作将M (M t) ? M t两层monadic信息"扁平"为一层.

帮助我了解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
Run Code Online (Sandbox Code Playgroud)

我的问题是:我认为既然>>= 可以由fmap和组成,并且不需要joinmonadic函数, a -> m b并且普通函数a -> b将满足操作,但是围绕Web的许多教程仍然坚持使用monadic函数,因为那是Kleisli triple和单子公婆.

那么,为了简单起见,我们不应该只使用非monadic函数,只要它们是endo函数即可吗?我错过了什么?

相关主题是

Monad加入功能

Haskell Monad绑定运算符混淆

fmap和bind之间的能力差异?

pig*_*ker 9

从某种意义上说,你是对的.由于每一个单子m是一个仿函数,我们可以用fmap f一个函数f :: a -> b把一个m a成一个m b,但有一个问题.什么b

我喜欢将这样的m意思想象为"计划获取",其中"计划"涉及除纯计算之外的某种额外交互.如果你有一个"计划获得Int"并且你想要一个"计划获取String",你可以使用fmap一个函数Int -> String,但该函数的类型告诉你String从中获取Int不涉及进一步的交互.

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

一般情况是我们有足够的信息来计算计划以获得更多.那就是a -> m b模特.特别是,我们已经return :: a -> m a将我们所掌握的信息转化为计划,通过不采取进一步行动来为我们提供准确的信息,而且我们有(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)两个这样的事情.我们也有(>=>)联想和左右吸收return,很多方式;是联想和吸收skip经典命令式编程.

它是建立使用该构图方法较小的更大的计划更方便,保持的"从计划到获得"层数一致的一个.否则,你需要建立一个n层计划fmap,然后join在外面做正确数量的s(这将是计划的脆弱属性).

现在,哈斯克尔是"自由变量"和"范围",在一个概念的语言a

(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)
Run Code Online (Sandbox Code Playgroud)

代表"整体输入信息"只能来自我们已有的东西,离开

(>>=) ::       m b  -> (b -> m c) ->       m c
Run Code Online (Sandbox Code Playgroud)

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

总而言之,您可以使用a -> b,但通常需要b"计划获得某些东西",如果您想要在构图上构建计划,这是有用的选择.

  • 这种类型的"Int String"是什么意思?它不能被称为`Int String`,因为`Int`和`String`已经是类型.如果要达到*适当的*一般性,为什么特殊类型会是一个好主意呢?假设我想从名称转换回注册号码?那个'String - > m Int`需要*相同的*`m`但不同的值类型.关键是要指出允许哪种类型的*交互计划*,与通过这些计划计算的价值类型无关,并允许计划构建计划. (3认同)
  • @KenOKABE我很困惑.您是否重新发布自己被删除的评论或其他人的评论?此外,还有很多东西要从这些评论中解压缩和讨论.我相信至少有一两个误解会掩盖事物. (2认同)

Dar*_*nec 6

我很难理解您的问题是什么,但是无论如何我都会设法解决。

我认为,由于>>=可以由fmap和组成,所以不需要join一元函数, a -> m b而普通函数a -> b将满足该操作,

我希望您a -> m b在的类型中引用“ monadic函数”,对>>=吗?好吧,让我们看看用type函数替换它时会发生什么a -> b

(>>=) :: m a -> (a -> m b) -> m b  -- standard version
(>>=) :: m a -> (a -> b) -> m b    -- your version
Run Code Online (Sandbox Code Playgroud)

但这看起来不熟悉吗?等效于fmap :: (a -> b) -> m a -> m b,但参数已切换。实际上,实现只是x >>= y = fmap y x,不需要join。因此,您的答案是:如果您使用“普通函数a -> b”而不是“单函数a -> m b”,则您将不再有单子。相反,您有一个Functor


但是网络上的许多教程仍然坚持使用monadic函数,因为那是Kleisli三元组和monad-laws。

我不确定您要查看哪些教程。以我的经验,教程的本质是他们坚持要使用任何教程。如果Monads 的教程开始提出问题,然后提出除Monads 之外的其他东西作为解决方案,那将很奇怪。至少,这超出了本教程的范围,对于任何阅读它来了解Monads的人来说都是浪费时间。


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

内在功能是类型的功能a -> a。鉴于你的问题的情况下,我想你实际上意味着纯功能型的a -> b(“纯”,而不是固有的一元函数,如readIORef需要进行类型a -> m b)。如果我的假设是错误的,请告诉我,我将编辑问题。

编辑:
正如@duplode在评论中所建议,您可能是说endofunctor,在Haskell中只是任何类型的Functor。在这种情况下,以下内容仍然适用。

在情况下Monad是没有必要的,它往往更容易使用ApplicativeFunctor或只是基本的纯函数。在这些情况下,应(通常)使用这些东西代替Monad。例如:

ws <- getLine >>= return . words  -- Monad
ws <- words <$> getLine           -- Functor (much nicer)
Run Code Online (Sandbox Code Playgroud)

需要明确的是:如果没有monad可以实现,如果没有monad则更简单易读,那么就应该没有monad来做到!如果monad使代码变得比所需复杂或混乱,请不要使用monad!Haskell具有monad的唯一目的是使某些复杂的计算更简单,更易于阅读且更易于推理。如果那没有发生,那么您不应该使用monad

  • @ user6440264我很难理解您的问题的原因是因为我可以采用大约十种千差万别的方式来解决问题,而这些方式都具有同等的意义。换句话说,我的“理解还不够”的原因是因为*您不够清楚*。我认为我不应该为此而投票。我希望我们大家一起努力,互相学习(最终是本网站的目的),但令我有些失望的是,这还没有实现。 (2认同)