Trasmetti un costruttore di dati null tra i tipi

6

Supponiamo di avere un tipo di dati parametrizzato con più di un costruttore di dati null (costante), come ad esempio:

data Check a = Valid | Invalid | Unsure a

A volte voglio manipolare i costruttori non costanti con una funzione che mantiene fisse le costanti nulle e spero di farlo come

instance Functor Check where
  fmap f (Unsure a) = Unsure (f a)
  fmap f c = c

Questo fallisce nel typecheck perché nella dichiarazione fmap f c = c , se f :: a -> b allora c deve essere di entrambi i tipi Check a e Check b . Ovviamente potrei scriverlo completamente in

  fmap f (Unsure a) = Unsure (f a)
  fmap f Valid = Valid
  fmap f Invalid = Invalid

che funziona ma diventa molto difficile quando ci sono molti costruttori nullari. Oppure, in alcuni casi potrei probabilmente ricavare istanze di Show e Read e usare read (show c) per forzare c al tipo necessario. Ma c'è un modo più elegante per avvicinarsi a questo?

    
posta Herng Yi 12.06.2016 - 11:32
fonte

2 risposte

7

Una cosa che potresti fare è cambiare la definizione del tuo tipo di dati in factour fuori dalla parte Valid / Invalid in questo modo:

data Status  = StatusValid | StatusInvalid
data Check a = Sure Status | Unsure a

Puoi quindi implementare Functor senza dover esaminare Status :

instance Functor Check where
  fmap f (Unsure a) = Unsure (f a)
  fmap _ (Sure s)   = Sure s

Se desideri utilizzare l'estensione PatternSynonyms (basta incollare {-# LANGUAGE PatternSynonyms #-} nella parte superiore del file), puoi anche recuperare Valid / Invalid :

pattern Valid   = Sure StatusValid
pattern Invalid = Sure StatusInvalid
    
risposta data 12.06.2016 - 15:10
fonte
4

Puoi utilizzare l'estensione DeriveFunctor e scrivere semplicemente

data Check a = Valid | Invalid | Unsure a deriving Functor
    
risposta data 12.06.2016 - 20:32
fonte

Leggi altre domande sui tag