2017-09-26 4 views
0

tl; dr: ist es möglich, eine der lens Familie von Abstraktionen zu verwenden, zu wickeln/auspacken jeder beliebigen newtype (also eine Instanz für solche Abstraktionen bereitstellt)?Wie die vorformulierten der Verpackung zu beseitigen und Abwickeln mit Linsen

Ich werde meine Frage durch ein einfaches Beispiel motivieren, basierend auf einer wahren Geschichte. Angenommen, ich definieren die folgende newtype:

newtype FreeMonoid a = FreeMonoid { asMap :: Map a Int } 

die verwendet wird, hinsichtlich der Form darzustellen:

a0 <> a1 <> ... <> an-1 

Wir können frei Monoide als Listen darstellen:

instance Ord a => IsList (FreeMonoid a) where 
    type Item (FreeMonoid a) = a 
    fromList xs = FreeMonoid $ Map.fromListWith (+) $ zip xs (repeat 1) 
    toList (FreeMonoid p) = do 
     (x, n) <- Map.toList p 
     genericReplicate n x 

Zwei Beispiele Frei-Monoiden sind Sequenzen von Summe und Sequenzen von Produkten:

type FreeSum a = FreeMonoid (Sum a) 
type FreeProduct a = FreeMonoid (Product a) 

Dabei sind Sum und Product in Data.Monoid definiert. Jetzt konnten wir fromList und toList Operationen für FreeSum definieren und FreeProduct wie folgt:

fromListSum :: Ord a => [a] -> FreeSum a 
fromListSum = fromList . (Sum <$>) 

fromListProduct :: Ord a => [a] -> FreeProduct a 
fromListProduct = fromList . (Product <$>) 

Das hat aber eine ganze Reihe von vorformulierten. Es wäre schöner, wenn wir einfach sagen könnte:

fromListW :: (Ord a, Wrapper f) => [a] -> FreeMonoid (f a) 
fromListW = fromList . (wrap <$>) 

wo wrap ist eine Operation der (hypotetical) Wrapper Klasse waren:

wrap :: a -> f a 
unwrap :: f a -> a 

Und ich möchte in der Lage sein zu schreiben eine Funktion:

toListW :: (Ord a, Wrapper f) => FreeMonoid (f a) -> [a] 
toListW = (unwrap <$>) . toList 

Lenses scheinen solche eine Abstraktion in Control.Lens.Wrapped, um (für die SumProduct und in diesem Beispiel sind Insta nces der typeclasses dort!). Meine Versuche, die Abstraktionen in diesem Modul zu verstehen und zu verwenden, sind jedoch fehlgeschlagen. Zum Beispiel:

fromListW :: (Ord a, Wrapped (f a)) => [a] -> FreeMonoid (f a) 
fromListW = fromList . (Wrapped <$>) 

wird nicht funktionieren, da das Argument nicht eine Liste von Unwrapped (f a) ist.

Also meine Frage ist:

  • Do Linsen eine Abstraktion ähnlich wie diese Wrapper Klasse zur Verfügung stellen?
  • Wenn nicht, kann dieses Problem mit der Verwendung von Linsen gelöst werden?

Antwort

1

Das „Problem“ ist, dass Sie Wrapped verwenden, das ist wirklich ein Convenience-Muster Synonym und kein wrapping „Konstruktor“ gemeint ist, zu sein.Weil es entworfen ist polymorph Verpackung zu unterstützen, müssen Sie behaupten, dass Ihre Art umgebrochen werden kann:

fromListW :: (Rewrapped a a, Ord a) => [Unwrapped a] -> FreeMonoid a 
fromListW = fromList . (Wrapped <$>) 

Dies ist dann wie erwartet funktioniert:

> let x = [1,2,3] 
> fromListW x :: FreeMonoid (Sum Int) 
FreeMonoid {asMap = fromList [(Sum {getSum = 1},... 
> fromListW x :: FreeMonoid (Product Int) 
FreeMonoid {asMap = fromList [(Product {getProduct = 1},... 
> 

denke ich, eine idiomatische Objektiv Implementierung wäre:

fromListW :: (Rewrapped a a, Ord a) => [Unwrapped a] -> FreeMonoid a 
fromListW = fromList . view (mapping _Unwrapped) 

Dies erfordert noch die Rewrapped a a Einschränkung, aber Sie können die nicht-polymorphe _Unwrapped' statt:

fromListW :: (Wrapped a, Ord a) => [Unwrapped a] -> FreeMonoid a 
fromListW = fromList . view (mapping _Unwrapped') 

, die ein wenig natürlicher aussieht.

Die toListW Implementierung würde eine ähnliche Struktur haben:

toListW :: (Wrapped a, Ord a) => FreeMonoid a -> [Unwrapped a] 
toListW = view (mapping _Wrapped') . toList 
+0

Danke für die tolle Antwort. Es ist immer noch unklar, wie und warum die Lösung funktioniert, aber ich hoffe, dass das Verständnis kommt, nachdem ich tiefer in Linsen eingetaucht bin. In der Zwischenzeit ist [hier] (https://github.com/capitanbatata/sandbox/blob/master/pw-lenses/src/Coercions.lhs) ein funktionierender Code. –

Verwandte Themen