2013-04-25 17 views
13

Con il pacchetto dell'obiettivo stavo codificando. Tutto stava andando bene fino a quando ho provato ad accedere a un determinato campo su un tipo algebrico:Pacchetto di lenti con tipi algebrici

import Control.Lens 

data Type = A { _a :: Char } | B 

makeLenses ''Type 

test1 = _a (A 'a') 
test2 = (A 'a') ^. a 

No instance for (Data.Monoid.Monoid Char) 
    arising from a use of `a' 
Possible fix: 
    add an instance declaration for (Data.Monoid.Monoid Char) 
In the second argument of `(^.)', namely `a' 
In the expression: (A 'a') ^. a 
In an equation for `test2': test2 = (A 'a') ^. a 

ho potuto solo andare con _A, ma il tipo di dati nel mio programma reale è molto più profondo e mi sono inteso sull'uso di lenti a ridurre la quantità di lavoro che devo fare. Ho esaminato la libreria degli obiettivi, ma c'è così tanto, e non sono sicuro che abbia affrontato questo scenario o sia qualcosa che la libreria di obiettivi non supporta.

Come nota a margine, se effettivamente uso una stringa monoide come il tipo di dati anziché Char, quindi compila e fornisce la risposta corretta, non ho idea del perché.

Edit: Dopo aver letto il commento di Hammar, ho provato questo e questo funziona:

test2 = (A 'a') ^? a 
test3 = B ^? a 

Ma è un po 'strano per ottenere un forse da quella per qualcosa che deve esistere.

+5

Non troppo familiare con il funzionamento interno del pacchetto dell'obiettivo, ma: Considerare cosa 'B ^. a' dovrebbe tornare. Deve scegliere qualcosa, quindi cerca di usare 'mempty' come default invece di lanciare un'eccezione come' _a B' fa. – hammar

+2

Non avevo idea che _a B si sarebbe compilato. Ho avuto un bug nel mio codice che non avrei realizzato se non ci fosse stato runtime e non ci sono stati avvertimenti nemmeno con Wall. Quindi, suppongo che userò ^? e forse la funzione e questo fa esattamente quello di cui ho bisogno. –

+3

In realtà, ripensandoci, sono giunto alla conclusione che i metodi di accesso ai tipi algebrici sono solo una cattiva idea. Sono sorpreso che sia persino permesso. Ho avuto così tanti bug nel mio programma che ho appena ripulito. –

risposta

5

Proprio per questo, il mio problema era che avevo un tipo algebrico in cui alcuni campi erano in comune tra i diversi costruttori ma c'era un paio di campi che non erano condivisi sarebbero morti in runtime se avessi provato ad usare loro.

data Exercise = 
    BarbellExercise { 
    name :: String, 
    weight :: Int, 
    reps :: Int 
    } | 
    BodyWeightExercise { 
    name :: String, 
    reps :: Int 
    } 

exer1 = BarbellExercise "Squats" 235 15 
exer2 = BarbellExercise "Deadlifts" 265 15 
exer3 = BodyWeightExercise "Pullups" 12 
exer4 = BarbellExercise "Overhead Press" 85 15 

workout = [exer1, exer2, exer3, exer4] 

test = do 
    mapM_ displayExercise workout 

    where 
    displayExercise x = putStrLn $ "Exercise: " ++ (name x) ++ " You must perform " ++ (show $ reps x) ++ "@" ++ (show $ weight x) 

Questo compila ma muore in runtime se commetto l'errore di utilizzare la funzione peso. Errore comprensibile Quando gli obiettivi utilizzano haskell del modello per generare istanze, questo lo rileva e modifica il suo comportamento per evitare un errore. È possibile rimuovere gli accessors di campo ma nel mio caso la maggior parte dei campi erano gli stessi tra i tipi di dati. Ecco come avrei dovuto scrivere il tipo di dati una volta ho notato che i campi non corrispondono:

data Exercise = 
    BarbellExercise 
    String --^name 
    Int --^reps 
    Int --^weight 
    | 
    BodyWeightExercise 
    String --^name 
    Int -- reps 


name :: Exercise -> String 
name (BarbellExercise n _ _) = n 
name (BodyWeightExercise n _) = n 

reps :: Exercise -> Int 
reps (BarbellExercise _ r _) = r 
reps (BodyWeightExercise _ r) = r 

Facendo in questo modo, mentre è un po 'meno pulito, l'errore sono catturati in fase di compilazione. Costringendomi a scrivere le funzioni personalmente, noterei le funzioni parziali mentre le stavo scrivendo.

Vorrei un po 'che ghc mi avrebbe avvertito. Sembra che sarebbe davvero facile per lui rilevare una cosa del genere.

Problemi correlati