首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多元函数的无点复合

多元函数的无点复合
EN

Stack Overflow用户
提问于 2021-09-28 14:10:34
回答 3查看 58关注 0票数 1

比方说,我们想要引入不同参数的函数之和的概念(让我们称之为<+>),它的行为类似于(f1 <+> f2)(x1, x2) == f1(x1) + f2(x2)

虽然这可以很容易地手动写出,但在笛卡尔函数乘积概念的帮助下,使用无点样式是有意义的。后者的定义如下,对我来说似乎很好,也很普遍:

代码语言:javascript
复制
x :: (x1 -> y1) -> (x2 -> y2) -> (x1 -> x2 -> (y1, y2))
x f1 f2 = \x1 x2 -> (f1(x1), f2(x2))

然后我们可以这样写:

代码语言:javascript
复制
(<+>):: Num a => (a -> a) -> (a -> a) -> (a -> a -> a)
(<+>) = (uncurry (+)) . x

上面的代码在我看来也没问题,但GHC却不这么认为:

代码语言:javascript
复制
 * 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

感觉编译器不能推断第二个函数的类型,但为什么呢?我该怎么做,这有可能做到吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-09-28 14:21:37

如果你提供两个参数,你就会发现哪里出了问题。

代码语言:javascript
复制
(<+>) = uncurry (+) . x
(<+>) a = (uncurry (+) . x) a
        = uncurry (+) (x a)
(<+>) a b = uncurry (+) (x a) b

哇哦!该b作为第三个参数传递给uncurry,而不是像您希望的那样作为第二个参数传递给x。第三个和第四个参数也应该传递给x而不是uncurry,如下所示:

代码语言:javascript
复制
(<+>) a b c d = uncurry (+) (x a b c d)

下面是对四个参数的作文进行无指针简化的正确方法。

代码语言:javascript
复制
\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。将这一新事实应用到您的案例中:

代码语言:javascript
复制
\a b c d -> uncurry (+) (x a b c d)
    = (((uncurry (+) .) .) .) . x
票数 3
EN

Stack Overflow用户

发布于 2021-09-28 14:21:02

.运算符仅用于组合具有单个参数的函数,但函数x有四个参数,因此您必须使用.四次:

代码语言:javascript
复制
(<+>) = (((uncurry (+) .) .) .) . x

请记住,在实际代码中,这并不是好的风格。

票数 2
EN

Stack Overflow用户

发布于 2021-09-28 16:41:34

定义

代码语言:javascript
复制
compose2 :: (b -> c -> t) -> (a -> b) -> (d -> c) -> a -> d -> t
compose2 p f g x y = p (f x) (g y)

现在,compose2 (+)就是您的<+>

代码语言:javascript
复制
> :t compose2 (+)
compose2 (+) :: Num t => (a -> t) -> (d -> t) -> a -> d -> t

正如您所看到的,它的类型比您想象的要通用一些。

compose2 already exists.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69363327

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档