首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Control.Lens正确格式化函数?

如何使用Control.Lens正确格式化函数?
EN

Stack Overflow用户
提问于 2017-06-02 11:20:55
回答 1查看 70关注 0票数 0

我目前正在学习镜头库,通过使用这个库编写一些简单的函数。不幸的是,我被生成的编译器错误搞糊涂了,所以我很难确定为什么在下面的函数dmg中前两个函数编译正确,但是最后一个函数失败了。

代码语言:javascript
复制
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))

这件事的真谛。

代码语言:javascript
复制
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的方法。

代码语言:javascript
复制
dmg myCard otherCard = 
    let 
        damageTaken = _damage otherCard
        oldHealth = _health myCard
        newHealth = oldHealth - damageTaken
    in myCard {_health = newHealth}

编辑:作为参考,这是我在理解(写错了)第3行时遇到的错误信息。

代码语言:javascript
复制
*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>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-02 12:38:26

  1. 因为解析规则。您的代码是窗体的 abc = def %~ ghi jkl 函数应用程序比任何infix运算符绑定得更紧,因此将其解析为 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 ...where内部父母可以省略,因为 Prelude>:信息控制。镜头。^。..。内定8控制镜头。Prelude>:我.内固定物6- 也就是说,^.-绑定得更紧, dmg myCard otherCard = health %~ (otherCard^.damage -) $ myCard 接下来,我将尝试减少η。如果交换参数,这将很容易,这可能是Haskell-惯用的参数顺序: dmg otherCard myCard = health %~ (otherCard^.damage -) $ myCard dmg otherCard = health %~ (otherCard^.damage -) 这可能是最优雅的解决方案。

也就是说,假设您的代码实际上是正确的。我不知道dmg应该做什么,但是也许更常见的情况是你想从你的卡中减去另一张卡的伤害。也就是说,基本上不是(otherCard^.damage -),而是(- otherCard^.damage),但它被解析为一元减号,因此需要编写subtract (otherCard^.damage)。镜头有专门的加减符,给你

代码语言:javascript
复制
dmg otherCard = health -~ otherCard^.damage
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44327686

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档