2017-05-19 7 views
2

Ich habe eine einfache Art und Funktion unten, aber scheint eine Menge Standard dort, so Wunder, gibt es einen besseren Weg, es zu tun. Meine eigentliche Frage ist, wenn ich weiß, dass die Eingabe vom Typ Fähigkeit ist, also irgendeine der Str/Dex usw., was ist der einfachste Weg, die Ganzzahl daraus zu extrahieren, ohne dass Muster mit jedem übereinstimmen?Haskell Constructor Typ Pattern Matching

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) 

Danke, //

+0

Sie könnten ableiten auch 'Functor' . – Reactormonk

+0

du willst also den Fähigkeitstyp abbilden? – pip

+0

Eine andere Option ist 'wo m = Modifikator 's. Am Ende des Blockes. Kombiniere es mit 'wo a = Fähigkeit 's' und zumindest verschiebst du das Boilerplate in Utility-Funktionen, die nur einmal geschrieben werden müssen. – Davislor

Antwort

3

Normalerweise, wenn Sie eine Datenstruktur haben, wo jeder möglicher Konstruktor ein Feld hat, die die gleiche semantische Bedeutung hat, können Sie Datensatz Syntax, verwenden und damit das Kind einer geben Name:

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

Das schöne daran ist, Sie automatisch eine Funktion abilityValue :: Ability -> Integer aufgebaut haben, die so hat Zugang zu diesem Feld.

Als nächstes können wir einfach schreiben:

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

Es gibt natürlich einige Mühe in die Namen der Felder angibt, aber wenn diese Werte eine „ähnliche semantische Bedeutung“ haben, dann wird es in der Regel zahlen aus, da Sie einen "Getter" eingeführt haben (und Sie können die Notation für "Setter" verwenden).

+0

so einfach, aber nie in den Sinn gekommen. Vielen Dank. – pip

+0

vielleicht aus dem Thema, hat Lens etwas damit zu tun? Ich frage, weil du Getter/Setter erwähnt hast. Ich mag deine Antwort viel – pip

11

Können Sie den Datentyp umgestalten?

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

setModifier würde die gleiche Definition wie Willem Van Onsem haben.

+0

Danke für die Antwort! Aus irgendeinem Grund habe ich die Aufzeichnungssyntax dafür vermieden, aber ich sollte dies mit Sicherheit neu bewerten. – pip

+4

Die Schlüsselverbesserung hier ist überhaupt keine Datensatzsyntax, aber das Ausschließen der vielen doppelten Ganzzahlfelder in verschiedenen Konstruktoren, um alle innerhalb desselben Konstruktors mit einem anderen Feld zu sein, das den AbilityType angibt. – amalloy

+3

Ohne Record-Syntax sind 'data Ability = AbilityAbilityType Integer' und' setModifier a @ (Ability _ v) = (a, Modifier $ modifier 'v) 'schon Welten besser als dein Original. –

2

Beantwortung der Kommentar-Frage zu Lens mit (mit Microlens-Plattform in dieser Antwort, aber für diese Operationen seines exakt die gleiche Code wie Voll Objektiv mit kleineren Abhängigkeiten):

{-# 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)