使 Haskell 类型系统理解fundeps继承了复合(类似元组)类型

问题描述 投票:0回答:1

我有以下代码,我用它来将 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   

haskell functional-dependencies type-level-computation
1个回答
0
投票

您可以启用

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)

就我个人而言,我发现类型族比函数依赖更容易使用,所以我更喜欢尽可能使用它们。

© www.soinside.com 2019 - 2024. All rights reserved.