我下面有一个简单的类型和功能,但在那里看起来很多样板,所以奇怪有更好的方法来做到这一点。我想我真正的问题是,如果我知道输入是类型的能力,那么任何一个Str / Dex等,从中提取整数的最简单方法是什么,没有模式匹配它们中的每一个?
data Ability = StrAbi Integer
| DexAbi Integer
| ConAbi Integer
| IntAbi Integer
| WisAbi Integer
| ChaAbi Integer
deriving (Show)
data Modifier = Modifier Integer deriving (Show)
setModifier :: Ability -> (Ability, Modifier)
setModifier abi@(StrAbi s) = (abi, Modifier $ modifier' s)
setModifier abi@(DexAbi s) = (abi, Modifier $ modifier' s)
setModifier abi@(ConAbi s) = (abi, Modifier $ modifier' s)
setModifier abi@(IntAbi s) = (abi, Modifier $ modifier' s)
setModifier abi@(WisAbi s) = (abi, Modifier $ modifier' s)
setModifier abi@(ChaAbi s) = (abi, Modifier $ modifier' s)
谢谢, //
答案 0 :(得分:13)
你能重构数据类型吗?
data Ability = Ability { abilityType :: AbilityType, abilityValue :: Integer }
data AbilityType = Str | Dec | Con | Int | Wis | Cha
setModifier
与Willem Van Onsem的定义相同。
答案 1 :(得分:3)
通常,如果您有一个数据结构,其中每个可能的构造函数都有一个具有相同语义含义的字段,您可以使用记录语法,从而为该子项命名:
data Ability = StrAbi { abilityValue :: Integer }
| DexAbi { abilityValue :: Integer }
| ConAbi { abilityValue :: Integer }
| IntAbi { abilityValue :: Integer }
| WisAbi { abilityValue :: Integer }
| ChaAbi { abilityValue :: Integer }
deriving (Show)
好消息是,自动构建了一个函数abilityValue :: Ability -> Integer
,因此可以访问该字段。
接下来我们可以简单地写一下:
setModifier :: Ability -> (Ability, Modifier)
setModifier abi = (abi, Modifier $ modifier' $ abilityValue abi)
指定字段的名称当然有一些努力,但如果这些值具有“类似的语义”,那么它通常会因为你引入了“getter”而得到回报(并且您可以对“setter”使用记录表示法。)
答案 2 :(得分:2)
回答关于使用Lens的评论问题(在这个答案中使用MicroLens平台,但对于这些操作,其代码与完整镜头具有较小依赖性的完全相同):
{-# LANGUAGE TemplateHaskell #-}
import Lens.Micro.Platform
data Ability
= StrAbi { _abilityValue :: Integer }
| DexAbi { _abilityValue :: Integer }
| ConAbi { _abilityValue :: Integer }
| IntAbi { _abilityValue :: Integer }
| WisAbi { _abilityValue :: Integer }
| ChaAbi { _abilityValue :: Integer }
deriving (Show)
makeLenses ''Ability
-- Just some examples
getAbilityValue :: Ability -> Integer
getAbilityValue ab = ab ^. abilityValue
setAbilityValue :: Ability -> Integer -> Ability
setAbilityValue ab val = ab & abilityValue .~ val
modifyAbilityValue :: Ability -> (Integer -> Integer) -> Ability
modifyAbilityValue ab f = ab & abilityValue %~ f
-- Edit after reading the question instead of just the comment:
data Modifier = Modifier Integer deriving (Show)
setModifier :: Ability -> (Ability, Modifier)
setModifier ab = (ab,Modifier (ab ^. abilityValue))
-- or import Control.Arrow and
-- setModifier = id &&& Modifier . (^. abilityValue)