许多功能可以简化为自由形式 - 但对所有这些功能都适用吗?
E.g。我不知道如何做到:
apply2 f x = f x x
答案 0 :(得分:10)
逻辑组合子(即S,K,I组合子)本质上是无点形式的函数,而lambda演算相当于组合逻辑,所以我认为这表明答案是肯定的。
apply2
函数的组合子是(如果我正确读取的话):
((S((S(KS))K))(K((S((SK)K))((SK)K))))
也称为“Lark”,来自Raymond Smullyan's Combinatory Birds页。
( edit-in:)结果 1 以上相当于\f x -> f (x x)
。根据下面“@gereeter”的评论,它确实被称为“Lark”,而问题中要求的函数\f x -> f x x
是上述书中的“鸣鸟”(又名the "W" combinator) ,W f x = S(S(K(S(KS)K))S)(KK)SI f x = S(S(KB)S)(KK)SI f x = CSI f x = SfIx = f x x
。
1 这里:
((S((S(KS))K))(K((S((SK)K))((SK)K)))) f x =
S( S(KS) K) (K( S( SK K) ( SK K))) f x = -- SKK == I
S (S(KS) K) (K( S I I )) f x = -- S(KS)K == B
S B (K( S I I )) f x =
Bf (K(SII)f) x = Bf (SII) x = f (SII x) = f (x x)
答案 1 :(得分:9)
如前所述,通过一组适当的固定组合器,任何lambda项都可以转换为仅使用那些组合器和函数应用程序的形式 - 没有lambda抽象(因此没有变量)。最着名的组合子集是S
和K
。 Se Combinatory Logic/Completeness of the S-K basis用于描述该过程。组合子定义为
K x y = x
S x y z = (x z) (y z)
有时会包含身份组合器I
,但它与I = S K K
一样多余。
有趣的是,即使使用单个组合器也可以做到这一点。 Iota语言使用
U f = (f S) K
可以证明
I = (UU)
K = (U(U(UU)))
S = (U(U(U(UU))))
因此我们可以将任何lambda术语转换为二叉树,除了它的形状之外没有其他信息(所有叶子都包含U
,并且节点代表函数应用程序。)
但是,如果我们想要有点效率并获得合理大小的转换,那么使用I
并引入另外两个冗余组合器会很有帮助,这些组合称为B
和{{1} }:
C
此处C f x y = f y x
B f g x = f (g x)
颠倒C
和f
的参数顺序是函数组合。
此添加会显着缩短输出的长度。
实际上Haskell已经包含了某种形式的所有标准组合器。特别是:
B
其中I = id
K = const
= pure :: a -> (r -> a)
S = (<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
B = (.)
= (<$>) :: (a -> b) -> (r -> a) -> (r -> b)
C = flip
= \k x -> k <*> pure x
,pure
和<*>
是<$>
仿函数类型的函数,我们这里专门为读者monad Applicative
。
所以在你的情况下,我们可以写
(->) r
在抽象消除过程中,我们尝试转换apply2 = (<*>) `flip` id
形式的术语(其中λx -> M :: r -> a
是r
的类型,而x
是a
的类型{1}})在没有M
的表单中。我们通过递归处理x
来执行此操作,然后我们将其M
类型的子项(可能包含b
)转换为类型x
的函数(不包含{ {1}}),然后我们将这些子项组合在一起。这就是读者monad的设计目的:将r -> b
类型的函数组合在一起。
有关详细信息,请参阅The Monad Reader, Issue 17:读者Monad和抽象消除。
为了构造数据结构,我们只使用它们的构造函数,这里没有问题。
为了解构它们,我们需要一些方法来摆脱模式匹配。这是编译器在编译功能程序时必须执行的操作。 The Implementation of Functional Programming Languages第5章:模式匹配的高效编译中描述了这样的过程。我们的想法是,对于每种数据类型,我们都有一个 case 函数,它描述了如何解构(折叠)数据类型。例如,对于列表x
,r -> something
列出foldr
,让我们说4元组它是
Either
等。因此,对于每种数据类型,我们添加其构造函数,解构 case 函数,并将模式编译到此函数中。
举个例子,让我们表达
either
这可以使用caseTuple4 :: (a -> b -> c -> d -> r) -> (a,b,c,d) -> r
caseTuple4 f (a,b,c,d) = f a b c d
表示:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x : xs) = f x : map f xs
然后使用我们之前讨论过的组合器进行转换:
foldr
您可以验证它确实符合我们的要求。
另请参阅System F data structures,其中介绍了如果我们启用higher rank types,数据结构如何直接编码为函数。
是,我们可以构造一组固定的组合器,然后将任何函数转换为只使用这些组合器和函数应用程序的无点样式。
答案 2 :(得分:5)
有很多函数看起来可能不是,但是可以用点自由风格表达,但是为了得到一个没有的函数,你可以快速定义一个适用于非常大的元组的函数。任何标准功能。
我认为这种事情不太可能是无表情的,不是因为复杂性,而是因为这个元组的元组功能不多:
weird (a,b,c,d,e,f,g,h,i,j) = (a<*>b,c++d,e^f+a,g ()-h 4+e,j <*> take f i)
你的例子:
apply2 :: (b -> b -> a) -> (b -> a)
apply2 = join
读者monad join
((->) b)
join :: Monad m => m (m a) -> m a
所以在这种情况下
join :: ((->) b) ((->) b a) -> ((->) b) a
join :: ((->) b) (b -> a) -> (b -> a)
join :: (b -> (b -> a)) -> (b -> a)
join :: (b -> b -> a) -> (b -> a)
比我们预期的更多功能有无点版本,但是一些无点表达式完全混乱。 有时最好是明确而不是简洁。