2015-09-05 13 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