haskell - 镜头变焦模糊变量

标签 haskell haskell-lens

我在使用 Control.Lens 提供的 zoom 功能时遇到困难。使用我的自定义 monad 转换器 HearthMonad,我无法弄清楚如何满足 GHC 的“模糊类型”投诉。

有问题的代码位于drawCard中。

我该如何解决这个问题?我是否必须创建自己的自定义缩放运算符来处理 Hearth m 中的 Monad m

<小时/>
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}


module EngineZoom where


--------------------------------------------------------------------------------


import Control.Applicative
import Control.Lens
import Control.Monad.State
import Data.List
import Data.Maybe


--------------------------------------------------------------------------------


type PlayerHandle = String


data Card = Card String
    deriving (Show, Eq, Ord)


data Player = Player {
    _playerHandle :: PlayerHandle,
    _hand :: [Card]
} deriving (Show, Eq, Ord)
makeLenses ''Player


data GameState = GameState {
    _gamePlayers :: [Player]
} deriving (Show, Eq, Ord)
makeLenses ''GameState


newtype Hearth m a = Hearth {
    unHearth :: StateT GameState m a
} deriving (Functor, Applicative, Monad, MonadState GameState, MonadIO, MonadTrans)


type HearthMonad = MonadIO


runHearth :: (HearthMonad m) => m ()
runHearth = evalStateT (unHearth runGame) mkGameState


mkGameState :: GameState
mkGameState = GameState { _gamePlayers = map mkPlayer ["Bob", "Joe"] }


mkPlayer :: PlayerHandle -> Player
mkPlayer handle = Player { _playerHandle = handle, _hand = [] }


runGame :: (HearthMonad m) => Hearth m ()
runGame = do
    card <- drawCard "Bob"
    liftIO $ print card


getPlayer :: PlayerHandle -> Lens' GameState Player
getPlayer handle f st = fmap put' get'
    where
        players = st^.gamePlayers
        put' player = let
            g p = case p^.playerHandle == handle of
                True -> player
                False -> p
            in set gamePlayers (map g players) st
        get' = f $ fromJust $ find (\p -> p^.playerHandle == handle) players


drawCard :: (HearthMonad m) => PlayerHandle -> Hearth m Card
drawCard handle = do
    let card = Card "Yeti"
    --getPlayer handle.hand <>= [card]
    zoom (getPlayer handle) $ hand <>= [card]
    return card
<小时/>
EngineZoom.hs:86:5:
    Could not deduce (Control.Lens.Internal.Zoom.Zoomed (Hearth m)
                      ~ Control.Lens.Internal.Zoom.Zoomed m0)
    from the context (HearthMonad m)
      bound by the type signature for
                 drawCard :: HearthMonad m => PlayerHandle -> Hearth m Card
      at EngineZoom.hs:82:13-60
    NB: `Control.Lens.Internal.Zoom.Zoomed' is a type function, and may not be injective
    The type variable `m0' is ambiguous
    Relevant bindings include
      drawCard :: PlayerHandle -> Hearth m Card
        (bound at EngineZoom.hs:83:1)
    In the expression: zoom (getPlayer handle)
    In a stmt of a 'do' block:
      zoom (getPlayer handle) $ hand <>= [card]
    In the expression:
      do { let card = Card "Yeti";
           zoom (getPlayer handle) $ hand <>= [card];
           return card }

最佳答案

问题是你的新类型只能保存一种状态,即GameState。缩放本质上是将状态更改为镜头目标,但由于 Hearth 无法将 Player 作为状态,因此 zoom(getPlayer 句柄) 可以“不能与 Hearth 一起使用。

简单的解决方案是将 newtype 替换为 type Hearth = StateT GameState 并进行缩放。如果您想要一个新类型,您需要将状态参数化,下面是一个示例:

import Control.Lens.Internal.Zoom

newtype HearthS s m a = Hearth {
    unHearth :: StateT s m a
} deriving (Functor, Applicative, Monad, MonadState s, MonadIO, MonadTrans)

type Hearth = HearthS GameState

type instance Zoomed (HearthS s m) = Focusing m
instance Monad z => Zoom (HearthS s z) (HearthS t z) s t where
  zoom l (Hearth m) = Hearth (zoom l m)

关于haskell - 镜头变焦模糊变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29188217/

相关文章:

haskell - 为什么镜头包含用于 fromEnum/toEnum 的 Iso,而不包含用于显示/读取的 Iso?

haskell - 如何为所有包自定义 Haddock 文档生成?

Haskell:类型类和实例(不在范围内:数据构造函数..)

haskell - 用于平衡二叉树根的单通透镜

haskell - 棱镜或仿射遍历的对偶是什么?

haskell - `<<%~` 的类似物不需要 Monoid 进行遍历

string - Haskell:从字符串列表中删除空格

haskell - gtk 和 gtk2 之间的区别

haskell - 函数变量和应用中的 ()

Haskell 透镜 setter/getter ,比较两个透镜 setter/getter 的值