Việc triển khai GHC của Data.Reflection
từ gói sử dụng một mẹo liên quan đến unsafeCoerce
tận dụng lợi thế của cách GHC biên soạn typeclasses bằng cách sử dụng từ điển đi qua. Việc thực hiện ngắn, vì vậy tôi có thể tái tạo nó một cách trọn vẹn ở đây:Có thể thực hiện thủ thuật của Data.Reflection bằng cách sử dụng các loại gia đình thay vì fundeps không?
class Reifies s a | s -> a where
reflect :: proxy s -> a
newtype Magic a r = Magic (forall (s :: *). Reifies s a => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). Reifies s a => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
Điều này làm cho nó có thể cụ thể hóa một giá trị ở cấp loại, sau đó phản ánh nó trở lại:
ghci> reify (42 :: Integer) (\p -> reflect p) :: Integer
42
Tôi đã quan tâm khi sử dụng kỹ thuật này, nhưng tôi nghĩ sẽ thuận tiện cho mục đích sử dụng gia đình kiểu của mình với số Reifies
thay vì phụ thuộc chức năng, vì vậy tôi đã cố gắng viết lại quá trình triển khai bằng cách sử dụng phép biến đổi thông thường:
class Reifies s where
type Reflects s
reflect :: Proxy s -> Reflects s
newtype Magic a r = Magic (forall (s :: *). (Reifies s, Reflects s ~ a) => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). (Reifies s, Reflects s ~ a) => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
Đáng buồn thay, tuy nhiên, điều này không còn hoạt động! Điều này thay đổi quá trình biên soạn đủ để phá vỡ thủ thuật unsafeCoerce
:
ghci> reify (42 :: Integer) (\p -> reflect p) :: Integer
2199023255808
Tuy nhiên, tôi không quen với cách GHC hoạt động để hiểu tại sao. Có thể triển khai Data.Reflection
bằng cách sử dụng loại được liên kết thay vì phụ thuộc chức năng không? Nếu có, cần thay đổi điều gì? Nếu không, tai sao không?
Sau khi tôi viết câu hỏi này, tôi lén nhìn vào cốt lõi và phát hiện ra, trước sự ngạc nhiên của tôi, rằng đẳng loại có nhân chứng thời gian chạy , ít nhất là ở cấp độ cốt lõi. Có một số thông tin ở đâu đó về cách các nhân chứng bình đẳng hoạt động không? Tôi có thể (không an toàn) cung cấp cái gì khác thay cho nhân chứng bình đẳng không? Thay đổi mã của tôi bao giờ quá nhẹ để 'unsafeCoerce (Magic k :: Magic a r) (const a)() Proxy' hoạt động, nhưng tôi e rằng nó có thể không phải lúc nào cũng hoạt động. –
@AlexisKing, đó là một câu hỏi hay mà tôi không biết câu trả lời. – dfeuer
@AlexisKing, một tùy chọn khác (tôi nghĩ) có thể là làm cho 'reflect'' trả về GADT cho bằng chứng rằng' a ~ Reflects s'. Tôi chưa từng làm việc. – dfeuer