2010-02-19 29 views
15

Thử nghiệm với các loại hiện có. Có vẻ là một cách tuyệt vời để có được một số loại linh hoạt.Làm thế nào để giải nén một loại tồn tại haskell?

Tôi đang gặp sự cố với việc unboxing một loại tồn tại sau khi tôi đã gói nó lên. Mã của tôi như sau:

{-# LANGUAGE ExistentialQuantification #-} 

class Eq a => Blurb a 
data BlurbBox = forall a . Blurb a => BlurbBox a 

data Greek = Alpha | Beta deriving Eq 
instance Blurb Greek 

data English = Ay | Bee deriving Eq 
instance Blurb English 

box1 :: BlurbBox 
box1 = BlurbBox Alpha 

box2 :: BlurbBox 
box2 = BlurbBox Ay 

main = do 
    case box1 of 
     BlurbBox Alpha -> putStrLn "Alpha" 
     BlurbBox Beta -> putStrLn "Beta" 
     BlurbBox Ay -> putStrLn "Ay" 
     BlurbBox Bee -> putStrLn "Bee" 

Mã này biên dịch chính, sau đó khiếu nại về loại BlurbBox Alpha. Làm thế nào để tôi đi về unboxing/giải nén một loại tồn tại?

Trả lời

14

Trên thực tế, các loại hiện sinh không thể được giải nén, bởi vì toàn bộ quan điểm của họ là mã mong đợi một kiểu hiện sinh phải làm việc hoàn toàn theo cùng một cách (theo nghĩa của tính đa hình tham số) không phân biệt mà chính xác gõ biến kiểu tồn tại được khởi tạo.

Bạn có thể hiểu rằng tốt hơn bằng cách hiểu rằng

data BlurbBox = forall a . Blurb a => BlurbBox a 

được dịch sang

type BlurbBox = forall b . (forall a . Blurb a => a -> b) -> b 

có nghĩa là, BlurbBox là cái gì đó, cho một chức năng đa hình mà làm việc cho hoàn toàn tất cả các squeky, có thể được sử dụng để tạo ra kết quả của việc áp dụng hàm đó cho một số nhiễu (không rõ).

Vì vậy, tương tự như cách bạn không thể viết một hàm kiểu f :: a -> Int và có f String = 5 và f Bool = 3, bạn không thể gửi loại 'a' trong một BlurbBox.

Bạn có thể xem chương trong TAPL về các loại hiện có. Nó mô tả bản dịch mà tôi đã cung cấp.

+0

bạn có liên kết về cách thức/nơi bản dịch này xảy ra không? BlurbBox (hàm tạo) có kiểu 'forall a. Blurb a => a -> BlurbBox 'nhưng bản thân loại (nói chung) là đẳng cấu với ..? – nicolas

+0

có thể trợ giúp. https://mail.haskell.org/pipermail/haskell-cafe/2010-May/078254.html bài tập 23.4.8 của TAPL và chương 24.3 cũng hữu ích – nicolas

4

Theo như tôi biết bạn không thể làm điều đó. Toàn bộ điểm của các kiểu tồn tại là để ẩn một kiểu, vì vậy bạn có thể truy cập tất cả các cá thể "" một cách thống nhất (giống như gửi động các phương thức lớp con trong Java và các ngôn ngữ hướng đối tượng khác).

Vì vậy, trong ví dụ của bạn, "giao diện" của bạn là BlurbBox và bạn sẽ sử dụng nó để áp dụng một số phương pháp thống nhất để BlurbBoxes khác nhau, mà không lo lắng về những gì các loại nội a là (ví dụ nếu Blurb lớp con Show, sau đó bạn có thể có a [BlurbBox] và in từng phần tử trong danh sách mà không cần phải biết chính xác loại nội bộ của mỗi số BlurbBox trong danh sách).

11

Bạn không thể * chuyên loại sau khi bạn đã ẩn đi. Thêm một số ràng buộc hoặc phương thức vào Blurb nếu bạn cần một thao tác như thế này.

-- choose one 
class (Eq a, Show a) => Blurb a where 
    printBlurb :: a -> IO() 
instance Blurb Greek where 
    printBlurb Alpha = putStrLn "Alpha" 
... 

class (Eq a, Show a) => Blurb a 
data Greek deriving (Eq, Show) 
... 

data BlurbBox = forall a. (Blurb a, Show a) => BlurbBox a 
data Greek deriving (Eq, Show) 
... 

* Tôi sẽ rất nhiều khuyên chống này, nhưng nếu bạn thực sự muốn & hellip;

{-# LANGUAGE DeriveDataTypeable #-} 
import Data.Dynamic 

data Greek = Alpha | Beta deriving (Eq, Typeable) 
data English = Ay | Bee deriving (Eq, Typeable) 

box1 :: Dynamic 
box1 = toDyn Alpha 

box2 :: Dynamic 
box2 = toDyn Ay 

main = do 
    case fromDynamic box1 of 
     Just Alpha -> putStrLn "Alpha" 
     Just Beta -> putStrLn "Beta" 
     Nothing -> case fromDynamic box1 of 
     Just Ay -> putStrLn "Ay" 
     Just Bee -> putStrLn "Bee" 
+0

Bạn có thể vui lòng giải thích về phiên bản thứ hai của bạn với 'Dynamic's, why * against *? – wowofbob

Các vấn đề liên quan