具有函数的Haskells数据类型和构造函数?

时间:2016-09-09 17:07:58

标签: haskell types

我是Haskell的新手,我正在研究具有函数的基本数据类型和构造函数。

我已完成以下代码:

data Name = Name String deriving (Show)
data Age = Age Int deriving (Show)
data Iq = Iq Int deriving (Show)
data Language = Language String deriving (Show)
data DataSubject = DSInformation Name Age Iq Language | DSConstruct {name :: String, age :: Int, iq :: Int, language :: String} deriving (Show)

makeDataSubject :: DataSubject -> DataSubject --Take in info and output a record
makeDataSubject (DSInformation (Name n) (Age a) (Iq i) (Language l)) = (DSConstruct {name = n, age = a, iq = i, language = l})

main = do 
  let x = makeDataSubject $ (DSInformation (Name "Ron") (Age 34) (Iq 100) (Language "French"))
  putStrLn $ show x

运行良好,但似乎过于冗长 - 我怎样才能让它变得更好?

2 个答案:

答案 0 :(得分:4)

您的大多数data声明可能都是简单的type别名。

type Name = String
type Age = Int
type Iq = Int
type Language = String

使用这些别名,DataSubject的两个构造函数之间没有显着差异(记录语法除外)。摆脱一个,省去makeDataSubject。 (除非您想要封装某些逻辑或阻止模式匹配,否则您不需要智能构造函数来执行您正在执行的操作。)

data DataSubject = DS { name :: Name
                      , age :: Age
                      , iq :: Iq
                      , language :: Language
                   } deriving (Show)

main = do 
        let x = DS { name="Ron", age=34, iq=100, language="French"}
        putStrLn $ show x

如果您确实需要真实类型,而不仅仅是别名,请使用newtype代替data

newtype Name = Name String deriving Show
newtype Age = Age Int deriving Show
newtype Iq = Iq Int deriving Show
newtype Language = Language String deriving Show

data DataSubject = DS { name :: Name
                      , age :: Age
                      , iq :: Iq
                      , language :: Language
                      } deriving (Show)

main = do
         let x = DS { name=Name "Ron", age=Age 34, iq=Iq 100, language=Language "French"}
         putStrLn $ show x

你可能想在这里添加一个智能构造函数,但是它将每个数据作为一个单独的参数(包装或解包),而不是一个已经是同构的返回值的参数。 (也就是说,除了重新打包输入之外,你的构造函数本质上是身份函数。)

makeDataSubject :: String -> Int -> Int -> String -> DataSubject
makeDataSubject name age iq lang = DS {name=Name name, age=Age age, iq=Iq iq, language=Language lang}

makeDataSubject' :: Name -> Age -> Iq -> Language -> DataSubject
makeDataSubject' name age iq lang = DS {name=name, age=age, iq=iq, language=lang}

答案 1 :(得分:1)

不幸的是,你遇到了Haskell的一个弱点:记录系统。如果我们有一些符号来表达subject.namesubject.age而不是明确地解构,那将是很好的,但现在没有好的答案。然而,GHC 8中的工作应该很快就会解决这个问题,并且有各种各样的库在问题空间中工作。但是,对于这个问题,我们可以采用一个简单的技巧:-XRecordWildcards

{-# LANGUAGE RecordWildCards #-}

module Main where

newtype Name = Name String deriving Show
newtype Age = Age Int deriving Show
newtype Iq = Iq Int deriving Show
newtype Language = Language String deriving Show

data DataSubject =
    DSInformation Name Age Iq Language
  | DSConstruct {name :: String, age :: Int, iq :: Int, language :: String}
  deriving Show

-- | Take in info and output a record
makeDataSubject :: DataSubject -> DataSubject
makeDataSubject (DSInformation (Name name) (Age age) (Iq iq) (Language language)) =
  DSConstruct {..}

main :: IO ()
main =
  print . makeDataSubject $ DSInformation (Name "Ron") (Age 34) (Iq 100) (Language "French")

通过对字段名称进行解构,{..}将获取范围内的那些绑定以自动填充字段。您将绝对想要在编译期间打开-Wall -Werror因为现在比以往更容易拼错一些东西而忘记填充字段然后最终得到部分记录(另一个记录系统的疣)其中一些字段留有undefined