Haskell构造函数类型模式匹配

时间:2017-05-19 21:15:35

标签: haskell

我下面有一个简单的类型和功能,但在那里看起来很多样板,所以奇怪有更好的方法来做到这一点。我想我真正的问题是,如果我知道输入是类型的能力,那么任何一个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)

谢谢, //

3 个答案:

答案 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)