gpt4 book ai didi

haskell - 为什么一个函数不能接受单子(monad)值并返回另一个单子(monad)值?

转载 作者:行者123 更新时间:2023-12-03 15:04:45 25 4
gpt4 key购买 nike

假设我们有两个一元函数:

  f :: a -> m b
g :: b -> m c
h :: a -> m c

绑定(bind)函数定义为
(>>=) :: m a -> (a -> m b) -> m b

我的问题是为什么我们不能做下面的事情。声明一个接受一元值并返回另一个一元值的函数?
  f :: a -> m b
g :: m b -> m c
h :: a -> m c

绑定(bind)函数定义为
(>>=) :: m a -> (ma -> m b) -> m b

haskell 中有什么限制函数将一元值作为参数?

编辑:我想我没有把我的问题说清楚。关键是,当您使用绑定(bind)运算符组合函数时,为什么绑定(bind)运算符的第二个参数是一个采用非单子(monad)值( b)的函数?为什么它不能采用一元值( mb )并返回 mc .是不是这样,当您处理 monad 时,您将编写的函数将始终具有以下类型。
  f :: a -> m b
g :: b -> m c
h :: a -> m c

h = f 'compose' g
我正在尝试学习单子(monad),这是我无法理解的。

最佳答案

Monad的关键能力是“看里面”m a输入并查看 a ;但是 Monad 的关键限制是单子(monad)必须有可能是“不可避免的”,即 Monad typeclass 操作不足以编写 Monad m => m a -> a 类型的函数. (>>=) :: Monad m => m a -> (a -> m b) -> m b给你这个能力。

但实现这一目标的方法不止一种。 Monad类可以这样定义:

class Functor f where
fmap :: (a -> b) -> f a -> f b

class Functor f => Monad m where
return :: a -> m a
join :: m (m a) -> m a

你问为什么我们不能有 Monad m => m a -> (m a -> m b) -> m b功能。好吧,给定 f :: a -> b , fmap f :: ma -> mb基本上就是这样。但是 fmap其本身并不能让您“向内看” Monad m => m a却又无法摆脱它。然而 joinfmap一起给你那个能力。 (>>=)可以写成 fmapjoin :
(>>=) :: Monad m => m a -> (a -> m b) -> m b
ma >>= f = join (fmap f ma)

事实上,这是定义 Monad 的常用技巧。例如,当您想出 (>>=) 的定义时遇到问题——写 join为你可能的 monad 提供函数,然后使用 (>>=) 的通用定义.

好吧,这回答了问题的“它必须是它的方式”的一部分,并带有“否”。但是,为什么会这样呢?

我不能代表 Haskell 的设计者,但我喜欢这样想:在 Haskell monadic 编程中,基本的构建 block 是这样的 Action :
getLine :: IO String
putStrLn :: String -> IO ()

更一般地说,这些基本构建 block 的类型类似于 Monad m => m a , Monad m => a -> m b , Monad m => a -> b -> m c , ..., Monad m => a -> b -> ... -> m z .人们非正式地称这些行为。 Monad m => m a是无参数操作, Monad m => a -> m b是一个单参数 Action ,依此类推。

好吧, (>>=) :: Monad m => m a -> (a -> m b) -> m b基本上是“连接”两个 Action 的最简单的功能。 getLine >>= putStrLn是首先执行的 Action getLine ,然后执行 putStrLn将执行 getLine 获得的结果传递给它.如果您有 fmapjoin而不是 >>=你必须这样写:
join (fmap putStrLn getLine)

更一般地说, (>>=)体现了一个很像 Action “管道”的概念,因此对于使用 monad 作为一种编程语言来说,它是更有用的运算符。

最后一件事:确保您了解 Control.Monad 模块。而 return(>>=)是 monad 的基本函数,您可以使用这两个函数定义无数其他更高级的函数,并且该模块收集了几十个更常见的函数。 (>>=) 不应该强制你的代码穿紧身衣。 ;它是一个重要的构建 block ,既可以单独使用,也可以作为更大构建 block 的组件。

关于haskell - 为什么一个函数不能接受单子(monad)值并返回另一个单子(monad)值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11967645/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com