jam*_*her 39 haskell pointfree function-composition
普通的功能组成属于这种类型
(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)
我认为这应该概括为类型:
(.) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
Run Code Online (Sandbox Code Playgroud)
一个具体的例子:计算差分平方.我们可以写diffsq a b = (a - b) ^ 2,但感觉我应该能够编写(-)和(^2)编写类似的东西diffsq = (^2) . (-).
当然,我不能.我可以做的一件事是使用一个元组而不是两个参数(-),通过转换它uncurry,但这不一样.
有可能做我想要的吗?如果没有,我误解的是什么让我认为它应该是可能的?
注意:这里已经有效地提出过这个问题,但是没有给出答案(我怀疑必须存在).
Edw*_*ETT 46
我首选的实现是
fmap . fmap :: (Functor f, Functor f1) => (a -> b) -> f (f1 a) -> f (f1 b)
Run Code Online (Sandbox Code Playgroud)
如果只是因为它很容易记住.
将f和f1实例化为和时(->) c,(->) d分别得到类型
(a -> b) -> (c -> d -> a) -> c -> d -> b
Run Code Online (Sandbox Code Playgroud)
这是哪种类型
(.) . (.) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
Run Code Online (Sandbox Code Playgroud)
但它更容易摆脱fmap . fmap版本,它推广到其他仿函数.
有时这是写的fmap fmap fmap,但写的,因为fmap . fmap它可以更容易扩展,以允许更多的参数.
fmap . fmap . fmap
:: (Functor f, Functor g, Functor h) => (a -> b) -> f (g (h a)) -> f (g (h b))
fmap . fmap . fmap . fmap
:: (Functor f, Functor g, Functor h, Functor i) => (a -> b) -> f (g (h (i a))) -> f (g (h (i b))
Run Code Online (Sandbox Code Playgroud)
等等
一般fmap用自己组成n次可以用到fmap n级深!
由于函数形成了一个Functor,这为n个参数提供了管道.
有关更多信息,请参阅Conal Elliott的语义编辑器组合器.
ham*_*mar 30
误解是你将类型a -> b -> c的函数看作具有返回类型的两个参数的函数c,而实际上它是一个带有返回类型的参数的函数,b -> c因为函数类型与右边相关(即它与...相同)a -> (b -> c).使得无法使用标准函数组合运算符.
要了解原因,请尝试将(.)类型为(y -> z) -> (x -> y) -> (x -> z)operator的运算符应用于两个函数,g :: c -> d并且f :: a -> (b -> c).这意味着我们必须y与之相c结合b -> c.这没有多大意义.怎样才能y既c和函数返回c?那将是一个无限类型.所以这不起作用.
仅仅因为我们不能使用标准组合运算符,它不会阻止我们定义自己的运算符.
compose2 :: (c -> d) -> (a -> b -> c) -> a -> b -> d
compose2 g f x y = g (f x y)
diffsq = (^2) `compose2` (-)
Run Code Online (Sandbox Code Playgroud)
通常情况下,最好避免在这种情况下使用无点样式
diffsq a b = (a-b)^2
Run Code Online (Sandbox Code Playgroud)
mig*_*yte 19
我不知道执行此操作的标准库函数,但实现它的无点模式是组合函数:
(.) . (.) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
Run Code Online (Sandbox Code Playgroud)
我打算在评论中写这个,但它有点长,它来自强大的和哈马尔.
我建议我们围绕运营商进行标准化,例如.*for compose2和.**for compose3.使用mightybyte的定义:
(.*) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
(.*) = (.) . (.)
(.**) :: (d -> e) -> (a -> b -> c -> d) -> (a -> b -> c -> e)
(.**) = (.) . (.*)
diffsq :: (Num a) => a -> a -> a
diffsq = (^2) .* (-)
modminus :: (Integral a) => a -> a -> a -> a
modminus n = (`mod` n) .* (-)
diffsqmod :: (Integral a) => a -> a -> a -> a
diffsqmod = (^2) .** modminus
Run Code Online (Sandbox Code Playgroud)
是的,modminus并且diffsqmod是非常随机且毫无价值的功能,但它们很快并且显示了重点.注意通过在另一个组合函数中组合来定义下一级别是多么容易(类似于fmapEdward提到的链接).
(.***) = (.) . (.**)
Run Code Online (Sandbox Code Playgroud)
实际上,compose12从上到下,编写函数名称而不是运算符的时间更短
f .*********** g
f `compose12` g
Run Code Online (Sandbox Code Playgroud)
虽然计算星号很累,但我们可能想要在4或5时停止惯例.
[编辑]另一个随机的想法,我们可以使用.:compose2,.:.对于compose3,.::对于compose4,.::.对于compose5,.:::对于compose6,让点数(在初始一个之后)可视地标记要向下钻取的参数数量.我想我更喜欢明星了.
diffsq = ((^ 2) .) . (-)
Run Code Online (Sandbox Code Playgroud)
您可以f . g将其视为对 应用一个参数g,然后将结果传递给f。(f .) . g将两个参数应用于g,然后将结果传递给f。((f .) .) . g对 应用三个参数g,依此类推。
\f g -> (f .) . g :: (c -> d) -> (a -> b -> c) -> a -> b -> d
Run Code Online (Sandbox Code Playgroud)
如果我们用一些函数f :: c -> d(f左侧的部分应用程序)对组合运算符进行左截,我们得到:
(f .) :: (b -> c) -> b -> d
Run Code Online (Sandbox Code Playgroud)
所以我们有这个新函数,它期望一个函数来自b -> c,但我们的g是a -> b -> c,或者等效地,a -> (b -> c)。我们需要先申请一个,a然后才能得到我们需要的东西。好吧,让我们再次迭代:
((f .) .) :: (a -> b -> c) -> a -> b -> d
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9075 次 |
| 最近记录: |