解析索引类型

时间:2017-05-14 22:00:11

标签: parsing haskell dependent-type dynamic-typing

我刚开始探索data types à la carte与索引类型相结合的可能性。我目前的实验有点太大而无法包括在这里,但可以找到here。我的例子是将不同成分(算术,函数......)的表达混合在一起。目标是仅强制执行良好类型的表达式。这就是为表达式添加索引(Sort类型)。

我可以构建如下表达式:

-- define expressions over variables and arithmetic (+, *, numeric constants)
type Lia = IFix (VarF :+: ArithmeticF)

-- expression of integer type/sort
t :: Lia IntegralSort
t = var "c" .+. cnst 1

只要我只构造固定(静态)表达式,这一切都很好。

有没有办法从字符串/其他表示中读取表达式(显然必须对排序进行编码)并生成由这些函子表示的动态值?

例如,我想阅读((c : Int) + (1 : Int))并以VarFArithmeticF以某种方式表示它。在这里,我意识到我无法获得静态类型Lia IntegralSort的值。但是假设我还有:

data EqualityF a where
    Equals :: forall s. a s -> a s -> EqualityF a BoolSort

我可以期待有一个功能可以将String读入Maybe (IFix (EqualityF :+: VarF :+: ...))。这样的函数将尝试为LHS和RHS构建表示,如果匹配的类型可以产生静态已知类型IFix (EqualityF :+: ...) BoolSort的结果。问题是LHS(和RHS)的表示没有固定的静态排序。我选择的这种表述是不是我想做的事情?

1 个答案:

答案 0 :(得分:1)

(.=.) :: EqualityF :<: f => IFix f s -> IFix f s -> IFix f BoolSort
(.=.) a b = inject (Equals a b)

您可以使用GADT隐藏排序,允许您根据输入返回排序值。然后,模式匹配允许您恢复排序。

data Expr (f :: (Sort -> *) -> (Sort -> *)) where
  BoolExpr :: IFix f BoolSort -> Expr f
  IntExpr  :: IFix f IntegralSort -> Expr f

这是一个简单的后缀表达式解析器,涉及+=

parse :: (EqualityF :<: f, ArithmeticF :<: f) => String -> [Expr f] -> Maybe (Expr f)

parse (c : s) stack | isDigit c =
  parse s (IntExpr (cnst (digitToInt c)) : stack)

parse ('+' : s) (IntExpr e1 : IntExpr e2 : stack) =
  parse s (IntExpr (e1 .+. e2) : stack)

parse ('=' : s) (IntExpr e1 : IntExpr e2 : stack) =
  parse s (BoolExpr (e1 .=. e2) : stack)

parse ('=' : s) (BoolExpr e1 : BoolExpr e2 : stack) =
  parse s (BoolExpr (e1 .=. e2) : stack)

parse [] [e] = Just e
parse _ _ = Nothing

您可能不喜欢=的重复案例。更通用的框架是Typeable,允许您只测试所需的类型等式。

data SomeExpr (f :: (Sort -> *) -> Sort -> *) where
  SomeExpr :: Typeable s => IFix f s -> SomeExpr f


parseSome :: forall f. (EqualityF :<: f, ArithmeticF :<: f) => String -> [SomeExpr f] -> Maybe (Expr f)

parseSome (c : s) stack | isDigit c =
  parseSome s (SomeExpr (cnst (digitToInt c)) : stack)

parseSome ('+' : s) (SomeExpr e1 : SomeExpr e2 : stack) = do
  e1 <- gcast e1
  e2 <- gcast e2
  parseSome s (SomeExpr (e1 .+. e2) : stack)

parseSome ('=' : s) (SomeExpr (e1 :: IFix f s1) : SomeExpr (e2 :: IFix f s2) : stack) = do
  Refl <- eqT :: Maybe (s1 :~: s2) 
  parseSome s (SomeExpr (e1 .=. e2) : stack)

parseSome [] [e] = Just e
parseSome _ _ = Nothing

修改

要解析排序,您希望在类型级别跟踪它们。再次,使用存在类型。

data SomeSort where
  SomeSort :: Typeable (s :: Sort) => proxy s -> SomeSort

您可以通过这种方式构建数组:

-- \i e -> array i e
arraySort :: SomeSort -> SomeSort -> SomeSort
arraySort (SomeSort (Proxy :: Proxy i)) (SomeSort (Proxy :: Proxy e)) =
  SomeSort (Proxy :: Proxy (ArraySort i e))

这里Typeable的一个潜在问题是它只允许你测试类型的相等性,当你可能只想检查头构造函数时:你不能问“这个类型是{{1} }?“,但只有”这个类型等于ArraySort?“或其他一些完整类型。 在这种情况下,您需要一个反映排序结构的GADT。

ArraySort IntSort BoolSort

-- "Singleton type" data SSort (s :: Sort) where SIntSort :: SSort IntSort SBoolSort :: SSort BoolSort SArraySort :: SSort i -> SSort e -> SSort (ArraySort i e) data SomeSort where SomeSort :: SSort s -> SomeSort array :: SomeSort -> SomeSort -> SomeSort array (SomeSort i) (SomeSort e) = SomeSort (SArraySort i e) 包提供了各种用于定义和使用这些单例类型的工具,但对于您的用例可能有点过分。