Frage Schwierigkeit mit Zoom und freien Monaden


Ich mische mit freien Monaden und Linsen herum und benutze die freie Monade, um meine eigene Version der IO-Monade zu erstellen:

data MyIO next
    = LogMsg String next
    | GetInput (String -> next)
    deriving (Functor)

Ich staple das auf einer State Monade wie folgt: FreeT MyIO (State GameState) a woher GameState ist:

data GameState = GameState { _players :: [PlayerState] }

Nun, was ich gerne haben möchte, ist eine Möglichkeit, "hineinzuzoomen" PlayerState von einem GameState Kontext. Etwas wie das:

zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a
zoomPlayer i prog = hoistFreeT (zoom (players . element i)) prog

Aber ich bekomme diesen Fehler:

No instance for (Data.Monoid.Monoid a1)
  arising from a use of ‘_head’

Dieser Fehler scheint mit der Tatsache zusammenzuhängen, dass players . element i ist eine Durchquerung; wenn ich den Listenaspekt von entferne _players und benutze normale Linse, dann funktioniert der Code.

Irgendwelche Ideen, wie man diese Funktion schreibt?


5
2018-04-06 19:41


Ursprung


Antworten:


Wenn Sie sicher sind, dass Sie niemals in einen nicht existierenden Player einsteigen und sich nicht um ein wenig unsicher machen, können Sie das verwenden unsafeSingular Kombinator um a zu drehen Traversal in ein Lens, so was:

zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a
zoomPlayer i prog = hoistFreeT (zoom (players . unsafeSingular (element i))) prog

(Außerdem würde ich vielleicht verwenden ix Anstatt von element, aber das hat nichts mit dem Problem zu tun.)

Wir können auch sichere Indexierungslinsen für immer unendliche Sequenzen konstruieren, wie z Cofree von dem free Paket:

import Control.Lens (Lens', _Wrapped')
import Control.Comonad.Cofree (Cofree, telescoped)
import Data.Functor.Identity
import Control

sureIx :: Int -> Lens' (Cofree Identity a) a
sureIx i = telescoped $ replicate i _Wrapped'

Aber ein Spiel hat wahrscheinlich keine unendlichen Spieler.


2
2018-04-09 06:44