Sto provando a scrivere un lexer di base usando Haskell. Per l'implementazione di DFA e NFA, ho deciso di inserire alcune funzioni comuni nelle classi FA e FAState.Nessun errore di istanza con classi multiparametro
-- |A class for defining the common functionality of all finite automatons.
class FA a b where
mutateId :: a -> Int -> a -- ^Returns a new FA by changing the sId of the input FA.
mutateType :: a -> StateType -> a -- ^Returns a new FA by changing the stateType of the input FA.
addTransition :: a -> (b, a) -> a -- ^Returns a new FA by adding a new transition to the input FA.
-- |A class for defining the common functionality of all finite automaton states.
class FA a b => FAState a b where
sId :: a -> Int -- ^An unique identifier for the state(hence the prefix s).
sType :: a -> StateType -- ^The type of the state.
sTransitions :: a -> Transitions b a -- ^The transitions that occur from this state.
dove,
-- |A type which identifies different types of a FA state.
data StateType = Start | Normal | Final
deriving (Show, Read, Eq)
-- |A type which represents a list of transitions on input a to b.
-- Eg. [(Char, DFA)] represents the transition on a Char input.
type Transitions a b = [(a, b)]
Quindi, b rappresenta il tipo di dati per cui avvengono le transizioni. Per un DFA, b = Char, mentre per un NFA, b = Symbol.
data Symbol = Alphabet Char | Epsilon
deriving (Show, Read, Eq)
DFA e NFA sono rispettivamente definiti come:
data DFA = DState Int StateType (Transitions Char DFA)
deriving (Show, Read)
data NFA = NState Int StateType (Transitions Symbol NFA)
deriving (Show, Read)
Sto avendo un problema con le definizioni di istanza di FA & FAState:
instance FA DFA Char where
mutateId (DState i ty ts) new_i = DState new_i ty ts
mutateType (DState i ty ts) new_ty = DState i new_ty ts
addTransition (DState i ty ts) state = DState i ty (state:ts)
instance FAState DFA Char where
sId (DState i t ts) = i
sType (DState i t ts) = t
sTransitions (DState i t ts) = ts
instance FA NFA Symbol where
mutateId (NState i ty ts) new_i = NState new_i ty ts
mutateType (NState i ty ts) new_ty = NState i new_ty ts
addTransition (NState i ty ts) state = NState i ty (state:ts)
instance FAState NFA Symbol where
sId (NState i t ts) = i
sType (NState i t ts) = t
sTransitions (NState i t ts) = ts
Il tentativo di eseguire qualsiasi le funzioni ottengono un errore senza istanze:
>>sId egNFA
<interactive>:15:1:
No instance for (FAState NFA b0)
arising from a use of `sId'
Possible fix: add an instance declaration for (FAState NFA b0)
In the expression: sId egNFA
In an equation for `it': it = sId egNFA
Non capisco cosa sta succedendo qui.
C'è anche il vecchio trucco di unificazione ritardata, in cui si pretende che un parametro di tipo sia molto generico e quindi ruoti il braccio di GHC rendendolo specifico una volta che si impegna in un'istanza ... ma è utile soprattutto per ingannare shenanigans disonputabili. –
@ C.A.McCann Ah, sì, buon suggerimento. Lo aggiungerò –
Prima di postare la domanda ho letto un po 'sulle dipendenze delle funzioni, non pensavo si applicasse a questo caso perché non riesco a capire come il compilatore possa dedurre il valore di b con a. Voglio dire come si dice che "b può essere scoperto usando un", aiutare il compilatore a trovare effettivamente b? – Likhit