List 从列表初始化代数数据类型

List 从列表初始化代数数据类型,list,haskell,algebraic-data-types,List,Haskell,Algebraic Data Types,我是一个相当新的Haskell程序员,我正试图找出如何将一些值转换成代数数据类型 我有一个记录数据类型: data OrbitElements = OrbitElements { epoch :: Double, ecc :: Double, distPeri :: Double,

我是一个相当新的Haskell程序员,我正试图找出如何将一些值转换成代数数据类型

我有一个记录数据类型:

data OrbitElements = OrbitElements { epoch :: Double,
                                     ecc :: Double,
                                     distPeri :: Double,
                                     incl :: Double,
                                     longAscNode :: Double,
                                     argPeri :: Double,
                                     timePeri :: Double,
                                     meanMotion :: Double,
                                     meanAnomaly :: Double,
                                     trueAnomaly :: Double,
                                     semiMajorAxis :: Double,
                                     distApo :: Double,
                                     period :: Double
                                   }
我从一个文本文件中提取了一些信息,最后出现在一个双倍列表中。是否有一种简单的方法可以使用列表初始化此数据类型?我可以单独调用每个setter,但当我已经有了列表中的所有值时,这似乎非常低效

let d = [2456382.5,6.786842103348031e-3,0.7184187640759256,3.394660181513041,76.64395338801751,55.2296201483587,2456457.141012543,1.602144936476915,240.4142797010899,239.7408018186761,0.7233278761603762,0.7282369882448266,224.6987721295883]
let o = OrbitElements
let epoch o = d !! 0
let ecc o = d !! 1
-- and so on

我遗漏了什么?

您遗漏了Haskell是静态类型的事实。不,Haskell没有这样的构造

让我们假设该语言有某种方法来填充列表中的构造函数值。以下是一些需要思考的问题:

  • 如果列表中包含的项目多于或少于所需的项目,会发生什么情况
  • 如何初始化字段类型不统一的记录

代数数据类型意味着一次初始化所有数据类型,而不是像您这样一次初始化一个字段。正确的方法是:

let d = ...
let o = OrbitElements {epoch = d !! 0
                       ecc = d !! 1,
                       distPeri = d !! 2,
                       incl = d !! 3,
                       longAscNode = d !! 4,
                       argPeri = d !! 5,
                       timePeri = d !! 6,
                       meanMotion = d !! 7,
                       meanAnomaly = d !! 8,
                       trueAnomaly = d !! 9,
                       semiMajorAxis = d !! 10,
                       distApo = d !! 11,
                       period = d !! 12}

请注意,您这样做的方式实际上并不是在
o
中设置任何值<代码>让历元o=d!!0定义了一个名为
epoch
的函数,该函数将
epoch
的定义屏蔽为一个字段(您应该始终在启用警告的情况下编译,以便编译器捕获类似的内容),并且这个新函数接受任何值
o
(不仅仅是先前定义的
元素)并返回
d!!0
而不使用
o
执行任何操作。如果您确实想设置或更改
o
epoch
字段,正确的方法是
let o'=o{epoch=d!!0}
,它将返回一个新的
orbielements
对象及其
epoch
字段已更改。

最直接的方法是手动执行:

fromList :: [Double] -> Maybe OrbitElements
fromList [ _epoch
         , _ecc
         , _distPeri
         , _incl
         , _longAscNode
         , _argPeri
         , _timePeri
         , _meanMotion
         , _meanAnomaly
         , _trueAnomaly
         , _semiMajorAxis
         , _distApo
         , _period
         ]
    = Just $ OrbitElements
          _epoch
          _ecc
          _distPeri
          _incl
          _longAscNode
          _argPeri
          _timePeri
          _meanMotion
          _meanAnomaly
          _trueAnomaly
          _semiMajorAxis
          _distApo
          _period
fromList _ = Nothing
然而,有一种稍微性感一点的方法,那就是逐个元素解析它们,这种方法不太容易出错,并且更能描述我们正在尝试做的事情:

首先,我们定义两个解析器,其中一个解析器从列表中请求新元素(如果列表为空,则会失败),第二个解析器与列表末尾匹配(如果列表不为空,则会失败):


一个多么丑陋的解决方案…:-o

使您的类型派生
读取

data OrbitElements = OrbitElements { ... }
                         deriving (Read)
然后,您可以通过以下方式定义
fromList

fromList :: [Double] -> OrbitElements
fromList ds = read $ "OrbitElement " ++ (concat $ Data.List.intersperse " " $ map show ds)

谢谢,这证实了我的怀疑,在我的书中,任何以“首先,我们定义两个解析器…”开头的答案都很好。:“手动”选项与:
fromList[epoch,ecc,distPeri,incl,longasnode,argPeri,timePeri,meanMotion,meannormal,truenormal,semiMajorAxis,distApo,period]=Just-orbielements{..}
。一些愚蠢的风格注释:
concat
with
interspose
interlate
相同
interlate”“
unwords
相同。因此,您可以将定义的第二部分重写为
unwords$map show ds
。因此,
fromList ds=read$“orbielement”+(unwords$map show ds)
。可能需要编写
Data.List.unwords
data OrbitElements = OrbitElements { ... }
                         deriving (Read)
fromList :: [Double] -> OrbitElements
fromList ds = read $ "OrbitElement " ++ (concat $ Data.List.intersperse " " $ map show ds)