Vâng, mặc dù không phải trong Haskell. Nhưng bậc cao lambda calculus đa hình (hay còn gọi là hệ thống F-omega) là tổng quát hơn:
bi : forall m n a b. (forall a. m a -> n a) -> m a -> m b -> (n a, n b)
bi {m} {n} {a} {b} f x y = (f {a} x, f {b} y)
x1 : (Integer, Char)
x1 = bi {\a. List a} {\a. a} {Integer} {Char} head [2,3] "45"
x2 : (Integer, Char)
x2 = bi {\a . exists b. (a, b)} {\a. a} {Integer} {Char} (\{a}. \p. unpack<b,x>=p in fst {a} {b} x) (pack<Char, (2,'3')>) (pack<Integer, ('4',5)>)
x3 : (Integer, Double)
x3 = bi {\a. a} {\a. a} {Integer} {Double} (1+) 2 3.45
Ở đây, tôi viết f {T}
cho các ứng dụng kiểu tường minh và giả định một thư viện gõ tương ứng. Một cái gì đó như \a. a
là một loại lambda cấp. Ví dụ x2
phức tạp hơn, bởi vì nó cũng cần các kiểu tồn tại để "quên" các bit đa hình khác trong các đối số.
Bạn thực sự có thể mô phỏng này trong Haskell bằng cách định nghĩa một newtype
hoặc datatype cho mỗi khác nhau m
hoặc n
bạn nhanh chóng với, và thông qua chức năng bao bọc một cách thích hợp f
mà thêm và loại bỏ nhà xây dựng cho phù hợp. Nhưng rõ ràng, đó không phải là niềm vui chút nào.
Chỉnh sửa: Tôi phải chỉ ra rằng điều này vẫn không phải là giải pháp tổng thể đầy đủ. Ví dụ: tôi không thể thấy cách bạn có thể nhập
swap (x,y) = (y,x)
x4 = bi swap (3, "hi") (True, 3.1)
ngay cả trong Hệ thống F-omega.Vấn đề là chức năng swap
là đa hình hơn bi
cho phép, và không giống như với x2
, kích thước đa hình khác không bị lãng quên trong kết quả, do đó, thủ thuật tồn tại không hoạt động. Có vẻ như bạn sẽ cần đa hình loại để cho phép một (để đối số để bi
có thể được đa hình trên một số lượng khác nhau của các loại).
Tôi không nghĩ vậy. Bạn sẽ phải định lượng nó trên tất cả các kiểu đầu vào, đòi hỏi phải trừu tượng hóa các ràng buộc về kiểu chữ. –
@LouisWasserman, có một số công cụ mới (ConstraintKinds) cho phép trừu tượng hóa các ràng buộc. – aemxdp
Được rồi, tôi thấy điều đó, nhưng tôi không nghĩ rằng bạn có thể định lượng các loại kết quả như bạn phải làm. Nếu nó có dạng «a -> a', bạn có thể làm' bi :: (cxt a, cxt b) => (forall x. Cxt x => x -> x) -> a -> b -> (a, b) ', nhưng tôi không nghĩ rằng bạn có thể tự động nhận được" loại chức năng "từ mỗi đầu vào đến loại kết quả của nó. –