我相信这很明显,但请耐心等待,我对这些东西不熟悉并且没有点击.所以我和许多其他人一样,试图让我的头脑绕过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函数缩小到我想要的函数类型?
另外,请随时告诉我,我接近这一切都错了.我对这类东西还很陌生.如果是这样,请指出我正确的方向.
如果你检查类似的东西
> :t \f -> foldr (++) [] . map f
Run Code Online (Sandbox Code Playgroud)
在GHCi中,就像我上面所做的那样,你会发现一些有趣的东西
\f -> foldr (++) [] . map f :: (a -> [b]) -> [a] -> [b]
Run Code Online (Sandbox Code Playgroud)
或者,为了切入追逐,事实证明输入功能f 已经并且自然地具有您要求的更受限制的类型.为什么会这样?
让我们来看看foldr (++) []哪个更自然地被称为concat
concat :: [[a]] -> [a]
concat = foldr (++) []
Run Code Online (Sandbox Code Playgroud)
我们看到它的输入必须是列表列表的输入.如果我们考虑在后期作文的背景下意味着什么map
concat :: [[c]] -> [c]
. map f :: [a] -> [ b ] -- for (f :: a -> b)
Run Code Online (Sandbox Code Playgroud)
我们可以看到b必须与[c]某些类型相同c.换句话说,关于使用映射结果的信息f,例如它的通过concat,已经向后流动,以专门化我们所知道的信息map甚至其论点f.
因此,统一b和[c]上面我们看到map必须有一个稍微限制更多的类型
map ::* (a -> [c]) -> [a] -> [[c]]
Run Code Online (Sandbox Code Playgroud)
我所写的地方(::*)表明这是一种自然类型的专业化,map通过与类型的统一自然而然地实现concat.