问题描述
我很难使用由 Control.Lens
给出的缩放
函数。使用我自定义的monad变换器 HearthMonad
,我无法弄清楚如何满足GHC的模棱两可的类型的投诉。
有问题的代码位于 drawCard
中。
我该如何解决这个问题?我是否必须创建自己的自定义缩放操作符来处理 Hearth m
?
Monad m
b $ b
{ - #LANGUAGE ConstraintKinds# - }
{ - #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)
这篇关于镜头变焦暧昧变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!