Haskell 将高阶函数提升到monad中

Haskell 将高阶函数提升到monad中,haskell,functional-programming,monads,Haskell,Functional Programming,Monads,假设我有一个高阶函数,它使用从函数参数中检索的值执行一些计算 f :: a -> (b -> c) -> d 其中a、b、c、d是一些混凝土类型 然后我有一个这样的函数 g :: b -> m c 其中m是一些单子 现在有没有一种方法可以把g和f一起使用。也就是说,把f变成一个函数,它产生md而不是d,并且可以使用g作为它的第二个参数 一个具体的例子是,m是IO单子,f是一个函数,计算从其函数参数检索到的n个数字的和,g从标准输入读取一个数字 f n g = sum

假设我有一个高阶函数,它使用从函数参数中检索的值执行一些计算

f :: a -> (b -> c) -> d
其中a、b、c、d是一些混凝土类型

然后我有一个这样的函数

g :: b -> m c
其中m是一些单子

现在有没有一种方法可以把g和f一起使用。也就是说,把f变成一个函数,它产生
md
而不是
d
,并且可以使用g作为它的第二个参数

一个具体的例子是,m是IO单子,f是一个函数,计算从其函数参数检索到的n个数字的和,g从标准输入读取一个数字

f n g = sum $ map g (1..n)
g :: Int -> IO Int
g _ = readLn
我知道有一些函数可以将标准输入转换为惰性列表,这可以解决这个问题,但我的实际情况并没有那么简单

假设我有一个在图上做某事的算法。该算法使用函数参数来确定节点的邻居。这样我就可以有多个图形的实现

现在我想用这个算法处理一个不确定的图(List monad)或者一个不完全已知的图(可能是monad)。我知道我可以重写算法使用monad,然后在基本情况下使用identity monad,但这是唯一的方法吗?我认为在没有单子的情况下编写算法会更容易


这种行为可能吗?我找不到不应该这样做的原因,但我找不到一种方法。

因此,您希望例如派生
mapM
给定
map
。也就是说,您有一个简单的
地图

map  :: (a -> b) -> [a] -> [b]
你想把它当作一个

我们可以通过映射IO操作,然后对其排序,从
map
计算
mapM
,因此:

mapM f xs = sequence (map f xs)
现在我们有了更一般的形式,我们可以通过在中运行
mapM
返回
map
,然后在标识单子中的经典
map
mapM

> 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]
所以,是的,你需要将你的高阶函数泛化到正确的层次——不管是单子,还是函子,还是应用函数,然后你可以自由地替换其他的计算概念,包括恒等式

通过转换函数的AST,可以机械地将任何纯函数重写为其一元函数:

  • 将结果值包装在
    返回中
  • 识别新的一元子表达式,并绑定它们
  • 用一元结合取代可变结合;或者,如果适用:
  • 用monad中的应用程序替换应用程序(注意)
例如

To(应用型风格)


要从map创建mapM,我们需要知道map的作用。这是必需的吗?也就是说,如果您示例中的map函数是其他函数(可能具有我们未知的定义),那么我们是否能够做到这一点?从你的回答来看,我想不是。你有什么解释吗?因为给定任何函数,我认为可以用这种方式重写它。那么,为什么一般来说不可能这样做呢?不管怎样,谢谢你的回答,我会等一会儿,如果没有其他人想出什么,我会把它标记为正确的。@MartinKolinek为你添加了一些派生词。谢谢,所以我想修改AST是唯一的方法,这意味着必须知道函数的定义。如果你想变得一般,要让这种情况发生在这种非常普遍的类型的所有
f
,那么这是不可能的。例如,一个可能的
f
f=()
,但由于它只是忽略了高阶函数部分,因此它将违反您正在寻找的行为。不过,函数的定义不是必需的。Don的示例
map
是一个很好的选择,因为我们可以确保它具有正确的类型,尽管实际上不知道
map
是如何实现的。在所有情况下,
(f::(a->b)->[a]->[b])。(g::Monad m=>[MA]->m[a]:::(a->MB)->[a]->m[b]
> runIdentity $ mapM g [1..10]
[1,4,9,16,25,36,49,64,81,100]
map f []     = []
map f (x:xs) = f x : map f xs
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)
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