理解类型错误:“预期签名 Int*Int->Int 但得到 Int*Int->Int”

发布于 2024-07-09 08:53:36 字数 898 浏览 16 评论 0 原文

Steve Yegge帖子 关于 服务器端 Javascript 开始讨论语言中类型系统的优点,这个评论 描述:

...来自 HM 风格系统的示例,您可以在其中获得以下内容:

期望签名 Int*Int->Int 但得到 Int*Int->Int 
  

:函数定义(或两个?)和会产生该错误的函数调用的示例? 看起来在大型程序中调试可能相当困难。

另外,我可能在 Miranda 中看到过类似的错误吗? (我已经15年没有使用过它了,所以我对它的记忆很模糊)

The comments on Steve Yegge's post about server-side Javascript started discussing the merits of type systems in languages and this comment describes:

... examples from H-M style systems where you can get things like:

expected signature Int*Int->Int but got Int*Int->Int

Can you give an example of a function definition (or two?) and a function call that would produce that error? That looks like it might be quite hard to debug in a large-ish program.

Also, might I have seen a similar error in Miranda? (I have not used it in 15 years and so my memory of it is vague)

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

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

发布评论

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

评论(3

烟酉 2024-07-16 08:53:36

我对 Yegge(和 Ola Bini)对静态类型的看法持保留态度。 如果您欣赏静态类型为您提供的功能,您将了解您选择的编程语言的类型系统如何工作。

IIRC,ML 对元组使用“*”语法。 <类型> * <类型> 是具有两个元素的元组类型。 因此,(1, 2) 将具有 int * int 类型。

Haskell 和 ML 都使用 -> 对于功能。 在机器学习中,int * int -> int 是一个函数的类型,它接受 int 和 int 的元组并将其映射到 int。

您可能会看到一个看起来有点像 Ola 在从另一种语言进行 ML 时引用的错误的原因之一是,如果您尝试使用括号和逗号将参数传递给一个函数,就像在 C 或 Pascal 中那样,有两个参数。

麻烦的是,函数式语言通常将多个参数的函数建模为返回函数的函数; 所有函数只接受一个参数。 如果函数应该接受两个参数,则它会接受一个参数并返回单个参数的函数,该函数返回最终结果,依此类推。 为了使所有这些清晰易读,函数应用只需通过合取即可完成(即将表达式放在一起)。

因此,ML 中的一个简单函数(注意:我使用 F# 作为我的 ML)可能看起来有点像:

let f x y = x + y;;

它具有类型:(

val f : int -> int -> int

一个函数接受一个整数并返回一个函数,该函数本身接受一个整数并返回一个整数。)

但是,如果您天真地使用元组调用它:

f(1, 2)

...您将收到错误,因为您将 int*int 传递给了需要 int 的对象。

我想这就是奥拉试图诽谤的“问题”。 不过,我认为问题并不像他想象的那么严重; 当然,C++ 模板的情况要糟糕得多。

I'd take Yegge's (and Ola Bini's) opinions on static typing with a grain of salt. If you appreciate what static typing gives you, you'll learn how the type system of the programming language you choose works.

IIRC, ML uses the '*' syntax for tuples. <type> * <type> is a tuple type with two elements. So, (1, 2) would have int * int type.

Both Haskell and ML use -> for functions. In ML, int * int -> int would be the type of a function that takes a tuple of int and int and maps it to an int.

One of the reasons you might see an error that looks vaguely like the one Ola quoted when coming to ML from a different language, is if you try and pass arguments using parentheses and commas, like one would in C or Pascal, to a function that takes two parameters.

The trouble is, functional languages generally model functions of more than one parameter as functions returning functions; all functions only take a single argument. If the function should take two arguments, it instead takes an argument and returns a function of a single argument, which returns the final result, and so on. To make all this legible, function application is done simply by conjunction (i.e. placing the expressions beside one another).

So, a simple function in ML (note: I'm using F# as my ML) might look a bit like:

let f x y = x + y;;

It has type:

val f : int -> int -> int

(A function taking an integer and returning a function which itself takes an integer and returns an integer.)

However, if you naively call it with a tuple:

f(1, 2)

... you'll get an error, because you passed an int*int to something expecting an int.

I expect that this is the "problem" Ola was trying to cast aspersions at. I don't think the problem is as bad as he thinks, though; certainly, it's far worse in C++ templates.

¢好甜 2024-07-16 08:53:36

这可能是指编写错误的编译器未能插入括号来消除错误消息的歧义。 具体来说,该函数需要一个 int 元组并返回一个 int,但您传递了一个 int 元组和一个来自 int 的函数int。 更具体地说(在机器学习中):

fun f g = g (1, 2);

f (42, fn x => x * 2)

这将产生类似于以下内容的类型错误:

预期类型 int * int -> int,得到类型int * (int -> int)

如果省略括号,则此错误可能会令人恼火地模棱两可。

值得注意的是,这个问题并不是辛德利-米尔纳特有的。 事实上,我想不出任何特定于 HM 的奇怪类型错误。 至少,没有一个像给出的例子那样。 我怀疑奥拉只是在胡言乱语。

It's possible that this was in reference to a badly-written compiler which failed to insert parentheses to disambiguate error messages. Specifically, the function expected a tuple of int and returned an int, but you passed a tuple of int and a function from int to int. More concretely (in ML):

fun f g = g (1, 2);

f (42, fn x => x * 2)

This will produce a type error similar to the following:

Expected type int * int -> int, got type int * (int -> int)

If the parentheses are omitted, this error can be annoyingly ambiguous.

It's worth noting that this problem is far from being specific to Hindley-Milner. In fact, I can't think of any weird type errors which are specific to H-M. At least, none like the example given. I suspect that Ola was just blowing smoke.

一指流沙 2024-07-16 08:53:36

由于许多函数式语言允许您以与重新绑定变量相同的方式重新绑定类型名称,因此实际上很容易出现这样的错误,特别是如果您为类型使用某种通用名称(例如,t< /code>) 在不同的模块中。 这是 OCaml 中的一个简单示例:

# let f x = x + 1;;
val f : int -> int = <fun>
# type int = Foo of string;;
type int = Foo of string
# f (Foo "hello");;
This expression has type int but is here used with type int

我在这里所做的是将类型标识符 int 重新绑定到与内置 int 类型不兼容的新类型。 只要多一点努力,我们就可以得到与上面或多或少相同的错误:

# let f g x y = g(x,y) + x + y;;
val f : (int * int -> int) -> int -> int -> int = <fun>
# type int = Foo of int;;
type int = Foo of int
# let h (Foo a, Foo b) = (Foo a);;
val h : int * int -> int = <fun>
# f h;;
This expression has type int * int -> int but is here used with type
  int * int -> int

Since many functional language allow you to rebind type names in the same way you can rebind variables, it's actually quite easy to end up with an error like this, especially if you use somewhat generic names for your types (e.g., t) in different modules. Here's a simple example in OCaml:

# let f x = x + 1;;
val f : int -> int = <fun>
# type int = Foo of string;;
type int = Foo of string
# f (Foo "hello");;
This expression has type int but is here used with type int

What I've done here is rebind the type identifier int to a new type that is incompatible with the built-in int type. With a little bit more effort, we can get more-or-less the same error as above:

# let f g x y = g(x,y) + x + y;;
val f : (int * int -> int) -> int -> int -> int = <fun>
# type int = Foo of int;;
type int = Foo of int
# let h (Foo a, Foo b) = (Foo a);;
val h : int * int -> int = <fun>
# f h;;
This expression has type int * int -> int but is here used with type
  int * int -> int
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文