2017-05-19 22 views
2

私は単純な型と機能を持っていますが、そこには定型文がたくさんあるようです。私の本当の疑問は、もし入力が能力のタイプであることを知っていれば、Str/Dexのどれかのどれか、パターンマッチなしでIntegerを抽出する最も簡単な方法は何ですか?Haskellコンストラクタ型パターンマッチング

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 [email protected](StrAbi s) = (abi, Modifier $ modifier' s) 
setModifier [email protected](DexAbi s) = (abi, Modifier $ modifier' s) 
setModifier [email protected](ConAbi s) = (abi, Modifier $ modifier' s) 
setModifier [email protected](IntAbi s) = (abi, Modifier $ modifier' s) 
setModifier [email protected](WisAbi s) = (abi, Modifier $ modifier' s) 
setModifier [email protected](ChaAbi s) = (abi, Modifier $ modifier' s) 

おかげで、 //

+0

あなたは 'Functor'をも導き出すことができ。 – Reactormonk

+0

あなたはAbilityタイプをマップすることを意味していますか? – pip

+0

もう一つのオプションは 'm = modifier 'sです。ブロックの終わりに。それを 'where a = ability 'と組み合わせて、少なくともあなたは一度だけ書く必要があるユーティリティ関数に定型文を移動します。 – Davislor

答えて

3

あなたは、可能な各コンストラクタは同じ意味論的意味を持つフィールドを持つデータ構造を持っている通常ならば、あなたはレコード構文を使用するので、その子aを与えることができます名前:あなたは自動的にので、持っている機能abilityValue :: Ability -> Integerを構築した

data Ability = StrAbi { abilityValue ::Integer } 
     | DexAbi { abilityValue ::Integer } 
     | ConAbi { abilityValue ::Integer } 
     | IntAbi { abilityValue ::Integer } 
     | WisAbi { abilityValue ::Integer } 
     | ChaAbi { abilityValue ::Integer } 
     deriving (Show)

素敵な事は、ありますそのフィールドへのアクセス。

次は、単純に書くことができます。

setModifier :: Ability -> (Ability, Modifier) 
setModifier abi = (abi, Modifier $ modifier' $ abilityValue abi)

ありフィールドの名前を指定するにおけるいくつかの努力はもちろんですが、これらの値は、「同様の意味論的な意味」を持っている場合、それは通常支払うことになりますあなたは "ゲッター"を導入しています(そして "セッター"のためにレコード記法を使うことができます)。

+0

シンプルだけど、私の心を越えたことはありません。ありがとう。 – pip

+0

おそらく話題を外していますが、レンズにはこれに関連するものがありますか?あなたがゲッター/セッターについて言及したので私は尋ねています。私はあなたの答えが大好きです – pip

11

データ型をリファクタリングすることはできますか?

data Ability = Ability { abilityType :: AbilityType, abilityValue :: Integer } 
data AbilityType = Str | Dec | Con | Int | Wis | Cha 

setModifierは、ウィレム・ヴァン・オンセムと同じ定義を有する。

+0

答えをありがとう!何らかの理由で私はこれのための記録的な構文を避けていましたが、確かにこれを再評価する必要があります。 – pip

+4

ここで重要な点は、構文の記録はまったくありませんが、異なるコンストラクタ内の多くの重複するIntegerフィールドをすべて、同じコンストラクタ内にあり、AbilityTypeを示す別のフィールドを持つことになります。 – amalloy

+3

これは、レコードの構文がなくても、 'data Ability = AbilityType Integer'と' setModifier a @(Ability _ v)=(a、修飾子$修飾子 'v) 'はすでにあなたのオリジナルよりも優れています。 –

2

(小さい依存関係を完全にレンズとしてその正確な同じコードこの回答では、マイクロレンズ・プラットフォームではなく、これらの操作のための)レンズの使用に関するコメント・質問に答える:

{-# 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) 
関連する問題