Tôi đã có một chức năng có nhiệm vụ tính toán một số giá trị tối ưu của loại a
wrt một số chức năng giá trị của loại a -> v
loại Hiện sinh trong chức năng bậc cao
type OptiF a v = (a -> v) -> a
Sau đó, tôi có một container mà muốn để lưu trữ như vậy một chức năng cùng với chức năng khác trong đó sử dụng các giá trị giá trị:
data Container a = forall v. (Ord v) => Cons (OptiF a v) (a -> Int)
ý tưởng là bất cứ ai thực hiện một chức năng của loại OptiF a v
không nên bị làm phiền với các chi tiết của v
ngoại trừ việc nó' s một ví dụ của Ord
.
Vì vậy, tôi đã viết một hàm có hàm giá trị như vậy và vùng chứa. Sử dụng OptiF a v
nó nên tính giá trị wrt tối ưu val
và cắm nó vào result
chức năng của container:
optimize :: (forall v. (Ord v) => a -> v) -> Container a -> Int
optimize val (Cons opti result) = result (opti val)
Cho đến nay rất tốt, nhưng tôi không thể gọi optimize
, vì
callOptimize :: Int
callOptimize = optimize val cont
where val = (*3)
opti val' = if val' 1 > val' 0 then 100 else -100
cont = Cons opti (*2)
không biên dịch:
Could not deduce (v ~ Int)
from the context (Ord v)
bound by a type expected by the context: Ord v => Int -> v
at bla.hs:12:16-32
`v' is a rigid type variable bound by
a type expected by the context: Ord v => Int -> v at bla.hs:12:16
Expected type: Int
Actual type: Int
Expected type: Int -> v
Actual type: Int -> Int
In the first argument of `optimize', namely `val'
In the expression: optimize val cont
nơi dòng 12: 16-32 là optimize val cont
.
Tôi có hiểu nhầm các loại tồn tại trong trường hợp này không? Có phải forall v
trong tuyên bố của optimize
có nghĩa là optimize
có thể mong đợi từ a -> v
bất cứ điều gì v
muốn? Hoặc có nghĩa là optimize
có thể không mong đợi gì từ a -> v
ngoại trừ Ord v
?
Điều tôi muốn là OptiF a v
không được sửa cho bất kỳ v
nào, bởi vì tôi muốn cắm vào một số a -> v
sau này. Ràng buộc duy nhất tôi muốn áp đặt là Ord v
. Thậm chí có thể diễn tả một cái gì đó như thế bằng cách sử dụng các loại tồn tại (hay bất kỳ thứ gì)?
Tôi đã đạt được điều đó với một kiểu chữ bổ sung cung cấp hàm optimize
có chữ ký tương tự với OptiF a v
, nhưng trông có vẻ xấu hơn nhiều so với sử dụng hàm bậc cao hơn.
Bạn đã làm cho ngày của mình và có thể là một vài câu hỏi tiếp theo :) Bạn có ý nghĩa gì bởi 'existentials đã lỗi thời'? Rằng họ được gộp bởi GADTs như đã nói trong http://en.wikibooks.org/wiki/Haskell/GADT#Existential_types? Nhưng tôi không nên thay thế ADT bằng GADTs khi không cần thiết, đúng không? – chs
Đối với các hàm tạo đơn giản (nhưng có thể có nhiều hàm khác nhau), cú pháp 'dữ liệu cũ 'được cho là dễ đọc hơn, vì vậy: không, bạn không nên thay thế những người có GADT (mặc dù không có gì sai cả!). Đối với bất cứ điều gì liên quan đến các biến kiểu không được đề cập trong đầu dữ liệu, tôi sẽ sử dụng cú pháp GADT. – leftaroundabout