我一直在尝试采用一些简单的功能,并将其转换为无点样式进行练习。 我从这样的事情开始:
zipSorted x y = (zip . sort) y $ sort x --zipSorted(x, y) = zip(sort(y), sort(x))
并最终将其转换为
zipSorted = flip (zip . sort) . sort
(我不确定这是否是最好的方法,但确实可行)
现在,我试图通过完全不依赖于zip
和sort
来进一步简化该表达式。换句话说,我正在寻找此功能:(如果我的词汇没有误,我认为它是一个组合器)
P(f, g, x, y) = f(g(y), g(x))
sort
出现两次但仅传入一次的事实告诉我,我应该使用应用函子运算符<*>
,但由于某种原因我不知道怎么做。
根据我的理解,(f <*> g)(x) = f(x, g(x))
,所以我尝试以这种形式重新编写第一个无点表达式:
flip (zip . sort) . sort
(.) (flip $ zip . sort) sort
(flip (.)) sort $ flip (zip . sort)
(flip (.)) sort $ flip $ (zip .) sort
似乎sort
应该是x
,(flip (.))
应该是f
,而flip . (zip .)
应该是g
。
p = (flip (.)) <*> (flip . (zip .))
p sort [2, 1, 3] [4, 1, 5]
如预期那样产生[(1, 1), (4, 2), (5, 3)]
,但是现在我迷失了如何拔出zip
。我已经尝试过
p = (flip (.)) <*> (flip . (.))
p zip sort [2, 1, 3] [4, 1, 5]
但这不起作用。有没有一种方法可以将该表达式转换为排除zip
的组合器?
答案 0 :(得分:5)
让我们从头开始:
zipSort x y = zip (sort y) (sort x)
以相反的顺序使用其参数有点奇怪,但是我们稍后可以通过flip
来解决。
在这里,我们有两个参数(此处为zip
)的“组合”函数的一般模式,该参数传递由另一个函数转换的两个值。如果我们具有相同的基本参数但具有不同的转换器,则该模式将为liftA2
模式:
c (f x) (g x)
==
liftA2 c f g x
但是这是相反的:我们在两侧都有相同的转换函数(在这里:sort
),但是参数(x
和y
)不同。那是on
:
c (f x) (f y)
==
(c `on` f) x y
在您的情况下,我们得到:
zip (sort y) (sort x)
(zip `on` sort) y x
flip (zip `on` sort) x y
所以
zipSort = flip (zip `on` sort) -- or: flip (on zip sort)
我们可以通过识别标准的两个参数到一个参数功能组合来进一步提取zip
和sort
:
(\x y -> f (g x y)) == (f .) . g
给予
zipSort = ((flip .) . on) zip sort
但是请注意,此函数的通用性要低于有针对性的版本。原始函数的类型为
(Ord a, Ord b) => [a] -> [b] -> [(b, a)]
但无点版本具有类型
(Ord a) => [a] -> [a] -> [(a, a)]
因为将两个sort
统一会迫使它们具有相同的类型。
答案 1 :(得分:1)
我只是要求lambdabot给出答案,而不是尝试手工解决:
<amalloy> @pl \zip sort x y -> (zip . sort) y $ sort x
<lambdabot> join . (((.) . flip) .) . (.)