2008-11-27 31 views
8

Các ý kiến ​​về Steve Yegge 's post về server-side Javascript bắt đầu thảo luận về giá trị của hệ thống loại bằng các ngôn ngữ và điều này comment mô tả:Hiểu lỗi kiểu: "mong đợi chữ ký Int * Int-> Int nhưng có Int * Int-> Int"

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

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

Bạn có thể đưa ra ví dụ về định nghĩa hàm (hoặc hai?) Và cuộc gọi hàm sẽ tạo ra lỗi đó? Dường như nó có thể khá khó khăn để gỡ lỗi trong một chương trình lớn-ish.

Ngoài ra, tôi có thể gặp lỗi tương tự trong số Miranda không? (Tôi đã không sử dụng nó trong 15 năm và vì vậy bộ nhớ của tôi về nó là mơ hồ)

Trả lời

8

Tôi sẽ nhận ý kiến ​​của Yegge (và Ola Bini) về cách gõ tĩnh với một hạt muối. Nếu bạn đánh giá cao tính năng nhập tĩnh sẽ cung cấp cho bạn, bạn sẽ tìm hiểu cách hệ thống loại ngôn ngữ lập trình bạn chọn hoạt động.

IIRC, ML sử dụng cú pháp '*' cho bộ dữ liệu. < type> * < type> là một loại bộ tuple có hai phần tử. Vì vậy, (1, 2) sẽ có int * int loại.

Cả sử dụng Haskell và ML -> cho chức năng. Trong ML, int * int -> int sẽ là kiểu hàm nhận một bộ int và int và ánh xạ nó thành một int.

Một trong những lý do khiến bạn có thể thấy lỗi có vẻ mơ hồ giống như ngôn ngữ được sử dụng trong ngôn ngữ khác. với một hàm lấy hai tham số.

Vấn đề là, các ngôn ngữ chức năng thường mô hình hóa các hàm của nhiều tham số như hàm trả về hàm; tất cả các hàm chỉ nhận một đối số duy nhất. Nếu hàm này lấy hai đối số, nó thay thế một đối số và trả về một hàm của một đối số duy nhất, trả về kết quả cuối cùng, v.v. Để làm cho tất cả điều này dễ đọc, ứng dụng chức năng được thực hiện đơn giản bằng cách kết hợp (tức là đặt các biểu thức bên cạnh nhau).

Vì vậy, một chức năng đơn giản trong ML (lưu ý: Tôi đang sử dụng F # như ML của tôi) có thể trông hơi giống:

let f x y = x + y;; 

Nó có kiểu:

val f : int -> int -> int 

(Một chức năng lấy một số nguyên và trả về một hàm mà chính nó lấy một số nguyên và trả về một số nguyên.)

Tuy nhiên, nếu bạn ngây thơ gọi nó bằng một bộ:

f(1, 2) 

... bạn sẽ gặp lỗi, vì bạn đã chuyển int * int vào nội dung mong đợi một int.

Tôi hy vọng rằng đây là "vấn đề" Ola đã cố gắng bỏ nguyện vọng tại. Tôi không nghĩ rằng vấn đề là xấu như ông nghĩ, mặc dù; chắc chắn, nó còn tồi tệ hơn trong các mẫu C++.

+1

Tôi sẽ xây dựng mạnh mẽ hơn nhiều (muối shaker!) ... câu trả lời hay. –

+0

cảm ơn - đó có lẽ là chính xác những gì tôi đã làm tất cả những năm trước đây như ngôn ngữ đầu tiên của tôi đã thực sự Pascal và C! – devstopfix

+2

Vì vậy, báo giá trong câu hỏi là "chữ ký dự kiến ​​Int * Int-> Int nhưng có Int-> Int-> Int"? Bởi vì tôi không thấy các loại giống hệt nhau là một lỗi. –

4

Có thể điều này là do tham chiếu đến trình biên dịch được viết sai, không thể chèn dấu ngoặc đơn để phân biệt các thông báo lỗi. Cụ thể, chức năng mong đợi một bộ gồm int và trả về một số int, nhưng bạn đã chuyển một bộ số int và một hàm từ int đến int.Cụ thể hơn (trong ML):

fun f g = g (1, 2); 

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

này sẽ tạo ra một lỗi kiểu tương tự như sau:

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

Nếu ngoặc được bỏ qua, lỗi này có thể khó chịu mơ hồ.

Điều đáng lưu ý là vấn đề này còn xa lạ với Hindley-Milner. Trong thực tế, tôi không thể nghĩ ra bất kỳ loại lỗi lạ nào dành riêng cho H-M. Ít nhất, không giống như ví dụ được đưa ra. Tôi nghi ngờ rằng Ola chỉ đang thổi khói.

3

Vì nhiều ngôn ngữ chức năng cho phép bạn khôi phục tên kiểu giống như cách bạn có thể rebind biến, thực sự rất dễ xảy ra lỗi như thế này, đặc biệt nếu bạn sử dụng tên hơi chung cho loại của mình (ví dụ: t) trong các mô-đun khác nhau. Dưới đây là một ví dụ đơn giản trong 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 

Những gì tôi đã làm ở đây là rebind loại định danh int cho một loại mới đó là không phù hợp với built-in int loại. Với nỗ lực nhiều hơn một chút, chúng tôi có thể nhận được nhiều hơn hoặc ít hơn cùng một lỗi như trên:

# 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 
Các vấn đề liên quan