有几个解决方案。
你可以使用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 f
到RowC 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
为什么要这样?这些“可能”中的一些应该是“只是”吗? – dfeuer
为了澄清@dfeuer在说什么......为什么你想要一个包含'RowF Identify'和'RowF Maybe'值的列表?向我们展示一些您想要编写的示例代码,如果您可以构建这样的列表。 – ErikR