2013-03-31 56 views
9

我是一個相當新的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 

我在想什麼?

回答

16

最直接的方式就是手工做:

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 

然而,有一個稍微性感的方式,這是由元素,這是容易出錯少,更多的描述來解析這些元素什麼,我們正在嘗試做的:

首先,我們定義兩個解析器,其中一個從列表中請求新的元素(或者如果列表是空的失敗),且其列表的末尾(匹配第二或者如果列表不爲空,則失敗):

import Control.Applicative 
import Control.Monad 
import Control.Monad.Trans.State 

getElem :: StateT [Double] Maybe Double 
getElem = do 
    s <- get 
    case s of 
     [] -> mzero 
     x:xs -> do 
      put xs 
      return x 

endOfList :: StateT [Double] Maybe() 
endOfList = do 
    s <- get 
    case s of 
     [] -> return() 
     _ -> mzero 

現在,我們可以在應用型風格定義fromList

fromList' :: [Double] -> Maybe OrbitElements 
fromList' = evalStateT $ OrbitElements 
    <$> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <*> getElem 
    <* endOfList 
+1

謝謝定義fromList,這證實了我的懷疑,並啓動了任何回答「首先,我們定義兩個解析器......「在我的書中很棒:) –

+4

與['-XRecordWildCards'](http://www.haskell.org/ghc/docs/7.4)結合使用時,」手動「 .2/html/users_guide/syntax-extns.html#record-wildcards):'fromList [epoch,ecc,distPeri, incl,longAscNode,argPeri,timePeri,meanMotion,meanAnomaly,trueAnomaly,semiMajorAxis,distApo,period] = Just OrbitElements {..}'。 –

5

你錯過了Haskell是靜態類型的事實。不,Haskell沒有任何這樣的構造。

讓我們假設語言有一些方法來填充列表中的構造函數值。以下是一些需要考慮的問題:

  • 如果列表包含的項目多於或少於所需項目,會發生什麼情況?
  • 你將如何初始化其字段不是統一鍵入的記錄?
2

代數數據類型意味着一次性初始化,而不是像你一樣在某個時間進行一次字段的初始化。要做到這一點,正確的方法是:

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設置任何值。 let epoch o = d !! 0定義了一個名爲epoch的函數,它將字段epoch的定義屏蔽爲一個字段(您應該始終編譯時啓用警告,以便編譯器可以捕捉像這樣的內容),並且此新函數可以使用任何值o(而不僅僅是之前定義的OrbitElements)並返回d !! 0而根本沒有用o做任何事情。如果您確實想要設置或更改的epoch字段,則正確的方法是let o' = o {epoch = d !! 0},該對象將返回一個新的OrbitElements對象,其epoch字段已更改。

11

一個somwhat醜陋的解決方案...:-o

讓你的類型派生Read

data OrbitElements = OrbitElements { ... } 
         deriving (Read) 

然後你就可以通過

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

這真的很聰明! –

+2

一些愚蠢的風格筆記:帶'intersperse'的'concat'與'intercalate'相同。 「插入」「」與「unwords」相同。所以你可以把你的定義的第二部分改寫爲'unwords $ map show ds'。 –

+1

因此,'fromList ds = read $「OrbitElement」++(unwords $ map show ds)'。也許,需要編寫'Data.List.unwords'。 – md2perpe

相關問題