2013-02-01 23 views
32

Sono nuovo di Haskell e sono in difficoltà con il debug del mio codice. La correzione di un errore porta ad altri errori ...Nessuna istanza per (Fractional Int) derivante da un uso di `/ '

Ecco il mio codice.

import Data.Maybe 

data Op = Add | Sub | Mul | Div | And | Or | Not | Eq | Less | Great 
    deriving (Eq, Show) 

data Exp = Literal Value 
    | Primitive Op [Exp] 
    | Variable String 
    | If Exp Exp Exp 
    | Let [(String, Exp)] Exp 
    deriving (Show, Eq) 

data Value = Number Int 
     | Bool Bool 
     | String String 
    deriving (Eq, Show) 

type Env = [(String, Value)] 

eval :: Env -> Exp -> Value 
eval e (Literal v) = v 
eval e (Variable x) = fromJust (lookup x e) --22 

prim :: Op -> [Value] -> Value 
prim Add [Number a, Number b] = Number (a + b) 
prim And [Bool a, Bool b] = Bool (a && b) 
prim Sub [Number a, Nuamber b] = Number (a - b) -- No instance for (Fractional Int) arising from a use of `/' 
prim Mul [Number a, Number b] = Number (a * b) 
prim Div [Number a, Number b] = Number (a/b) 
prim Or [Bool a, Bool b] = Bool (a || b) 
prim Not [Bool a] = Bool (not a) 
prim Eq [Number a, Number b] = Bool (a == b) 
prim Eq [String a, String b] = Bool (a == b) 
prim Less [Number a, Number b] = Bool (a < b) 
prim Less [String a, String b] = Bool (a < b) 
prim Great [Number a, Number b] = Bool (a > b) 
prim Great [String a, String b] = Bool (a > b) --37 

main = do 
    eval [("y", (Number 40))] (Let [("x", (Literal (Number 2)))] (prim Add [(Variable "x"), (Variable "y")])) -- Couldn't match expected type `Exp' with actual type `Value' 

Ora sto ricevendo due errori che ho scritto nei commenti. Se sai cosa c'è di sbagliato nel mio codice, per favore condividi la tua idea e risparmia il mio tempo ...

Grazie mille.

+0

Intendevi 'Numero (div a b)' o la sua versione infisso? –

risposta

52
-- No instance for (Fractional Int) arising from a use of `/' 

Presumibilmente che sta venendo da questa linea anziché uno con il tuo commento:

prim Div [Number a, Number b] = Number (a/b) 

a e b sono Int s. L'operatore di divisione è (/) :: Fractional a => a -> a -> a (lo puoi scoprire attivando ghci e inserendo :t (/) o looking it up on Hoogle).

Se non avete visto i tipi come Fractional a => a -> a -> a, si dovrebbe leggere questo in due parti:

  1. Il contesto Fractional a
  2. Il tipo a -> a -> a

Questo è proprio come un normale a -> a -> a digita, quindi accetta due argomenti di un certo tipo e ti restituisce un risultato dello stesso tipo.L'unica differenza nell'aggiunta del contesto Fractional a è che il tipo utilizzato per a deve essere un'istanza della classe di tipo Fractional; non è libero di spaziare su qualsiasi tipo che ti piace.

Se non hai ancora imparato a conoscere le classi di tipi, non preoccuparti. Sono abbastanza facili da capire, ma non qualcosa che dovresti guardare in profondità quando stai iniziando; li raggiungerai più tardi.

Int non è un membro della classe Fractional tipo, quindi l'operatore / non funziona su Int s.

Il motivo è che la divisione matematica regolare non funziona su numeri interi con questo tipo,; 3/2 dovrebbe fornire 1.5, nel qual caso non si adatta al tipo Int -> Int -> Int o fornire 1 o 2, nel qual caso non sarebbe corretta divisione matematica. Esiste una funzione div per l'implementazione di integer division, utilizzabile come a `div` b in notazione infisso.

