2014-06-15 67 views
3

我已經搜索並搜索了以下內容,特別是堆棧溢出和Google中的一般情況。如果它已經覆蓋或如此微不足道,以至於無法在任何地方提及,我對此表示歉意。訪問自定義Haskell數據類型的函數

我已經對於那些有時離散,有時連續的,像這樣的對象定義的自定義數據類型:

data Gene = Discrete String Int | Continuous String Double 
       deriving (Eq, Show, Read, Ord) 

這裏,串表示的基因(例如,vWF的或一些這樣的)和名稱數值參數是它的狀態,無論是離散的或連續的,像這樣:

bober = Discrete "vWF" 2 
slick = Continuous "gurg" 0.45432 

我可以使用記錄語法來訪問一個基因的性質,但也有許多對名稱和狀態2種不同的功能。我想要的是訪問身份的功能之一,以及訪問狀態的功能之一。對於身份,這很簡單,因爲這是兩個值構造一個字符串:

geneName :: Gene -> String 
geneName (Discrete dName _) = dName 
geneName (Continuous cName _) = cName 

當我試圖使返回一個基因的狀態,儘管一個功能,我遇到了麻煩。我以爲模式匹配會的工作:

geneState :: Num a => Gene -> a 
geneState (Discrete _ dState) = dState 
geneState (Continuous _ cState) = cState 

這未能在GHCI加載,並提供:

DynamicalModularity.hs:34:35: 無法比擬Int' with型雙師型」 預期類型:一個 實際類型:雙 在表達式:cState 在用於`geneState'的等式: geneState(連續_ cState)= cState 失敗,加載的模塊:無。

我嘗試使用case語法:

geneState :: Num a => Gene -> a 
geneState gene = case gene of (Discrete _ dState) -> dState 
           (Continuous _ cState) -> cState 

同樣,這並不負荷:

DynamicalModularity.hs:30:56: 無法匹配類型Int' with雙人」 預期類型:a 實際類型:雙倍 在表達式中:cState 在一個替代案例中:(Continuous _ cSt (連續_cState) - > cState} 失敗,已加載模塊:無。在下列表達式中: 病例基因爲{ (Discrete_dState) - > dState (Continuous_cState) - > cState} 失敗,模塊加載:無。

我的問題是:我想要做什麼和/或好的Haskell?我錯過了明顯的東西嗎?我一直在尋找解決方案。任何幫助將不勝感激。

+0

你會如何預期使用'geneState'? –

+0

也許你認爲'Num a => Gene - > a'的意思是「這個函數返回某種數字,這取決於我們提供的Gene值。它不是。 Haskell中沒有這樣的事情。 –

+2

GHC Haskell中有這樣的事情(存在),但我想在推薦它們之前更好地理解這個問題。 –

回答

4

任何代碼,這將消耗呼籲geneState將需要能夠同時處理IntDouble -clearly是這樣的話,因爲我可以呼籲離散和連續值geneState的結果。

讓我們來代表這個代碼中分別使用IntDouble的部分。這兩部分必須是簡單的功能,所以我們可以把它們寫成

intConsumer :: Int -> result 
doubleConsumer :: Double -> result 

現在我有這兩個部分的返回相同的結果,因爲消費代碼總是返回同樣的事不管是否接收到離散的或連續的Gene。現在

,我們可以利用這些信息和模式匹配,我們可以簡化這個功能

geneState :: (Int -> result) -> (Double -> result) -> Gene -> result 
geneState intConsumer doubleConsumer (Discrete _ st) = intConsumer st 
geneState intConsumer doubleConsumer (Continuous _ st) = doubleConsumer st 

一種方法是假設所有的消費者功能上Double的神妙,即使寫geneState輸入Gene是離散的。這在數學上是合理的,因爲Double包含所有的Int egers(如果你願意,可以更正式)。

在Haskell中,函數fromIntegralInt s轉換爲其他數字類型。我們可以這樣寫

geneStateAsDouble :: Gene -> Double 
geneStateAsDouble = geneState fromIntegral id 
+5

值得注意的是,這僅僅是'Either'的教會表示和從'Gene'到'Either'的健忘地圖。 – jozefg

+2

謝謝。你的迴應讓我更多地思考了會消耗這個功能的結果。這種情況下,代碼背後的建模在連續的情況下將會完全不同,所以消費者也會產生不同的東西,這意味着我可能應該爲每個東西都有不同的訪問函數,甚至放棄連續和離散的想法完全相同類型的基因。 – GreenQuestor