是否可以使用Haskell的类型系统(GADT)进行某种多态变体?

时间:2018-10-09 21:24:39

标签: haskell gadt

这是我要实现的目标:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}

module Action where

import Data.Type.Set

data Configuration
  = A
  | B
  | C

data Action (configuration :: Configuration) where
  Action1 :: Member cfg '[ 'A ]     => Action cfg
  Action2 :: Member cfg '[ 'B, 'C ] => Action cfg
  Action3 :: Member cfg '[ 'A, 'C ] => Action cfg

exhaustive :: Action 'A -> ()
exhaustive Action1 = ()
exhaustive Action3 = ()

我有一组操作和一组配置,但是某些操作仅在某些配置中才有意义。我不想不必显式丢弃配置中不相关的操作,因此我考虑使用GADT。不幸的是,类型检查器无法意识到我的exhaustive函数确实是详尽无遗的。

我想知道我是否可以使用任何现有的类型级别列表/集合,甚至可以使用行类型(如http://hackage.haskell.org/package/row-types-0.2.3.0/docs/Data-Row-Variants.html)来解决此问题。

我还尝试了一种方法Action2 :: Action '[ 'B, 'C ]并将类型类约束推入exhaustive,但没有成功。

谢谢您的任何建议! (或者甚至是为什么这是一个坏主意或不容易实现的原因)

1 个答案:

答案 0 :(得分:3)

一个朋友建议一个解决方案:

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}

module Action where

type family MemberB (x :: k) (l :: [k]) where
  MemberB x '[]     = 'False
  MemberB x (x:xs)  = 'True
  MemberB x (x':xs) = MemberB x xs

type Member x xs = MemberB x xs ~ 'True

data Configuration
  = A
  | B
  | C

data Action (configuration :: Configuration) where
  Action1 :: Member cfg '[ 'A ]     => Action cfg
  Action2 :: Member cfg '[ 'B, 'C ] => Action cfg
  Action3 :: Member cfg '[ 'A, 'C ] => Action cfg

exhaustive :: Action 'A -> ()
exhaustive Action1 = ()
exhaustive Action3 = ()
exhaustive Action2 = ()

显然,问题在于我使用的Member(来自Data.Type.Set)不是封闭类型的族。现在,错误消息不是很好,我们尝试执行以下操作:

type family MemberB (x :: k) (l :: [k]) where
  MemberB x '[]     = TypeError ('Text "not a member")
  MemberB x (x:xs)  = 'True
  MemberB x (x':xs) = MemberB x xs

但是不幸的是,这吃了类型错误!是因为TypeError将与'True统一在一起吗?如果有人有办法使类型错误稍微好一点,我会很高兴地接受它!

我对此提出了一个单独的问题:

How to define a custom type error within a type family for a constraint that uses type equality?