2017-06-02 33 views
0

我目前正在通過使用該庫編寫一些簡單的函數來學習鏡頭庫。不幸的是,我對生成的編譯器錯誤感到困惑,所以我正在努力確定爲什麼,在函數dmg中,前兩個函數編譯正確,但最後一個失敗。如何正確使用Control.Lens格式化函數?

import Control.Lens 

type Health = Int 
type Damage = Int 

data Card = Card { 
    _health :: Int, 
    _damage :: Int 
} deriving (Show,Eq) 

health :: Lens' Card Health 
health = lens _health (\card h -> card { _health = h }) 
damage :: Lens' Card Damage 
damage = lens _damage (\card d -> card { _damage = d }) 

cardDead :: Card -> Bool 
cardDead c = c^.health <= 0 

duel :: (Card,Card) -> (Card,Card) 
duel (c,c2) = ((dmg c c2),(dmg c2 c)) 

這件事真正的肉。

dmg :: Card -> Card -> Card 
dmg myCard otherCard = over health ((-) (otherCard^.damage)) myCard --compiles 
dmg myCard otherCard = myCard & health %~ ((-) (otherCard^.damage)) --compiles 
dmg myCard otherCard = health %~ ((-) (otherCard^.damage)) myCard --compile error 

我的問題分三部分。

  1. 爲什麼第三個dmg函數無法編譯?

  2. 我該怎麼寫dmg仍然使用(%~)運算符,而不是使用(&),仍然編譯?

  3. 什麼是最美麗,最習慣的鏡頭寫作方式dmg

-

僅供參考,這裏是你可能會寫DMG不帶鏡頭的一種方式

dmg myCard otherCard = 
    let 
     damageTaken = _damage otherCard 
     oldHealth = _health myCard 
     newHealth = oldHealth - damageTaken 
    in myCard {_health = newHealth} 

編輯:供參考,在這裏是我遇到了麻煩與理解錯誤信息(錯誤地寫)行3.

*Main GHC.Arr Control.Applicative Control.Lens> :l Doom.hs 
[1 of 1] Compiling Main    (Doom.hs, interpreted) 

Doom.hs:26:24: 
    Couldn't match expected type `Card' with actual type `Card -> Card' 
    In the expression: health %~ ((-) (otherCard ^. damage)) myCard 
    In an equation for `dmg': 
     dmg myCard otherCard = health %~ ((-) (otherCard ^. damage)) myCard 

Doom.hs:26:51: 
    Couldn't match type `Health -> Health' with `Int' 
    Expected type: Getting (Health -> Health) Card (Health -> Health) 
     Actual type: (Damage -> Const (Health -> Health) Damage) 
        -> Card -> Const (Health -> Health) Card 
    In the second argument of `(^.)', namely `damage' 
    In the first argument of `(-)', namely `(otherCard ^. damage)' 

Doom.hs:26:60: 
    Couldn't match expected type `Health -> Health' 
       with actual type `Card' 
    In the second argument of `(-)', namely `myCard' 
    In the second argument of `(%~)', namely 
     `((-) (otherCard ^. damage)) myCard' 
Failed, modules loaded: none. 
Prelude GHC.Arr Control.Applicative Control.Lens> 
+1

如果你要談論「混淆編譯錯誤」,你應該真的包括它們。 – Carl

+0

好點。下面的答案非常完美,但後人生病包括我編寫P3的錯誤。 – SolventGren

回答

3
  1. 因爲解析規則。您的代碼是

    abc = def %~ ghi jkl 
    

    功能應用結合比任何綴操作更緊密的形式,所以這被分析爲

    abc = def %~ (ghi jkl) 
    

    即什麼其他的語言會寫def %~ ghi(jkl)

  2. 您想改爲(def %~ ghi) jkl。這通常用在Haskell $完成,即

    dmg myCard otherCard = health %~ ((-) (otherCard^.damage)) $ myCard 
    
  3. 首先我要消除不必要的括號內。操作者部分通常比更好綴施加到表達式,即

    dmg myCard otherCard = health %~ ((otherCard^.damage) -) $ myCard 
    

    ...其中內括號可省略由於

    Prelude> :info Control.Lens.^. 
    ... 
    infixl 8 Control.Lens.Getter.^. 
    Prelude> :i - 
    ... 
    infixl 6 - 
    

    ^.結合不同於-更緊密無論如何,給出

    dmg myCard otherCard = health %~ (otherCard^.damage -) $ myCard 
    

    接下來,我會嘗試η減少。

    dmg otherCard myCard = health %~ (otherCard^.damage -) $ myCard 
    dmg otherCard = health %~ (otherCard^.damage -) 
    

    而這可能是最優雅的解決方案:如果參數交換,這可能是更哈斯克爾,地道參數順序這會很容易。

也就是說,假設你的代碼實際上是正確的。我不知道dmg應該做什麼,但更常見的情況是你想從你的牌中減去其他牌的傷害。即基本上不是(otherCard^.damage -),而是(- otherCard^.damage),除了解析爲一元減號,因此需要寫入subtract (otherCard^.damage)。鏡頭有專門的加法和減法操作,給你

dmg otherCard = health -~ otherCard^.damage 
+0

謝謝,很好的答案。 – SolventGren

相關問題