简体   繁体   English

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

[英]Haskells data types and constructors with functions?

I'm new to Haskell and I'm looking at basic data types and constructors with functions. 我是Haskell的新手,正在研究基本数据类型和具有函数的构造函数。

I've done the below code: 我已经完成了以下代码:

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

Runs fine, however it seems overly verbose -- how can I make to make it better? 运行良好,但是似乎太冗长了-我如何使它变得更好?

Most of your data declarations can probably be simple type aliases. 您的大多数data声明都可能是简单的type别名。

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

With these aliases, there is no significant difference (record syntax aside) between the two constructors for DataSubject . 使用这些别名, DataSubject的两个构造函数之间没有显着差异(除了记录语法)。 Get rid of one, and dispense with makeDataSubject . 摆脱一个,并省去makeDataSubject (Unless you want to encapsulate some logic or prevent pattern matching, you don't need a smart constructor to do what you are doing.) (除非您希望封装一些逻辑或防止模式匹配,否则您不需要智能构造函数即可执行操作。)

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

If you do want real types, not just aliases, use newtype instead of data . 如果确实需要实类型,而不仅仅是别名,请使用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

You might want to add a smart constructor here, but have it take each piece of data as a separate argument (wrapped or unwrapped), not a single argument that is already the return value up to isomorphism. 您可能想在此处添加一个智能构造函数,但要让它把每条数据作为一个单独的参数(包装的或展开的),而不是一个已经是同构的返回值的参数。 (That is, your constructor was essentially the identity function other than some repackaging of the input.) (也就是说,您的构造函数本质上是身份函数,而不是对输入进行一些重新包装。)

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

or 要么

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

Unfortunately you are running into one of Haskell's weaknesses: the record system. 不幸的是,您遇到了Haskell的弱点之一:记录系统。 It would be nice if we had some sort notation to express subject.name and subject.age rather than destructuring explicitly but right now there is no good answer. 如果我们有某种表示法来表示subject.namesubject.age而不是显式地进行销毁,那将是很好的选择,但是现在没有很好的答案。 Work coming down the pipeline in GHC 8 should address the problem soon, however, and there are are all sorts of libraries working in the problem space. 但是,GHC 8中即将进行的工作应该尽快解决该问题,并且在问题空间中有各种各样的库正在工作。 But, for this question specifically, we can employ a simple trick: -XRecordWildcards . 但是,对于这个问题,我们可以采用一个简单的技巧: -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")

By destructuring into the names of the fields, {..} will pick up on those bindings in scope to automatically populate the fields. 通过分解为字段的名称, {..}将选择范围内的那些绑定以自动填充字段。 You will absolutely want to turn on -Wall -Werror during compilation because it will be now more than ever easier to misspell something and forget to populate a field and then you end up with a partial record (another wart of the records system) where some fields are left undefined . 绝对希望在编译期间打开-Wall -Werror ,因为现在比以往任何时候都更容易拼写错误并忘记填充字段,然后最终得到部分记录(记录系统的另一个缺陷)字段undefined

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM