为什么(a - >(b - > c))为函数定义中的第一个参数,而是类型签名中的第二个参数?

发布于 2025-01-26 19:44:37 字数 599 浏览 5 评论 0原文

如果通过函数为函数应用程序的第一个参数是左求解的,例如:

drop 2 [1,2,3,4]

结果:[3,4]

等同于

(drop 2) [1,2,3,4]

相同的结果:[3,4]

在这里我的问题是,如果类型签名是正确的缔合性,则意味着,右侧的事物首先评估,在这种情况下,它将如下,因为第一个参数首先是由函数获取的:

drop :: [1,2,3,4] -> (2 -> [3,4])

它应该是' T如下,对吗?

drop :: Int -> ([a] -> [a])
drop :: 2 -> ([1,2,3,4] -> [3,4])

那么,为什么它首先在函数的类型签名中首先使用第二个参数,而不是第一个参数?

另外,如果在第一个参数之前评估了第二个参数,那么为什么以下用法无效?

(drop [1,2,3,4]) 2

If first parameter is taken by the function first as function application is left-associative, for example:

drop 2 [1,2,3,4]

result: [3,4]

is equivalent to

(drop 2) [1,2,3,4]

same result: [3,4]

Here my question is, if the type signature is right-associative, which means, things in right side evaluate first, in this case, it's gonna be as follows, as the first parameter is first taken by the function:

drop :: [1,2,3,4] -> (2 -> [3,4])

It shouldn't have been as follows, right?

drop :: Int -> ([a] -> [a])
drop :: 2 -> ([1,2,3,4] -> [3,4])

So, why does it take the second parameter first in type signature of the function instead of the first parameter?

In addition, if the second parameter is evaluated prior to first parameter, then why is the following usage invalid?

(drop [1,2,3,4]) 2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

忆梦 2025-02-02 19:44:37

drop :: [1,2,3,4] - &gt之类的东西是荒谬的。 (2 - > [3,4])2-> ([1,2,3,4] - > [3,4]) - 您正在混合那里的类型级别和值级符号。相反,您应该做的是查看本地类型的子表达:

drop                  2    [1,2,3,4]
└─┬┘                  ┊    └──┬────┘
┌─┴───────────────┐ ┌─┴─┐  ┌──┴──┐
│Int->[Int]->[Int]│ │Int│  │[Int]│
└─────────────────┘ └───┘  └─────┘

添加隐含的括号

(drop                   2)    [1,2,3,4]
 └┬─┘                   ┊     └──┬────┘
┌─┴─────────────────┐ ┌─┴─┐   ┌──┴──┐
│Int->([Int]->[Int])│ │Int│   │[Int]│
└───────────────────┘ └───┘   └─────┘

,现在subxpression drop 2表示您正在应用参数2作为该参数的第一个参数函数drop,即在其签名中为int。对于整个drop 2表达式,因此该参数已经消失:

(           drop           2   )  [1,2,3,4]
┊  ┌──────────┴────────┐ ┌─┴─┐ ┊  └──┬────┘
┊  │Int->([Int]->[Int])│ │Int│ ┊     ┊
┊  └───────────────────┘ └───┘ ┊     ┊
└────────────┬─────────────────┘  ┌──┴──┐
        ┌────┴───────┐            │[Int]│
        │[Int]->[Int]│            └─────┘
        └────────────┘

这类似于应用单个argument函数length :: [bool] - > int到单个参数[false,true] :: [bool]获得结果length [false,true]◦(2 :: int) 。对于drop,结果具有类型([int] - > [int])而不是int is在这个阶段无关。

然后,在外部级别,您要应用类型[int] - > [int]的函数。然后,整个过程只有结果类型[int]

