2016-08-05 29 views
7

zauważyłem, że zestaw testowy dla Data.Set tylko naprawdę definiuje Arbitrary Set a sensownie dla a ~ Int, ale aby uniknąć GHC specjalny ~ używaJak zdefiniować instancję dla konkretnej aplikacji typu w Haskell 98?

instance Enum a => Arbitrary (Set a) 

Jak mogę się upewnić, tylko instancja Arbitrary (Set Int) jest stosowany bez konieczności jakichkolwiek rozszerzeń GHC ? W GHC-tylko kodu, chciałbym użyć jednej FlexibleInstances lub GADTs a następnie albo

instance Arbitrary (Set Int) 

lub

instance a ~ Int => Arbitrary (Set a) 

Odpowiedz

6

Jest to możliwe za pomocą pomysł Chyba po raz pierwszy spotkali się w papierze Oleg Kiselyov, i który leży u podłoża 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 

Teraz mogę używać

instance IsInt a => Arbitrary (Set a) 

i mieć pewność, że mam do czynienia z naprawdę Int. Dla wygody, można ograniczyć klasę IsInt wszelkich klas I potrzebują których Int jest instancją:

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

Warto może wspomnieć: to daje gwarancję chcesz poza systemem, ale nie w środku. Oznacza to, że GHC nie wywnioskuje z 'IsInt a', że' a ~ Int'. Może to czasami wymagać denerwujących dodatkowych adnotacji typu. Nie sądzę, że można to osiągnąć wyłącznie w H98 (lub H2010). –

+0

@ Danielhagner, tak, jest zdecydowanie gorszy od podejścia GHC. Jeśli ograniczenia równości są zawsze ujednolicone, zdecydowanie będę je preferował. Ale "pojemniki" na ogół starają się być tak "przenośne", jak to możliwe, więc jeśli mogę zrobić to, czego potrzebuję bez rozszerzenia, zrobię to. – dfeuer

+1

@DanielWagner, myślę, że warto również zauważyć, że ta implementacja jest zgodna z GHC, ponieważ można zastosować 'fromIntF' do' Refl :: Int: ~: Int', aby uzyskać coś typu 'IsInt a => Int: ~ : a'. W rzeczywistości będzie to działało dla każdego podobnego rodzaju równości, niezależnie od tego, jak pasuje do tego języka. – dfeuer

Powiązane problemy