[英]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.name
和subject.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.