我有以下代码,我用它来将 HList-of-touples (或者更像是,tree-of-touples)转换为相同的形状,但不是元组,只保留第二个元素。
问题是,这需要
UndecidableInstances
(请参阅评论中的错误消息)。是否有可能让类型系统意识到,a :. c
确实决定了b :. d
,以便错误(以及 UndecidableInstances 的需要)消失?
class TupSnd a b | a -> b where
tupSnd :: a -> b
instance TupSnd PGTup (Only Action) where
tupSnd a = Only (snd a)
-- This needs UndecidableInstances allegedly, but probably there's some type-level trick to make it work?
--
-- Error:
--
-- Reason: lhs type ‘a :. c’ does not determine rhs type ‘b :. d’
--
-- Which sounds like it shouldn't be the case logically.
instance (TupSnd a b, TupSnd c d) => TupSnd (a :. c) (b :. d) where
tupSnd (a :. c) = tupSnd a :. tupSnd c
对于上下文,
:.
是来自postgresql-simple
的美化的元组构造函数助手,我也有
type PGTup = (Identifier, Action)
type PGTup2 = PGTup :. PGTup
type PGTup2_2 = PGTup2 :. PGTup2
type PGTup3 = PGTup :. PGTup2
type PGTup4 = PGTup :. PGTup3
您可以启用
UndecidableInstances
,这是一个无害的扩展。
或者,您也可以切换到类型系列。以下代码可编译(除了
TypeFamilies
之外没有其他扩展名)。在下面的代码中,我稍微更改了您的类型,以避免导入一堆模块。您应该能够轻松地将其调整回您的情况。
{-# LANGUAGE TypeFamilies #-}
class TupSnd a where
type T a
tupSnd :: a -> T a
instance TupSnd Bool where
type T Bool = String
tupSnd a = show a
instance (TupSnd a, TupSnd c) => TupSnd (a, c) where
type T (a, c) = (T a, T c)
tupSnd (a, c) = (tupSnd a, tupSnd c)
就我个人而言,我发现类型族比函数依赖更容易使用,所以我更喜欢尽可能使用它们。