本文介绍了镜头变焦暧昧变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难使用由 Control.Lens 给出的缩放函数。使用我自定义的monad变换器 HearthMonad ,我无法弄清楚如何满足GHC的模棱两可的类型的投诉。

有问题的代码位于 drawCard 中。



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

$中的 Monad m b
$ b


  { - #LANGUAGE Con​​straintKinds# - } 
{ - #LANGUAGE GeneralizedNewtypeDeriving# - }
{ - #LANGUAGE MultiParamTypeClasses# - }
{ - #LANGUAGE RankNTypes# - }
{ - #LANGUAGE TemplateHaskell# - }


module EngineZoom其中


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


导入Control.Applicative
导入Control.Lens
导入Control.Monad.State
导入Data.List
导入Data.Maybe


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


类型PlayerHandle =字符串


数据卡=卡片字符串
派生(Show,Eq,Ord)


data Player = Player {
_playerHandle :: PlayerHandle,
_hand :: [Card]
}派生(Show,Eq,Ord)
makeLen ses''Player


数据GameState = GameState {
_gamePlayers :: [Player]
}派生(Show,Eq,Ord)
makeLenses' 'GameState


newtype Hearth ma = Hearth {
unHearth :: StateT GameState ma
}派生(Functor,Applicative,Monad,MonadState GameState,MonadIO,MonadTrans)


类型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 = []}

$ b $ runGame ::(HearthMonad m)=> Hearth m()
runGame = do
card< - drawCardBob
liftIO $打印卡


getPlayer :: PlayerHandle - > Lens'GameState Player
getPlayer handle f st = fmap put'get'
where
players = st ^ .gamePlayers
put'player = let
gp = case p ^ .playerHandle ==
的句柄True - >玩家
错误 - > p
在设置gamePlayers(地图g玩家)st
get'= f $ fromJust $ find(\ p - > p ^ .playerHandle ==句柄)玩家


drawCard ::(HearthMonad m)=> PlayerHandle - > Hearth m Card
drawCard handle = do
let card = CardYeti
--getPlayer handle.hand<> = [card]
zoom(getPlayer handle)$手牌<> = [卡牌]
退货卡牌






  EngineZoom.hs:86:5:
无法推论(Control.Lens.Internal.Zoom.Zoomed(Hearth m)
〜Control。 Lens.Internal.Zoom.Zoomed m0)
来自上下文(HearthMonad m)
由类型签名绑定
drawCard :: HearthMonad m => PlayerHandle - > Hearth m card EngineZoom.hs中的
:82:13-60
注意:`Control.Lens.Internal.Zoom.Zoomed'是一个类型函数,可能不是内注
类型变量`m0'不明确
相关绑定包括
drawCard :: PlayerHandle - > Hearth m Card
(绑定在EngineZoom.hs:83:1)
在表达式中:zoom(getPlayer句柄)
在'do'块的标记中:
zoom (getPlayer handle)$ hand<> = [card]
在表达式中:
do {let card = CardYeti;
zoom(getPlayer handle)$ hand<> = [card];
return card}


解决方案

newtype只能保存一个状态,即 GameState 。缩放本质上改变了镜头的目标,但是因为 Hearth 不能有 Player 作为状态,所以 zoom(getPlayer handle)不能与 Hearth 一起使用。

类型Hearth = StateT GameState 替换newtype,然后缩放。如果你想要一个新类型,你需要参数化状态,这里是一个例子:

  import Control.Lens.Internal。缩放

新类型HearthS sma =炉边{
unHearth :: StateT sma
}派生(Functor,Applicative,Monad,MonadState,MonadIO,MonadTrans)

类型Hearth = HearthS GameState

类型实例缩放(HearthS sm)=聚焦m
实例Monad z => Zoom(HearthS s z)(HearthS t z)s t其中
zoom l(Hearth m)= Hearth(zoom l m)


I'm having difficulty using the zoom function given by Control.Lens. With my custom monad transformer HearthMonad, I cannot figure out how to satisfy GHC's "ambiguous type" complaint.

The code in question is in drawCard.

How can I solve this? Do I have to create my own custom zoom operator to handle the Monad m in Hearth 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 }
解决方案

The problem is your newtype can only hold one state, namely GameState. Zoom essentially changes the state to the target of your lens, but since Hearth cannot have Player as a state, zoom (getPlayer handle) can't be used with Hearth.

The simple solution is to replace the newtype with type Hearth = StateT GameState and zooming works. If you want a newtype you'll need to have the state parameterised, here's an example:

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)

这篇关于镜头变焦暧昧变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-27 16:47