Haskell 如何为类型级别列表编写交集函数

Haskell 如何为类型级别列表编写交集函数,haskell,Haskell,我正在研究操作系统的类型级列表,我编写了两个类型级函数,一个用于合并两个列表,另一个用于获取它们的交集。我很难让交集函数正常工作 (ghc 7.10.3) 以下是按预期工作的联合收割机功能: *Main> (combineSupportedOS debian freeBSD) :: OSList '[OSDebian, OSFreeBSD] OSList [OSDebian,OSFreeBSD] 下面是交集函数,不太有效: *Main> (intersectSupportedOS

我正在研究操作系统的类型级列表,我编写了两个类型级函数,一个用于合并两个列表,另一个用于获取它们的交集。我很难让交集函数正常工作

(ghc 7.10.3)

以下是按预期工作的联合收割机功能:

*Main> (combineSupportedOS debian freeBSD)  :: OSList '[OSDebian, OSFreeBSD]
OSList [OSDebian,OSFreeBSD]
下面是交集函数,不太有效:

*Main> (intersectSupportedOS debian debian)  :: OSList '[OSDebian]
Couldn't match expected type ‘IntersectOSList ['OSDebian] '['OSDebian]’
            with actual type ‘'['OSDebian]’
我怎样才能使类型检查器确信这是一个很好的类型

完整代码:

{-# LANGUAGE TypeOperators, PolyKinds, DataKinds, TypeFamilies, UndecidableInstances #-}

import Data.Typeable
import Data.String
import Data.Type.Bool
import Data.Type.Equality

data SupportedOS = OSDebian | OSFreeBSD
    deriving (Show, Eq)

data OSList (os :: [SupportedOS]) = OSList [SupportedOS]
    deriving (Show, Eq)

debian :: OSList '[OSDebian]
debian = typeOS OSDebian

freeBSD :: OSList '[OSFreeBSD]
freeBSD = typeOS OSFreeBSD

typeOS :: SupportedOS -> OSList os
typeOS o = OSList [o]

combineSupportedOS
    :: (r ~ ConcatOSList l1 l2)
    => OSList l1
    -> OSList l2
    -> OSList r
combineSupportedOS (OSList l1) (OSList l2) = OSList (l1 ++ l2)

type family ConcatOSList (list1 :: [a]) (list2 :: [a]) :: [a]
type instance ConcatOSList '[] list2 = list2
type instance ConcatOSList (a ': rest) list2 = a ': ConcatOSList rest list2

intersectSupportedOS
    :: (r ~ IntersectOSList l1 l2)
    => OSList l1
    -> OSList l2
    -> OSList r
intersectSupportedOS (OSList l1) (OSList l2) = OSList (filter (`elem` l2) l1)

type family IntersectOSList (list1 :: [a]) (list2 :: [a]) :: [a]
type instance IntersectOSList '[] list2 = list2
type instance IntersectOSList (a ': rest) list2 = 
    If (ElemOSList a list2)
        (a ': IntersectOSList rest list2)
        (IntersectOSList rest list2)

type family ElemOSList a (list :: [b]) :: Bool
type instance ElemOSList a '[] = False
type instance ElemOSList a (b ': bs) = 
    If (a == b)
        True
        (ElemOSList a bs)

type family EqOS (a :: SupportedOS) (b :: SupportedOS) where
    EqOS a a = True
    EqOS a b = False
type instance a == b = EqOS a b

主要修复方法如下:

- type family ElemOSList a (list :: [b]) :: Bool
+ type family ElemOSList (a :: SupportedOS) (list :: [SupportedOS]) :: Bool
此外,如前所述,有一个错误的基本情况

以下是固定代码:

type family IntersectOSList (list1 :: [a]) (list2 :: [a]) :: [a]
type instance IntersectOSList '[] list2 = '[]
type instance IntersectOSList (a ': rest) list2 = 
    If (ElemOSList a list2)
            (a ': IntersectOSList rest list2)
            (IntersectOSList rest list2)

type family ElemOSList (a :: SupportedOS) (list :: [SupportedOS]) :: Bool
type instance ElemOSList a '[] = False
type instance ElemOSList a (b ': bs) = a == b || ElemOSList a bs

嗯。
IntersectOSList'[]list2=list2
在我看来像是一个狡猾的基本情况。还有更多吗?我盯着这个看了太久,什么也没看到,但我注意到ElemOSList的类型家族是错误的。特别是第一个参数。是的,基本情况是错误的。所以,我没有得到的是,在处理类型族时,这种类型错误意味着类型检查器发现了一个问题,而不是类型检查器不够智能。@Joey:如果你找到了解决方案,你可以回答你自己的问题(
type family ElemOSList(a::b)(list:[b])::Bool
修复了我的问题)。顺便说一下,
如果cnd True els
cnd|els