在Haskell中扩展左活页夹
我试图理解哈斯克尔的单子,所以我在阅读在Haskell中扩展左活页夹,haskell,Haskell,我试图理解哈斯克尔的单子,所以我在阅读 让我们从上面的站点考虑一段代码: maternalGrandfather :: Sheep -> Maybe Sheep maternalGrandfather s = (return s) >>= mother >>= father fathersMaternalGrandmother :: Sheep -> Maybe Sheep fathersMaternalGrandmother s = (return s)
让我们从上面的站点考虑一段代码:
maternalGrandfather :: Sheep -> Maybe Sheep
maternalGrandfather s = (return s) >>= mother >>= father
fathersMaternalGrandmother :: Sheep -> Maybe Sheep
fathersMaternalGrandmother s = (return s) >>= father >>= mother >>= mother
一切都很清楚。但我想知道如何制作一个长的(也许是无限的)序列。我的意思是,例如:
expand :: Int -> Sheep -> MaybeSheep
例如,expand forexpand 10 s
makes(返回s)>>=父>>=父>>=父>>=父>>=父>>=父。。(10次)
如何实施。可能使用递归进行扩展,但我无法想象停止时会返回什么。您可以使用iterate进行此操作
iterate (>>= father) (return s) !! 10
将10更改为所需的父应用程序的数量。如果您有一个关于一元操作的列表(例如,
[IO x]
或[Maybe Int]
或其他什么),您可以使用sequence
函数将所有这些操作链接在一起。(请注意,它们首先必须具有相同的类型才能将它们放入列表中。)
如果您有一个输入列表,并且希望将它们传递给一元函数(例如,String->Maybe Int
),您可以将您的函数映射到该列表上,从而生成一元操作列表。然后,您可以使用序列
链接这些。但这是一种常见的模式,因此有一个函数用于此:您可以直接使用mapM
来处理这种情况
一般来说,在Control.Monad中查看一下其他与Monad相关的有用函数。与其考虑如何对一元值重复应用“一元函数”,不如考虑如何“折叠”将一元函数列表转换为一个函数,以后可以应用于一元值
在Haskell中,“折叠”列表的原型组合符称为:
foldr
接收函数、初始值和列表作为参数。它所做的是用函数替换列表中的每个构造函数:
,并用初始值替换列表末尾的空构造函数[]
。例如,考虑下面的Its列表:
4 : 5 : 77 : 34 : []
假设我们要将列表中的所有元素添加到88。我们可以这样做
foldr (+) 88 (4 : 5 : 77 : 34 : [])
这实际上等于
4 + 5 + 77 + 34 + 88.
好,现在假设列表的元素是a->a
类型的函数。我们可以用组合运算符(.)
组合两个函数,但是,我们应该用什么函数替换列表的末尾[]
?我们不想添加任何进一步的修改,所以我们将“中性元素”放在合成中,即标识函数id
:
foldr (.) id ((\x -> x + 1) : (\y -> y + 2) : [])
这等于
(\x -> x + 1) . (\y -> y + 2) . id
我们越来越近了。我们需要像(.)
这样的复合运算符,但对于一元函数,它可以组合两个一元函数并生成另一个。某种类型的东西Monad m=>(a->ma)->(a->ma)->a->ma
,我们发现更一般(但仍然合适)的运算符:
现在,您可以使用(>>=)
将结果应用于原始一元值,一个无限序列的一元操作将永远不会返回。(>>=)
运算符太严格了。@MathematicalArchid这通常不是真的,>=
的操作语义完全取决于如何为任何特定的monad定义函数。e、 gfix(\x->x:[[1]]>>=scanl(+)1)
定义得非常好。好的,它不是通用的。我有一个列表,我的停止约束是[]@Gilgamesz,你可以使用find
添加停止约束。
(\x -> x + 1) . (\y -> y + 2) . id
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
combineMonadicFunctions :: Monad m => [a -> m a] -> a -> m a
combineMonadicFunctions fs = foldr (<=<) return fs