( (           drop           2   )  [1,2,3,4] )
┊ ┊  ┌──────────┴────────┐ ┌─┴─┐ ┊  └──┬────┘ ┊
┊ ┊  │Int->([Int]->[Int])│ │Int│ ┊     ┊      ┊
┊ ┊  └───────────────────┘ └───┘ ┊     ┊      ┊
┊ └────────────┬─────────────────┘     ┊      ┊
┊         ┌────┴───────┐            ┌──┴──┐   ┊
┊         │[Int]->[Int]│            │[Int]│   ┊
┊         └────────────┘            └─────┘   ┊
└────────────────────────┬────────────────────┘
                      ┌──┴──┐
                      │[Int]│
                      └─────┘

It's nonsensical to write things like drop :: [1,2,3,4] -> (2 -> [3,4]) or 2 -> ([1,2,3,4] -> [3,4]) – you're mixing type-level and value-level notations there. What you should instead do is look at local types of subexpressions:

drop                  2    [1,2,3,4]
└─┬┘                  ┊    └──┬────┘
┌─┴───────────────┐ ┌─┴─┐  ┌──┴──┐
│Int->[Int]->[Int]│ │Int│  │[Int]│
└─────────────────┘ └───┘  └─────┘

Add the implied parentheses

(drop                   2)    [1,2,3,4]
 └┬─┘                   ┊     └──┬────┘
┌─┴─────────────────┐ ┌─┴─┐   ┌──┴──┐
│Int->([Int]->[Int])│ │Int│   │[Int]│
└───────────────────┘ └───┘   └─────┘

Now the subexpression drop 2 means you're applying the argument 2 as the first argument of the function drop, i.e. as the Int in its signature. For the whole drop 2 expression, this argument has therefore vanished:

(           drop           2   )  [1,2,3,4]
┊  ┌──────────┴────────┐ ┌─┴─┐ ┊  └──┬────┘
┊  │Int->([Int]->[Int])│ │Int│ ┊     ┊
┊  └───────────────────┘ └───┘ ┊     ┊
└────────────┬─────────────────┘  ┌──┴──┐
        ┌────┴───────┐            │[Int]│
        │[Int]->[Int]│            └─────┘
        └────────────┘

This is analogous to applying the single-argument function length :: [Bool] -> Int to the single argument [False,True] :: [Bool] to get the result length [False,True] ≡ (2::Int). The fact that for drop the result has type ([Int]->[Int]) instead of something “atomic” like Int is irrelevant at this stage.

Then on the outer level, you're applying the function of type [Int]->[Int] to the argument of type [Int], which is perfectly sensible. The whole thing then has simply result type [Int].

( (           drop           2   )  [1,2,3,4] )
┊ ┊  ┌──────────┴────────┐ ┌─┴─┐ ┊  └──┬────┘ ┊
┊ ┊  │Int->([Int]->[Int])│ │Int│ ┊     ┊      ┊
┊ ┊  └───────────────────┘ └───┘ ┊     ┊      ┊
┊ └────────────┬─────────────────┘     ┊      ┊
┊         ┌────┴───────┐            ┌──┴──┐   ┊
┊         │[Int]->[Int]│            │[Int]│   ┊
┊         └────────────┘            └─────┘   ┊
└────────────────────────┬────────────────────┘
                      ┌──┴──┐
                      │[Int]│
                      └─────┘
蓝咒 2025-02-02 19:44:37

我认为您误解了正确的联想意义。确实意味着:

drop :: Int -> [a] -> [a]

相当于:

drop :: Int -> ([a] -> [a])

因此,这意味着drop是一个采用类型int的参数,然后返回a 函数类型[a] - > [a]

但是功能应用程序本身是左求解。实际上:

drop 2 [1,2,3,4]

缩短了:

(drop 2) [1,2,3,4]

此处drop 2将返回类型[a] - &gt的函数; [A]将删除列表的前两个项目。然后,我们将[1,2,3,4]应用于该功能,从而获得[3,4]

I think you misunderstand what right associative means. It indeed means that:

drop :: Int -> [a] -> [a]

