Możesz za pomocą tej biblioteki: https://github.com/mikeizbicki/ifcxt.Możliwość wywoływania show
na wartości, która może lub nie może mieć instancji Show
, jest jednym z pierwszych podanych przez nią przykładów. W ten sposób można dostosować, że dla V a
:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
import IfCxt
import Data.Typeable
mkIfCxtInstances ''Show
data V a = V a
instance forall a. IfCxt (Show a) => Show (V a) where
show (V a) = ifCxt (Proxy::Proxy (Show a))
(show a)
"<<unshowable>>"
To jest istota tej biblioteki:
class IfCxt cxt where
ifCxt :: proxy cxt -> (cxt => a) -> a -> a
instance {-# OVERLAPPABLE #-} IfCxt cxt where ifCxt _ t f = f
nie w pełni go zrozumieć, ale to jest, jak myślę, działa:
nie narusza „otwartego świata” założenie więcej niż
instance {-# OVERLAPPABLE #-} Show a where
show _ = "<<unshowable>>"
ma. Podejście jest podobne do tego: dodanie domyślnego przypadku do wszystkich typów, które nie mają instancji w zakresie. Jednak dodaje trochę pośrednictwa, aby nie zepsuć istniejących instancji (i pozwolić różnym funkcjom na określenie różnych wartości domyślnych). IfCxt
pracuje jako AA „meta-klasie”, klasy o ograniczeniach, która wskazuje, czy istnieją takie przypadki, z domyślnym przypadku, który wskazuje „false”.:
instance {-# OVERLAPPABLE #-} IfCxt cxt where ifCxt _ t f = f
Wykorzystuje TemplateHaskell wygenerować długą listę przypadków dla tej klasy:
instance {-# OVERLAPS #-} IfCxt (Show Int) where ifCxt _ t f = t
instance {-# OVERLAPS #-} IfCxt (Show Char) where ifCxt _ t f = t
co oznacza również, że wszelkie przypadki, które nie były w zakresie gdy mkIfCxtInstances
nazwano będą rozpatrywane nieistniejącą.
proxy cxt
Argument ten jest używany do przekazywania do Constraint
do funkcji, (cxt => a)
argument (ja nie RankNTypes idea pozostawiono iż) jest teza, że można zastosowanie ograniczenie cxt
, ale tak długo, jak argument jest nieużywany, ograniczenie nie musi być rozwiązane. Jest to podobne do:
f :: (Show (a -> a) => a) -> a -> a
f _ x = x
proxy
argumentu dostarcza ograniczenie, a następnie IfCxt
ograniczeniem jest rozwiązany albo argumentu t
lub f
, czy to t
następnie istnieją pewne IfCxt
instancja gdzie to ograniczenie jest dostarczana co oznacza, że można rozwiązać bezpośrednio, jeśli jest to f
, to ograniczenie nigdy nie jest wymagane, więc zostaje zrzucone.
To rozwiązanie jest niedoskonały (jak nowe moduły mogą definiować nowe Show
instancji, który nie będzie działać, chyba że wymaga również mkIfCxtInstances
), ale jest w stanie to zrobić by naruszać otwartym światem założenie.
Haskell jest w pełni wymazanym językiem; w czasie wykonywania struktury alokowane w pamięci nie zawierają znaczników, które można wykorzystać do odzyskania ich typów lub klas, które te typy implementują. Dlatego nie ma operatora 'instanceof' takiego jak Java lub podobne języki. (Istnieją bardziej zaawansowane techniki, które mogą być używane w niektórych przypadkach do podobnego typu refleksji typu runtime, ale jeśli jesteś początkującym, powinieneś najpierw trzymać się podstaw!) –
To zachowanie nie może zostać zaimplementowane, ponieważ filozoficznie, każdy typ jest w każdej klasie_.Przyznane, jeśli kompilator nie może _find_ instancji 'Show' dla jakiegoś typu spróbujesz' show', wystąpi błąd; ale rozumiane jest to konceptualnie "zapomniałeś napisać niezbędną instancję" zamiast "spróbowałeś pokazać typ, który _nie jest_przygotowalny". Klasy typów są otwarte, każdy może później zdefiniować wystąpienia dla niektórych klas bibliotecznych. Kompilator nie może udowodnić, że tak się nie stanie, gdy skompiluje bibliotekę! – leftaroundabout
To powiedziawszy: zachowanie można emulować za pomocą [nakładających się instancji] (https://downloads.haskell.org/~ghc/7.8.1/docs/html/users_guide/type-class-extensions.html#instance-overlap) , które są uważane za brzydkie (lub nawet niebezpieczne). Być może lepiej pasuje do tego idea [rodziny typu zamkniętego] (http://research.microsoft.com/en-us/um/people/simonpj/papers/ext-f/axioms-extended.pdf), choć nie łatwo możesz zaimplementować tę instancję pokazową. – leftaroundabout