假设我有一个更高阶的函数,它使用从函数参数中检索的值执行一些计算。
f :: a -> (b -> c) -> d
其中a,b,c,d是一些具体类型。
然后我有一个这种类型的函数
g :: b -> m c
其中m是一些monad。
现在有办法将g与f一起使用。那就是把f变成一个产生m d
而不是d
的函数,可以用g作为它的第二个参数吗?
一个具体的例子是m是IO monad,f是计算从其功能参数中检索到的n个数字之和的函数,g从标准输入中读取数字。
f n g = sum $ map g (1..n)
g :: Int -> IO Int
g _ = readLn
我知道有一些函数可以将标准输入转换为惰性列表,这可以解决这个问题,但我的实际情况并不那么简单。
假设我有一个在图表上做某事的算法。该算法使用功能参数来确定节点的邻居。这样我就可以有多个图形实现。
现在我想将此算法与非确定性图形(List monad)或未完全已知的图形(可能是monad)一起使用。我知道我可以重写算法使用monads然后使用身份monad作为基本情况,但这是唯一的方法吗?我认为在没有monad的情况下编写算法会更容易。
这种行为可能吗?我找不到它不应该的原因,但我找不到如何做的方法。
答案 0 :(得分:7)
所以你想要例如派生mapM
给出map
。那就是你有一个简单的map
:
map :: (a -> b) -> [a] -> [b]
并且您希望将其用作map
on monadic structures
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
我们可以通过映射IO操作,然后对它们进行排序,从mapM
计算map
,因此:
mapM f xs = sequence (map f xs)
现在我们有了更通用的表单,我们可以通过在the Identity monad.中运行map
然后在mapM
中使用map
来获取mapM
身份monad。
> let g :: Int -> Identity Int
g a = return (a^2)
其中:
> runIdentity $ mapM g [1..10]
[1,4,9,16,25,36,49,64,81,100]
所以是的,你需要将你的高阶函数归为正确的级别 - 无论是monad,functor还是applicative,那么你可以自由地用其他的计算概念来代替,包括身份。
你可以通过转换函数的AST来机械地将任何纯函数重写为它的monadic:
return
E.g。
map f [] = []
map f (x:xs) = f x : map f xs
To(applicative style)
mapM f [] = return []
mapM f (x:xs) = (:) <$> f x <*> mapM' f xs
或更不清楚,并修正评估顺序:
mapM f [] = return []
mapM f (x:xs) = do
v <- f x
vs <- mapM f xs
return (v:vs)
我们可以使用地图的应用程序,因为不需要monadic绑定来将结果从一步传递到下一步。 foldl
:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z0 xs0 = lgo z0 xs0
where
lgo z [] = z
lgo z (x:xs) = lgo (f z x) xs
foldlM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
foldlM f z0 xs0 = lgo z0 xs0
where
lgo z [] = return z
lgo z (x:xs) = do
v <- f z x
lgo v xs