在 Idris 中列出总和类型元素的惯用方式

Idiomatic way of listing elements of a sum type in Idris

我有一个表示算术运算符的求和类型:

data Operator = Add | Substract | Multiply | Divide

我正在尝试为它编写一个解析器。为此,我需要所有运算符的详尽列表。

在 Haskell 中,我会像以下 Whosebug 问题中建议的那样使用 deriving (Enum, Bounded)Getting a list of all possible data type values in Haskell

不幸的是,Idris 中似乎没有 Issue #19. There is some ongoing work by David Christiansen on the question so hopefully the situation will improve in the future : david-christiansen/derive-all-the-instances

建议的这种机制

来自 Scala,我习惯于手动列出元素,所以我很自然地想到了以下内容:

Operators : Vect 4 Operator
Operators = [Add, Substract, Multiply, Divide]

为了确保Operators包含所有元素,我添加了以下证明:

total
opInOps : Elem op Operators
opInOps {op = Add} = Here
opInOps {op = Substract} = There Here
opInOps {op = Multiply} = There (There Here)
opInOps {op = Divide} = There (There (There Here))

因此,如果我将一个元素添加到 Operator 而未将其添加到 Operators,完整性检查器会抱怨:

Parsers.opInOps is not total as there are missing cases

它完成了工作,但它有很多样板。 我错过了什么?有更好的方法吗?

可以选择使用 elaborator reflection 等语言的特性来获取所有构造函数的列表。

这是解决这个特定问题的一个非常愚蠢的方法(我发布这个是因为目前的文档非常稀缺):

%language ElabReflection

data Operator = Add | Subtract | Multiply | Divide

constrsOfOperator : Elab ()
constrsOfOperator = 
  do (MkDatatype _ _ _ constrs) <- lookupDatatypeExact `{Operator}
     loop $ map fst constrs

  where loop : List TTName -> Elab ()
        loop [] =
          do fill `([] : List Operator); solve
        loop (c :: cs) =
          do [x, xs] <- apply `(List.(::) : Operator -> List Operator -> List Operator) [False, False]
             solve
             focus x; fill (Var c); solve
             focus xs
             loop cs

allOperators : List Operator
allOperators = %runElab constrsOfOperator

一些评论:

  1. 似乎要解决具有相似结构的任何归纳数据类型的这个问题,需要完成 Elaborator Reflection: Extending Idris in Idris 论文。
  2. 也许 pruviloj 库有一些东西可以更容易地解决更一般情况下的这个问题。