is equivalent to:

drop :: Int -> ([a] -> [a])

This thus means that drop is a function that takes a parameter of type Int, and then returns a function of type [a] -> [a].

But function application itself is left-associative. Indeed:

drop 2 [1,2,3,4]

is short for:

(drop 2) [1,2,3,4]

Here drop 2 will thus return a function of type [a] -> [a] that will drop the first two items of the list. We then apply [1,2,3,4] to that function, and thus obtain [3,4].

享受孤独 2025-02-02 19:44:37

我想我现在已经理解了这个难题:

在功能应用程序中,该函数将始终从左到右接一个,因为它具有左右相关性。它的目的是用参数替换结合变量。

现在,当涉及该函数的键入签名时,它确实是正确的缔合性,但这并不意味着该函数将通过进行最后一个参数,然后是第二个参数来应用。

功能应用程序:

((((((a)b)c)d)e

表示以下表达式具有以下类型:

a :: b -> (c -> (d -> e))
a    b ::  c -> (d -> e)
(a   b)    c ::  d -> e
((a  b)    c)    d :: e

可以读取为:函数采用第一个参数(b)并返回第二个函数(c - >(d - > e)),采用第二个参数(c)并返回第三个函数(d - > e),该功能(d - > e)获取第三参数(d)并返回最终结果(e )。

正如@Daniel Wagner指出的那样:

关联顺序并不意味着函数的评估顺序。

在这种情况下,类型签名中的右求解等效如下,一对括号(c - > d)是指通过(b)从左侧:

a :: b -> (c -> d)

由于Haskell中的功能基于Lambda cyculus,因此我将在这里使用lambdas,因为我熟悉它们,作为示例:

原始版本:

  (λab.a+b) (1,2)
= (a+b)[a:=1,b:=2]
= 1+2
= 3

但是,由于Lambda cyculus中的抽象仅在每个步骤中仅接受一个输入,因此可以被重写为:

咖喱版本:

  (λa.(λb.a+b)) 1 2
= ((λb.a+b)[a:=1]) 2
= (λb.1+b) 2
= (1+b)[b:=2]
= 1+2
= 3

注意:本文的术语或逻辑可能不正确。如果您能够并希望,可以编辑我的帖子以纠正它。 :)

I guess I've understood the puzzle now:

In a function application, the function will always take parameters from left to right, one by one, as it's left-associative. Its purpose is to substitute the bound variables with parameters.

Now, when it comes to type signature of the function, it's right-associative indeed, but it doesn't mean the function will be applicated by taking the last argument, then the second last argument, and so forth.

A function application:

((((a) b) c) d) e

means that the following expressions have the following types:

a :: b -> (c -> (d -> e))
a    b ::  c -> (d -> e)
(a   b)    c ::  d -> e
((a  b)    c)    d :: e

this can be read as: The function takes first parameter (b) and returns the second function (c -> (d -> e)), that takes second parameter (c) and returns the third function (d -> e) that takes third parameter (d) and returns the final result (e).

As @Daniel Wagner pointed out:

The associativity order doesn't mean the evaluation order of the function.

In this case, the right-associative in type-signature is equivalent as follows, a pair of parentheses (c -> d) means a returned function by the function that takes the (b) from left side:

a :: b -> (c -> d)

As functions in Haskell are based on Lambda calculus, here I'll use lambdas since I'm familiar with them, as examples:

Original version:

  (λab.a+b) (1,2)
= (a+b)[a:=1,b:=2]
= 1+2
= 3

But since an abstraction in Lambda calculus that only takes one input in each step, it can be rewritten into:

Curried version:

  (λa.(λb.a+b)) 1 2
= ((λb.a+b)[a:=1]) 2
= (λb.1+b) 2
= (1+b)[b:=2]
= 1+2
= 3

Note: Terms or logic of this post may be incorrect. If you are able to and wish, you could edit my post to correct it. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文