2016-04-28 67 views
1

我遇到問題。我有一個數據類型,這本質上是Maybe Doubles或Maybe Texts的大記錄。我想創建一個數據類型,它可以捕獲在其上運行計算的想法,即使某些字段可能爲Nothing。Haskell:適用於元組

data Computation a b = Computation 
    { getInputs :: Thing -> a 
     computation :: a -> b 
     modifyThing :: b -> Thing -> Thing 
    } 

基於輸出B,將最有可能對應於某些事情領域,我想創建一個新的東西。

modifyThing :: b -> Thing -> Thing 

從事物的計算來也許B可以被分成兩個部分,裝載變量和剛剛接受數字或文字的計算。

getInputs :: Thing -> a 

computation :: a -> b 

以上幾乎是我想要的。在這種情況下,a會是(也許a1,也許a2 ..)等等。這意味着,在「計算」和getInputs 我必須做一些像

getInputs t = \t -> (getProp1 t , getProp2 t) 

computation = \(m_a1, m_a2) -> do 
    a1 <- m_a1 
    a2 <- m_a2 
    return $ a1 + a2 

我寧願有計算只是看起來像

,然後像做

runComputation :: Thing -> Computation -> b 
runComputation thing comp = magic (computation comp) ((getInputs comp) thing) 
    where magic = ??? 

問題是我不知道該怎麼辦從

(Maybe a1, Maybe a2, ... , Maybe a_n) 

a1 -> a2 -> ... -> a_n 

如果有任何可能的是沒有那麼就返回Nothing。我能做

pure computation <*> m_a1 <*> m_a2 <*> m_a3 

但我怎麼能寫魔術工作的任何類型的元組?

P.S.

我考慮寫計算爲

computation :: Thing -> b 

與getInputs做了,但現在看來,這將更加unweildy 對我來說,測試和玩耍。這就是爲什麼我試圖採用我上面描述的方法。你認爲這是我做過的一個好主意嗎?

編輯

雖然不是一個解決特定的問題,我問過,但到了什麼,我試圖做的意圖,我決定做

data Computation = Computation 
    { getInputs :: Thing -> Maybe a 
    , computation :: a -> b 
    , modifyThing :: b -> Thing -> Thing 
    } 

將是最好的方式前進。這樣我就不用擔心元組了。

+0

有沒有什麼不能用的,也許是一個列表中的任何原因? – Guvante

+0

@Guvante名單的一個缺點是它們是同質的 - 例如,一個人不能同時挑出一個'Double'-y類型字段和一個'Int'-y類型字段。 –

+0

@ user3550758如果你找到一個解決方案,StackOverflow的方法是把它寫成答案,而不是將其包含在對問題的編輯中。我鼓勵你將你的「編輯」分成它自己的實體 - 如果它是你得到的最好答案,甚至接受它。 (這在這裏被認爲是完全有禮貌的,甚至是可取的。) –

回答

0

我不完全確定使用Computation而不是Thing -> Thing的好處,但您應該能夠相當容易地定義相關函數。首先,您的示例函數computation可以用稍微更方便的形式重寫。(你實際上應該把它稱爲別的,因爲名字computation已經被你的記錄訪問者採用)。

exampleComp :: Num a => (Maybe a, Maybe a) -> Maybe a 
exampleComp (a1, a2) = liftA2 (+) a1 a2 

它還不如普通加法那樣方便,但它接近。您的runComputation函數也非常簡單,因爲它實際上是構成Computation類型的三個組件。或者,用記錄訪問器編寫,它看起來像這樣。

runComputation thing comp = modifyThing comp 
          (computation comp $ getInputs comp thing) 
          thing 

基本上,這個函數使用getInputs提取適當的數據,傳遞該數據computation得到一個新的數據集,然後傳遞modifyThing實際修改的對象。

沒有關於您準備對數據類型做什麼的更多信息,很難說您應該使用哪種方法。就個人而言,我看不出有什麼理由將computationmodifyThing分開,但我真的看不出有什麼理由首先使用Computation。無論如何,CodeReview的問題更多的是StackOverflow。

1

的問題是,我不知道該怎麼做去從

(Maybe a1, Maybe a2, ... , Maybe a_n) 

a1 -> a2 -> ... -> a_n 

類似於十歲上下到uncurry,這需要一個普通的功能,製作一個採用元組而不是多個參數的版本。

uncurry :: (a -> b -> c) -> (a, b) -> c 
uncurry f (a, b) = f a b 

這個特殊的例子:

computation = \(m_a1, m_a2) -> do 
    a1 <- m_a1 
    a2 <- m_a2 
    return $ a1 + a2 

可以與應用型來完成,像這樣

computation (m_a1, m_a2) = (+) <$> m_a1 <*> m_a2 

,但你可以抽象這有點像uncurry這樣的:

uncurryA :: Applicative f => (a -> b -> c) -> (f a, f b) -> f c 
uncurryA f (a, b) = f <$> a <*> b 

允許computation來定義,像這樣:

computation a_b = uncurryA (+) a_b 
+0

'uncurry'只適用於雙參數函數。你可能會做某種遞歸的uncurrying(因爲'uncurry.uncurry',例如,可以把a→a→a→b'變成'((a,a),a) - > b')但是你仍然必須弄清楚如何拼湊結果嵌套元組。 – chepner

+0

(或者更確切地說,'uncurry'一次只能處理前兩個參數,如果'uncurry'被連續多次使用,會導致嵌套元組。 – chepner

相關問題