绑定来自哪里?

时间:2014-02-04 15:12:36

标签: haskell types monads pointfree

使用lambdabot的pl插件,

let iterate f x = x : iterate f (f x) in iterate

转换为

fix ((ap (:) .) . ((.) =<<))

(=<<)在这里意味着什么?我认为它只与monad一起使用。

3 个答案:

答案 0 :(得分:13)

让我们从定义

开始
iterate f x = x : iterate f (f x) 

我们希望将其转换为无点形式。我们可以一步一步地进行,但要理解它,首先必须知道

函数形成monad

或者,更具体地说,类型构造函数(->) r,您应该将其视为“r类型的函数”或(r ->),是一个monad。查看它的最佳方法是定义返回和绑定操作。 monad m的一般形式是

return :: a -> m a
(>>=)  :: m a -> (a -> m b) -> m b

专注于功能,你有

return :: a -> r -> a
(>>=)  :: (r -> a) -> (a -> r -> b) -> r -> b

你可以说服自己唯一明智的定义是

return x = \r -> x -- equivalent to 'const x'
f >>=  g = \r -> g (f r) r

这完全等同于Reader monad,也称为环境monad。我们的想法是你有一个额外的类型为r的参数(有时称为环境),它通过计算进行线程化 - 每个函数都隐式接收r作为附加参数。

现在我们知道了开始使我们的功能毫无意义所需的一切。

使用fix

删除递归

首先要删除iterate的递归引用。我们可以使用具有定义

fix来完成此操作
fix :: (t -> t) -> t
fix f = f (fix f)

您可以将fix视为规范递归函数,因为它可用于定义其他递归函数。标准惯用法是使用名为g的附加参数定义非递归函数func,该参数表示您要定义的函数。将fix应用于g会计算g的固定点,这是您想要的递归函数。

iterate = fix g where g func f x = x : func f (f x)

我们可以将其转换为lambda形式

iterate = fix (\func f x -> x : func f (f x))
        = fix (\func f x -> (:) x (func f (f x)))

其中第二行刚刚删除了中缀:,并将其替换为前缀(:)。既然没有自我引用,我们就可以继续了。

使用ap

删除部分点

我们可以使用ap来提取对x的引用。 ap的类型是

ap :: (Monad m) => m (a -> b) -> m a -> m b

它在某些monadic上下文中使用一个函数,并将其应用于另一个monadic上下文中的值。请注意,这已经在使用函数(->) r形成monad的事实!专业化m(->) r你得到

ap :: (r -> a -> b) -> (r -> a) -> (r -> b)

使类型运作的唯一方法是ap(专门用于函数)具有以下定义

ap f g = \r -> f r (g r)

这样你就可以使用第二个函数g来构建第一个函数f的第二个参数。请注意,ap的此定义与SKI combinator calculus中的组合符 S 完全相同。

对于我们来说,这允许我们将参数x提供给第一个函数(:),并使用另一个函数\y -> func f (f y)来构建第二个参数,即列表的尾部。作为加分,我们可以使用eta减少删除对x的所有引用。

iterate = fix (\func f x -> ap (:) (\y -> func f (f y)) x)
        = fix (\func f   -> ap (:) (\y -> func f (f y))  )

我们现在可以删除对y的引用,方法是识别func f (f y)只是func fy的组合。

iterate = fix (\func f   -> ap (:) (      func f . f)    )

使用(>>=)

线程化参数

现在我们使用表达式(func f . f)(.) (func f) f如果我们使用前缀表示法。我们想将此描述为应用于f的一些函数,但这要求我们将f线程化到两个位置的表达式中。

幸运的是,这正是(->) r的monad实例所做的!如果你记得函数monad与读者monad完全等价,那么这就完全有意义了,读者monad的工作是将一个额外的参数线程化到每个函数调用中。

专门用于函数的bind的定义是

f >>= g = \r -> g (f r) r

参数r首先穿过绑定的左侧参数,其结果由右侧参数用于创建可以使用另一个r的函数。助记符是参数r首先穿过左参数,然后穿过右参数。

在我们的例子中,我们写(.) (func f) f = (func >>= (.)) f来获得(使用eta减少)

iterate = fix (\func f   -> ap (:)  ((func >>= (.)) f))
        = fix (\func     -> ap (:) . (func >>= (.))   )

