2016-04-23 12 views
0

Ich habe folgendes Programm:Wie Wert in einer verschachtelten Karte setzen Objektiv mit

{-# LANGUAGE TemplateHaskell #-} 
import qualified Data.Map.Strict as Map 
import Control.Lens 

data MyLabel = MyLabel { _label :: String } deriving (Show, Eq, Ord) 
data MyMap = MyMap { _vals :: Map.Map String MyLabel } deriving (Show, Eq, Ord) 
makeLenses ''MyLabel 
makeLenses ''MyMap 

sample :: MyMap 
sample = MyMap { _vals = Map.fromList [("foo", MyLabel "bar")] } 

Jetzt würde ich gerne wissen, wie eine Transformation zu tun f Linsen, so dass:

f sample "quux" == MyMap { _vals = Map.fromList [("foo", MyLabel "quux")] } 

ich habe gelernt, dass die Funktion at von Lens-Bibliothek verwendet werden soll, Karten zu ändern, so dass ich versuchte, solche Dinge zu tun:

sample ^. vals & at "foo" . label .~ Just "quux" 

Aber das erzeugt eine Fehlermeldung, die für mich nicht sehr verständlich ist. Was ist der richtige Weg?

+0

Gibt es einen Grund, warum Sie 'data' anstelle von' newtype' dafür verwenden? – dfeuer

+1

Ja, zur besseren Lesbarkeit wurde es aus einem größeren Codecode extrahiert, in dem ich mehr Felder verwende. – user1747134

Antwort

4

Versuchen Sie, diese für Größe:

{-# LANGUAGE TemplateHaskell #-} 

module Main where 

import qualified Data.Map.Strict as Map 
import Control.Lens 

data MyLabel = 
    MyLabel { _label :: String } deriving (Show, Eq, Ord) 

data MyMap = 
    MyMap { _vals :: Map.Map String MyLabel } deriving (Show, Eq, Ord) 

makeLenses ''MyLabel 
makeLenses ''MyMap 

sample :: MyMap 
sample = 
    MyMap (Map.fromList [("foo", MyLabel "bar")]) 

main :: IO() 
main = 
    print (sample & (vals . at "foo" . _Just . label .~ "quux")) 

dass Denken Sie daran, bei der Einstellung, Sie versuchen MyMap -> MyMap eine Funktion des Typs zu bauen. Die Art, wie Sie das tun, besteht darin, eine Reihe von Optiken zusammen zu verketten (vals . at "foo" . _Just . label) und dann eine Setter-Operation zu wählen (.~). Sie können eine Getter-Operation wie ^. nicht mit einer Setter-Operation wie .~ mischen und abgleichen! Also jedes Setter mehr oder weniger wie folgt aussieht:

foo' = (optic1 . optic2 . optic3 . optic4) .~ value $ foo 
--  _________this has type Foo -> Foo___________ 

Und die Lesbarkeit verbessern wir & verwenden, die leicht geschlagene Version von $:

foo' = foo & (optic1 . optic2 . optic3 . optic4) .~ value 
+0

Vielen Dank für Ihre Antwort. Ich bekomme jedoch immer noch eine ähnliche Kompilierfehlermeldung, wenn ich versuche, Ihren Code zu kompilieren. Welche Version von Ghc/Objektiv sollte ich verwenden, damit dies funktioniert? 'Der Typ 'IxValue (Map.Map String MyLabel)' konnte nicht mit 'MyLabel'' abgeglichen werden ...' Der erwartete Typ' Index (Map.Map String MyLabel) konnte nicht mit dem tatsächlichen Typ '[Char]' ' – user1747134

+0

abgeglichen werden GHC 7.10, neueste Linse – hao

0

Das Problem tatsächlich durch Kabale Hölle verursacht wurde und Reinigung ~/.ghc Verzeichnis war notwendig, damit es funktioniert.