比方说,我们想要引入不同参数的函数之和的概念(让我们称之为<+>),它的行为类似于(f1 <+> f2)(x1, x2) == f1(x1) + f2(x2)。
虽然这可以很容易地手动写出,但在笛卡尔函数乘积概念的帮助下,使用无点样式是有意义的。后者的定义如下,对我来说似乎很好,也很普遍:
x :: (x1 -> y1) -> (x2 -> y2) -> (x1 -> x2 -> (y1, y2))
x f1 f2 = \x1 x2 -> (f1(x1), f2(x2))然后我们可以这样写:
(<+>):: Num a => (a -> a) -> (a -> a) -> (a -> a -> a)
(<+>) = (uncurry (+)) . x上面的代码在我看来也没问题,但GHC却不这么认为:
* Couldn't match type: (x20 -> y20) -> a -> x20 -> (a, y20)
with: ((a -> a) -> a -> a -> a, (a -> a) -> a -> a -> a)
Expected: (a -> a)
-> ((a -> a) -> a -> a -> a, (a -> a) -> a -> a -> a)
Actual: (a -> a) -> (x20 -> y20) -> a -> x20 -> (a, y20)
* Probable cause: `x' is applied to too few arguments
In the second argument of `(.)', namely `x'
In the expression: (uncurry (+)) . x
In an equation for `<+>': (<+>) = (uncurry (+)) . x
* Relevant bindings include
(<+>) :: (a -> a) -> (a -> a) -> a -> a -> a感觉编译器不能推断第二个函数的类型,但为什么呢?我该怎么做,这有可能做到吗?
发布于 2021-09-28 14:21:37
如果你提供两个参数,你就会发现哪里出了问题。
(<+>) = uncurry (+) . x
(<+>) a = (uncurry (+) . x) a
= uncurry (+) (x a)
(<+>) a b = uncurry (+) (x a) b哇哦!该b作为第三个参数传递给uncurry,而不是像您希望的那样作为第二个参数传递给x。第三个和第四个参数也应该传递给x而不是uncurry,如下所示:
(<+>) a b c d = uncurry (+) (x a b c d)下面是对四个参数的作文进行无指针简化的正确方法。
\a b c d -> f (g a b c d)
= \a b c d -> (f . g a b c) d
= \a b c -> f . g a b c
= \a b c -> ((.) f . g a b) c
= \a b -> (.) f . g a b
= \a b -> ((.) ((.) f) . g a) b
= \a -> (.) ((.) f) . g a
= \a -> ((.) ((.) ((.) f)) . g) a
= (.) ((.) ((.) f)) . g然后,大多数人使用段语法将其写为(((f .) .) .) . g。将这一新事实应用到您的案例中:
\a b c d -> uncurry (+) (x a b c d)
= (((uncurry (+) .) .) .) . x发布于 2021-09-28 14:21:02
.运算符仅用于组合具有单个参数的函数,但函数x有四个参数,因此您必须使用.四次:
(<+>) = (((uncurry (+) .) .) .) . x请记住,在实际代码中,这并不是好的风格。
发布于 2021-09-28 16:41:34
定义
compose2 :: (b -> c -> t) -> (a -> b) -> (d -> c) -> a -> d -> t
compose2 p f g x y = p (f x) (g y)现在,compose2 (+)就是您的<+>
> :t compose2 (+)
compose2 (+) :: Num t => (a -> t) -> (d -> t) -> a -> d -> t正如您所看到的,它的类型比您想象的要通用一些。
compose2 already exists.
https://stackoverflow.com/questions/69363327
复制相似问题