-- Couldn't match expected type `Exp' with actual type `Value' 

Questo messaggio riguarda i propri tipi, in una singola espressione che hai scritto. E il messaggio di errore completo effettivo ti avrebbe dato più contesto su quale parte dell'espressione contiene l'errore. Basta seguirlo dall'alto verso il basso, controllando il tipo di cose da te e l'errore salta fuori molto rapidamente.

In questo caso, si arriva a qui:

Let [("x", (Literal (Number 2)))] (prim Add [(Variable "x"), (Variable "y")]) 

Let ha bisogno di due argomenti, una [(String, Exp)] ed un Exp. L'elenco va bene, ma il secondo argomento è (prim Add [(Variable "x"), (Variable "y")]). Senza nemmeno scavare nella sottostruttura di quello per vedere se è corretto, prim ha tipo Op -> [Value] -> Value, quindi non c'è modo che possa darti un Exp.

Come risolvere ciò che sta a te; sembra che tu abbia bisogno di un po 'di un refactor attraverso l'intera distinzione espressione/valore. prim ti dà un Value, che potresti semplicemente applicare a capo in un Literal per superare l'errore di tipo che stai ricevendo, ma poi ti imbatti nel problema che prim dovrebbe prendere un Op e un [Value], ma sembra che tu abbia dato un Op e un [Exp] (contenente variabili). Penso che è necessario pensare alla differenza tra l'utilizzo prim per calcolare i risultati di un'applicazione primitiva, utilizzando la Primitive costruttore Exp per rappresentare un'applicazione primitivo, e l'utilizzo di eval per valutare (in ambiente) un'espressione arbitraria (che può contenere diverse applicazioni primitive) ad un valore.

+0

oops, il mio male. Ho inserito il commento nella riga sbagliata. – Nayana

+0

Grazie mille per il tempo dedicato a rispondere gentilmente alla mia domanda. – Nayana

+0

Mi dispiace, ma cosa significa questo "(/) :: Fractional a => a -> a -> a" significa? Significa che ne prende uno e un altro come parametri e restituisce a, giusto? ma cosa significa? Come faccio a sapere che Int non è un membro della classe di tipo Fractional da quello? – Nayana

19

Il problema che si verifica è che Haskell ha diverse funzioni per la divisione intera e "frazionaria". La divisione intera tronca, la divisione frazionaria no. Così, invece di

prim Div [Number a, Number b] = Number (a/b) 

si vuole fare

prim Div [Number a, Number b] = Number (a `div` b) 

Quello che il messaggio di errore significa in realtà è che la funzione (/) è parte della classe Fractional. Questa è fondamentalmente un'interfaccia che diversi tipi possono implementare. Per avere informazioni su di esso fuoco fino ghci e fare

Prelude> :i (/) 
class Num a => Fractional a where 
(/) :: a -> a -> a 
... 
-- Defined in `GHC.Real' 
infixl 7/

Prelude> :i Int 
data Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types' 
instance Bounded Int -- Defined in `GHC.Enum' 
instance Enum Int -- Defined in `GHC.Enum' 
instance Eq Int -- Defined in `GHC.Classes' 
instance Integral Int -- Defined in `GHC.Real' 
instance Num Int -- Defined in `GHC.Num' 
instance Ord Int -- Defined in `GHC.Classes' 
instance Read Int -- Defined in `GHC.Read' 
instance Real Int -- Defined in `GHC.Real' 
instance Show Int -- Defined in `GHC.Show' 

La prima fornisce informazioni sulla funzione (/): ti dice che è nella classe Fractional. Quindi quando si visualizza :i Int tutte le istanze per Int. Si noti che Int non è un'istanza di Fractional quindi non è possibile utilizzare (/) con Int.

altro suggerimento: I backtick (`) trasformare una funzione in un operatore infisso così

a `div` b 

è uguale

div a b 
+0

Grazie mille, hai un'idea per il secondo errore? – Nayana

+0

Beh, Ben era più veloce ... – Paul

+0

wok per l'operatore 'div' per me –

Problemi correlati