如何正确传递镜头到具有状态的函数中?让我们考虑下一个代码:将镜头传递给函数
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
import Control.Lens
import Control.Monad.State
data Game = Game { _armies :: [Army]
} deriving (Show)
data Army = Army { _troops :: Int
} deriving (Show)
makeLenses ''Game
makeLenses ''Army
data BattleResult = Win | Defeat deriving (Show)
offend offender defender = do
Just ot <- preuse $ offender.troops
Just dt <- preuse $ defender.troops
defender.troops.=0 -- doesn't work
let eval a b
| a >= b = return Win
| otherwise = return Defeat
eval ot dt
game :: State Game()
game = do
armies %= (:) (Army 100)
armies %= (:) (Army 200)
q <- offend (armies.ix 0) (armies.ix 1)
return()
标线引出了下一个错误:
Lens.hs:21:3:
Couldn't match type ‘Const (Data.Monoid.First Int) s’
with ‘Identity s’
Expected type: (Army -> Const (Data.Monoid.First Int) Army)
-> s -> Identity s
Actual type: (Army -> Const (Data.Monoid.First Int) Army)
-> s -> Const (Data.Monoid.First Int) s
Relevant bindings include
defender :: (Army -> Const (Data.Monoid.First Int) Army)
-> s -> Const (Data.Monoid.First Int) s
(bound at Lens.hs:18:17)
offender :: (Army -> Const (Data.Monoid.First Int) Army)
-> s -> Const (Data.Monoid.First Int) s
(bound at Lens.hs:18:8)
offend :: ((Army -> Const (Data.Monoid.First Int) Army)
-> s -> Const (Data.Monoid.First Int) s)
-> ((Army -> Const (Data.Monoid.First Int) Army)
-> s -> Const (Data.Monoid.First Int) s)
-> m BattleResult
(bound at Lens.hs:18:1)
In the first argument of ‘(.)’, namely ‘defender’
In the first argument of ‘(.=)’, namely ‘defender . troops’
Lens.hs:21:12:
Couldn't match type ‘Identity Integer’
with ‘Const (Data.Monoid.First Int) Int’
Expected type: (Int -> Identity Integer)
-> Army -> Const (Data.Monoid.First Int) Army
Actual type: (Int -> Const (Data.Monoid.First Int) Int)
-> Army -> Const (Data.Monoid.First Int) Army
In the second argument of ‘(.)’, namely ‘troops’
In the first argument of ‘(.=)’, namely ‘defender . troops’
如果有类似armies.ix 0.troops.=0
代码通常被编译更换线。是否有一些标准工具可以解决问题?并且可以使用相同的算法而不使用FlexibleContexts
?
'让eval ...'有点奇怪。为什么不跳过那个,只是写'如果a> = b然后返回赢,否则返回失败'? – dfeuer
@dfeuer,如果我需要更多的案例(例如>,<和==),我必须使用这个'let'表达式。你知道还有其他方法在'do'块中执行守卫吗? – Leonid
'_的情况() ......是经典的。 GHC'MultiWayIf'为它提供了更好的语法。 – dfeuer