2016-08-05 11 views
7

tôi nhận thấy rằng các bộ kiểm tra cho Data.Set chỉ thực sự định nghĩa Arbitrary Set a hợp lý cho a ~ Int, nhưng để tránh GHC đặc biệt ~ nó sử dụngLàm thế nào tôi có thể xác định một cá thể cho một ứng dụng kiểu cụ thể trong Haskell 98?

instance Enum a => Arbitrary (Set a) 

Làm thế nào tôi có thể chắc chắn rằng chỉ dụ Arbitrary (Set Int) được sử dụng mà không cần bất kỳ phần mở rộng GHC ? Trong GHC chỉ mã, tôi muốn sử dụng một trong hai FlexibleInstances hoặc GADTs và sau đó một trong hai

instance Arbitrary (Set Int) 

hoặc

instance a ~ Int => Arbitrary (Set a) 

Trả lời

6

Điều này có thể sử dụng một ý tưởng tôi nghĩ đầu tiên tôi gặp trong một bài báo của Oleg Kiselyov, và có phần dưới là Control.Lens.Equality.

import Data.Functor.Identity 

class IsInt a where 
    fromIntF :: f Int -> f a 

instance IsInt Int where 
    fromIntF fx = fx 

toIntF :: IsInt a => g a -> g Int 
toIntF = unf . fromIntF . F $ id 

newtype F g a b = F {unf :: g b -> a} 

fromInt :: IsInt a => Int -> a 
fromInt = runIdentity . fromIntF . Identity 

toInt :: IsInt a => a -> Int 
toInt = runIdentity . toIntF . Identity 

Bây giờ tôi có thể sử dụng

instance IsInt a => Arbitrary (Set a) 

và tự tin rằng tôi thực sự đối phó với Int. Để thuận tiện, tôi có thể hạn chế lớp IsInt với bất kỳ lớp học tôi cần trong đó Int là một ví dụ:

class (Show a, Read a, Integral a, Arbitrary a) => IsInt a where ... 
+3

Nó có thể là đáng nói: này mang đến cho bạn sự bảo đảm bạn muốn bên ngoài hệ thống, nhưng không phải bên trong nó. Tức là, GHC sẽ không suy ra từ 'IsInt a' là 'a ~ Int'. Điều này đôi khi có thể yêu cầu chú thích loại bổ sung gây phiền nhiễu. Tôi không nghĩ rằng có thể được giúp hoàn toàn trong H98 (hoặc H2010), mặc dù. –

+0

@DanielWagner, vâng, nó chắc chắn thấp hơn cách tiếp cận của GHC. Nếu các ràng buộc bình đẳng được chuẩn hóa, tôi chắc chắn sẽ thích chúng hơn. Nhưng 'container' thường cố gắng trở thành" di động "nhất có thể, vì vậy nếu tôi có thể làm những gì tôi cần mà không có phần mở rộng, tôi sẽ. – dfeuer

+1

@DanielWagner, tôi nghĩ rằng nó cũng đáng chú ý là việc triển khai này tương thích với GHC, trong đó bạn có thể áp dụng 'fromIntF' vào' Refl :: Int: ~: Int' để lấy một kiểu 'IsInt a => Int: ~ : a'. Thật vậy, điều này sẽ làm việc cho bất kỳ loại bình đẳng tương tự, bất kể nó phù hợp với ngôn ngữ như thế nào. – dfeuer

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