7 monads haskell functional-programming applicative
我试图通过在Javascript中实现他们的函数实例来提高我对Applicatives和Monads的理解.我对Haskell的了解有限,我希望我的问题有道理.
下面是我的实现fmap,<*>以及>>=为Functor,Applicative并Monad在Javascript类型类:
const fmap = f => g => x => f(g(x)); // B combinator
const apply = f => g => x => f(x) (g(x)); // S combinator
const bind = f => g => x => g(f(x)) (x); // ?
Run Code Online (Sandbox Code Playgroud)
我不确定bindHaskell实现的正确翻译是否正确:
(>>=) :: (r -> a) -> (a -> (r -> b)) -> r -> b
instance Monad ((->) r) where
f >>= k = \ r -> k (f r) r
Run Code Online (Sandbox Code Playgroud)
如果bind是正确的,它是如何解释的?我知道Applicative可以对有效的计算进行排序.我还知道,Monad此外,您还可以根据前一个效果确定下一个效果.
我可以看到序列(Javascript中急切的评估顺序):
apply:f(x)... g(x)... lambda(result of g)的...结果lambdabind:f(x)... g(result of f)... lambda(x)的...结果lambda但是,这个bind功能看起来很奇怪.为什么f和g其他方式嵌套?Monad在此实现中反映的具体行为(根据前一个确定下一个效果)如何?实际上g(f(x)) (x)看起来像一个带有翻转参数的函数组合,其中g是二元函数.
当我使用一元和二元函数应用apply/ bind时,它们会产生相同的结果.这没有多大意义.
李的答案的几个脚注:
但是,该
bind功能看起来很奇怪。为什么f和g以相反的方式嵌套?
因为bind是倒退。比较(>>=)及其翻转版本(=<<):
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(=<<) :: Monad m => (a -> m b) -> m a -> m b
Run Code Online (Sandbox Code Playgroud)
或者,在您的特定示例中:
(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b)
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
Run Code Online (Sandbox Code Playgroud)
尽管在实践中,我们倾向于使用(>>=)更多的东西(=<<)(因为从(>>=)句法上讲,如何使它很适合通常用来构建的管道monad的类型),但是从理论上讲,这(=<<)是最自然的编写方式。特别是,与fmap/ (<$>)和的相似之处和不同之处(<*>)更加明显:
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(=<<) :: Monad f => (a -> f b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
当我将
apply/bind与一元函数和二进制函数一起应用时,它们会产生相同的结果。这没有多大意义。
那是关于函数实例的偶然事实。让我们并排放置专用签名:
(<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
Run Code Online (Sandbox Code Playgroud)
Monad超越Applicative了提供根据先前结果确定下一个效果的方法(与“上一个效果”相反- Applicative已经可以做到)。在这种情况下,效果由一个函数产生,该函数根据给定的type参数生成值r。现在,由于具有多个参数的函数(即返回函数的函数)可以翻转,因此(r -> (a -> b))和之间没有明显区别(a -> (r -> b))(flip可以简单地将一个改变为另一个),这使得该Monad实例(->) r完全等同于Applicative一个实例。
函数的 monad 实例中的值具有r -> a某种固定类型的类型r。(a -> (r -> b))给定的函数(>>=)允许您选择下一个要返回的函数(给定当前值的结果)(函数r -> a)。f rhas typea并且k (f r)has typer -> b是下一个要应用的函数。
因此,在您的代码中g(f(x)),有一个函数需要一个类型为 的参数r。的调用者bind可以根据前一个函数返回的值来选择这个函数,例如
var inc = x => x + 1;
var f = bind(inc)(function(i) {
if(i <= 5) { return x => x * 2; }
else { return x => x * 3; }
});
Run Code Online (Sandbox Code Playgroud)
该函数将作为输入给出x,并可以根据以下结果选择计算的下一阶段inc(x):
f(2) //4;
f(5) //15;
Run Code Online (Sandbox Code Playgroud)