使用lambdabot的pl插件,
let iterate f x = x : iterate f (f x) in iterate
转换为
fix ((ap (:) .) . ((.) =<<))
(=<<)
在这里意味着什么?我认为它只与monad一起使用。
答案 0 :(得分:13)
让我们从定义
开始iterate f x = x : iterate f (f x)
我们希望将其转换为无点形式。我们可以一步一步地进行,但要理解它,首先必须知道
或者,更具体地说,类型构造函数(->) 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 f
和y
的组合。
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)最后here和here。