按类型指定函数参数

时间:2014-10-08 02:44:43

标签: haskell monads

我确定这很明显,但请耐心等待,我对这些东西不熟悉并且没有点击。 所以我和许多其他人一样,试图让我的头围绕Monads。我已经达到了我对>> =和返回运算符等方面感到满意的程度。但是我觉得在我落后并自己做一些写作之前我才能真正理解它。

因此,我一直在尝试为List实现bind>> =运算符作为map和foldr的组合。例如,[5,6,7,8] >>= (\x -> [x*5, x*6, x*7])会产生[25,30,35,30,36,42,35,42,49,40,48,56]。这看起来很像地图和折叠的组成。但是,如果我尝试foldr (++) [] . map之类的内容,我会得到明显的类型错误,即地图没有按预期类型[a] -> [[a]]。当然,如果我改为使用类似map (\x -> [x*5, x*6, x*7])之类的东西作为合成运算符的正确参数,那么它一切正常。

但每次指定一个特定的功能都会很麻烦;不知何故,>> =运算符以更一般的方式运行。有没有办法按类型指定参数?比如,我可以以某种方式告诉map只在这个组合中使用a -> [a]类型的函数吗?我是否需要从头开始编写一个类型为(a -> [a]) -> [a] -> [[a]]的函数,因为实际上没有办法将map函数缩小到我想要的函数类型?

另外,请随时告诉我,我接近这一切都是错的。我对这类东西还很陌生。如果是这样,请指出我正确的方向。

1 个答案:

答案 0 :(得分:7)

如果你检查类似

的类型
> :t \f -> foldr (++) [] . map f

在GHCi中,就像我上面所做的那样,你会注意到一些有趣的东西

\f -> foldr (++) [] . map f :: (a -> [b]) -> [a] -> [b]

或者,为了切入追逐,事实证明输入函数f 已经自然具有您要求的更受限制的类型。为什么会这样?

让我们检查foldr (++) [],它更自然地称为concat

concat :: [[a]] -> [a]
concat = foldr (++) []

我们看到它的输入必须是列表列表的输入。如果我们考虑使用map

在帖子构成的上下文中意味着什么
concat           ::        [[c]] -> [c]
       . map f   :: [a] -> [ b ]          -- for (f :: a -> b)

对于某些类型b,我们可以看到[c]必须与c相同。换句话说,有关使用映射f的结果的信息,例如它通过concat向后流动以专门化我们所了解的有关map甚至其参数f的信息。

因此,统一b[c],我们发现map必须具有更严格的限制类型

map ::* (a -> [c]) -> [a] -> [[c]]

我在其中写(::*)来表明这是统一自然执行的map自然类型的特化 concat