链接作品

最后,我们使用另一个技巧,重复组合,来提取参数func。这个想法是,如果你有一个表达

f . g a

然后你可以用

替换它
f . g a = (.) f (g a)
        = (((.) f) . g) a
        = ((f .) . g) a

所以你把它表达为一个应用于参数的函数(准备eta减少!)。在我们的情况下,这意味着进行替换

iterate = fix (\func     -> (ap (:) .) . (>>= (.)) func)
        = fix (            ((ap (:) .) . (>>= (.))     )

最后,删除内部括号并使用(=<<)而不是(>>=)来描述该部分

iterate = fix ((ap (:) .) . ((.) =<<))

这与lambdabot提出的表达相同。

答案 1 :(得分:4)

是的,这里的monad是((->) a)iterate f x显然会构建一个列表,因此iterate的类型为(a->a)->a->[a],所以给定(a->a),它产生(a->[a])

您可以看到ap被赋予了(:) :: a->[a]->[a]函数,该函数必须为m (a->b),因此m此处为(->) a

(ap (:) .) . ((.) =<<) =
\f -> (ap (:) .) . ((.) =<<) $ f =
\f -> ap (:) . ((.) =<< f) = -- at this stage we can see =<< is of (->) a monad,
                       -- whose bind is the S-combinator: s f g x = f (g x) x
\f -> ap (:) . (f >>= (.)) =
\f g -> ap (:) (f g . g) = -- ok, ap is also the S-combinator with some
                           -- arguments swapped around
-- you see, for monad ((->) r), ap needs function of type (r->(a->b)) = (r->a->b)
-- whereas >>= needs (a->(r->b)) = (a->r->b) - the same function flipped
\f g -> (flip (:)) =<< (f g . g) =
\f g -> \x -> x : (f g $ g x)

这是两个参数a->(b->c)的函数,因此当它传递给fix :: (a->a)->a时,它必须是a=(b->c)fix (ap...) :: b->c。反过来,因为这一切都与iterate相同,所以必须是b->c = (x->x)->(x->[x]),所以b=(x->x)c=(x->[x])

事实上:

Prelude Control.Monad> :t ((ap (:) .) . ((.) =<<))
((ap (:) .) . ((.) =<<))
  :: (Monad ((->) (a -> b)), Monad ((->) a)) =>
     ((a -> b) -> b -> [a]) -> (a -> b) -> a -> [a]

将在传递给b=a之后绑定fix

现在,fix提供了上面的第一个参数,如下所示:

fix h = let x = h x in x
hence, iterate = fix h = let iterate = h iterate in iterate 
-- supply iterate as the first
-- argument to the function passed to fix

所以我们有:

iterate =
fix (\f g -> \x -> x : (f g $ g x)) =
\g x -> x : (iterate g $ g x)

答案 2 :(得分:2)

这是一个简短,直截了当的combinators式派生词:

iterate f x 
   = x : iterate f (f x) 
   = (:) x ((iterate f . f) x)
   = ap (:) (iterate f . f) x            -- ap g f x = g x (f x)       (1)
   = ap (:) ((.) (iterate f) f) x
   = ap (:) ( ((.) =<< iterate) f) x     -- (g =<< f) x = g (f x) x    (2)
   = ap (:) ( ((.) =<<) iterate f) x
   = ((ap (:) .) . ((.) =<<)) iterate f x 
       -- ((f .) . g) x y = (f .) (g x) y = (f . g x) y = f (g x y)    (3)

所以,通过eta-contraction,

iterate = ((ap (:) .) . ((.) =<<)) iterate
        = fix ((ap (:) .) . ((.) =<<))    -- fix f = x where x = f x   (4)

QED。 (1)和(2)来自你所要求的,作为monad的功能,已在Chris的回答中解释过:

  ap :: (Monad m) => m (a->b) ->   m a  ->  m b              m ~ (r ->)
  that's            (r->a->b) -> (r->a) -> r->b 
  so            ap     g           f       x   = g x (f x)

  (=<<) :: (Monad m) => (a-> m b) ->   m a  ->  m b          m ~ (r ->)
  that's                (a->r->b) -> (r->a) -> r->b
  so            (=<<)      g           f       x   = g (f x) x
例如,讨论了(3)最后herehere