2015-09-05 24 views
1

我有以下的數據類型:你怎麼能把這兩個數據類型:`RowF Maybe`和`Maybe(RowF Identity)`放到同一個List中?

data RowF f = RowF { rsidf  :: f String 
        , rtimef :: f Double 
        } 

type Row = RowF Identity 


realizeRow :: RowF Maybe -> Maybe Row 

,我想有兩個和RowF Maybe的列表。也就是說我可能有:

[RowF (Maybe "hello") Nothing, Maybe (RowF "world" 12.3)] 

有人建議我應該實現一些功能:

f :: (forall x. f x -> g x) -> RowF f -> RowF g 

但我不知道這是什麼意思做或者如何實現它。

+1

爲什麼要這樣?這些「可能」中的一些應該是「只是」嗎? – dfeuer

+1

爲了澄清@dfeuer在說什麼......爲什麼你想要一個包含'RowF Identify'和'RowF Maybe'值的列表?向我們展示一些您想要編寫的示例代碼,如果您可以構建這樣的列表。 – ErikR

回答

2

有幾個解決方案。

你可以使用Either來包裝兩種類型:

ghci> let rm = RowF (Just "hello") Nothing :: RowF Maybe 
ghci> let mr = Just (RowF (Identity "world") (Identity 12.3)) :: Maybe Row 
ghci> :t [ Left rm, Right mr ] 
[ Left rm, Right mr ] :: [ Either (RowF Maybe) (Maybe Row) ] 

或者,你可以創建一些功能來來回轉換

toRow :: Applicative f => RowF f -> f Row 
toRow (RowF fs fd) = (\s d -> RowF (Identity s) (Identity d)) <$> fs <*> fd 

fromRow :: Functor f => f Row -> RowF f 
fromRow fr = RowF (runIdentity . rsidf <$> fr) (runIdentity . rtimef <$> fr) 

然後就轉化爲一種其他的需要。

ghci> :t [ rm, fromRow mr ] 
[ rm, fromRow mr ] :: [RowF Maybe] 
ghci> :t [ toRow rm, mr ] 
[ toRow rm, mr ] :: [Maybe Row] 

或者,您可以創建一個包裝所有RowF f的包裝,並使用:

ghci> :set -XRankNTypes -XConstraintKinds -XExistentialQuantification 
ghci> data RowC c = forall f. RowC { runRowC :: c f => RowF f } 
ghci> let ri = RowF (Identity "world") (Identity 12.3) :: Row 
ghci> :t [ RowC rm, RowC ri ] :: [ RowC Monad ] 
[ RowC rm, RowC ri ] :: [ RowC Monad ] :: [RowC Monad] 

這種方法的缺點是,一旦你轉換RowF fRowC c,你不能轉換返回,並且您無法執行任何操作 以及約束c定義的操作之外的任何值。

,你有最後的建議,確定

convert :: (forall x. f x -> g x) -> RowF f -> RowF g 
convert f2g (RowF fs fd) = RowF (f2g fs) (f2g fd) 

將允許你轉換從到RowF Maybe容易。

ghci> :t convert (Just . runIdentity) ri 
convert (Just . runIdentity) ri :: RowF Maybe