Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将简单类型化语言的非类型化AST转换为GADT_Haskell_Gadt - Fatal编程技术网

Haskell 将简单类型化语言的非类型化AST转换为GADT

Haskell 将简单类型化语言的非类型化AST转换为GADT,haskell,gadt,Haskell,Gadt,我有一个代表简单语言AST的ADT: data UTerm = UTrue | UFalse | UIf UTerm UTerm UTerm | UZero | USucc UTerm | UIsZero UTerm 此数据结构可以表示不遵循类型的无效术语 语言规则,比如UIsZero-UFalse,所以我想使用GADT 强制执行良好类型: {-# LANGUAGE GADTs #-} data TTerm a where TT

我有一个代表简单语言AST的ADT:

data UTerm = UTrue
      | UFalse
      | UIf UTerm UTerm UTerm
      | UZero
      | USucc UTerm
      | UIsZero UTerm
此数据结构可以表示不遵循类型的无效术语 语言规则,比如
UIsZero-UFalse
,所以我想使用GADT 强制执行良好类型:

{-# LANGUAGE GADTs #-}

data TTerm a where
  TTrue :: TTerm Bool
  TFalse :: TTerm Bool
  TIf :: TTerm Bool -> TTerm a -> TTerm a -> TTerm a
  TZero :: TTerm Int
  TSucc :: TTerm Int -> TTerm Int
  TIsZero :: TTerm Int -> TTerm Bool
我的问题是对子宫进行类型检查并将其转换为TTerm。我的第一次 思想是
utrem->Maybe(tterma)
,但这当然不起作用,因为 它不适用于所有
a
s。我甚至不知道会是什么类型,因为 我们不知道a是Int还是Bool。然后我想我可以写一本书
a的每个可能值的不同类型检查功能:

import Control.Applicative

typecheckbool :: UTerm -> Maybe (TTerm Bool)
typecheckbool UTrue = Just TTrue
typecheckbool UFalse = Just TFalse
typecheckbool (UIsZero a) = TIsZero <$> typecheckint a
typecheckbool _ = Nothing

typecheckint :: UTerm -> Maybe (TTerm Int)
typecheckint UZero = Just TZero
typecheckint (USucc a) = TSucc <$> typecheckint a
typecheckint (UIf a b c) = TIf <$> typecheckbool a <*> typecheckint b <*> typecheckint c
typecheckint UTrue = Nothing
typecheckint UFalse = Nothing
typecheckint (UIsZero _) = Nothing
导入控件。应用程序
typecheckbool::utem->Maybe(TTerm Bool)
typecheckbool-UTrue=Just-TTrue
typecheckbool-UFalse=仅TFalse
typecheckbool(UIsZero a)=TIsZero typecheckint a
typecheckbool=无
typecheckint::utem->Maybe(TTerm Int)
typecheckint-UZero=Just-TZero
typecheckint(USucc a)=TSucc typecheckint a
typecheckint(UIf a b c)=TIf typecheckbool a typecheckint b typecheckint c
typecheckint-UTrue=无
typecheckint-UFalse=无
typecheckint(UIsZero u)=无
这适用于某些情况,适用于TIf需要其 结果和替代是INT(但如果真的是TFalse TTrue
实际上是 完全有效),并且我们知道表达式的目标类型 打字


从子宫到子宫的正确转换方式是什么?

标准技术是定义存在类型:

data ETerm_ where
    ETerm_ :: TTerm a -> ETerm
在这种情况下,您可能还需要一些术语级别的证据,您拥有哪种类型的证据;e、 g

data Type a where
    TInt :: Type Int
    TBool :: Type Bool
那么真正的
etrem
将如下所示:

data ETerm where
    ETerm :: Type a -> TTerm a -> ETerm
类型检查的有趣案例如下

typeCheck (UIf ucond ut uf) = do
    ETerm TBool tcond <- typeCheck ucond
    ETerm tyt tt <- typeCheck ut
    ETerm tyf tf <- typeCheck uf
    case (tyt, tyf) of
        (TBool, TBool) -> return (ETerm TBool (TIf tcond tt tf))
        (TInt , TInt ) -> return (ETerm TInt  (TIf tcond tt tf))
        _ -> fail "branches have different types"
typeCheck(UIf ucond ut uf)=do
ETerm TBool tcond fail“分支具有不同的类型”

作为@DanielWagner答案的一个次要补充,您可能希望分解类型相等检查,例如

...
case (tyt, tyf) of
        (TBool, TBool) -> return (ETerm TBool (TIf tcond tt tf))
        (TInt , TInt ) -> return (ETerm TInt  (TIf tcond tt tf))
        _ -> fail "branches have different types"
一种方法是使用平等证人:

import Data.Type.Equality

typeEq :: Type a -> Type b -> Maybe (a :~: b)
typeEq TInt  TInt  = Just Refl
typeEq TBool TBool = Just Refl
typeEq _     _     = Nothing

typeCheck :: UTerm -> Maybe ETerm
typeCheck (UIf ucond ut uf) = do
    ETerm TBool tcond <- typeCheck ucond
    ETerm tyt tt <- typeCheck ut
    ETerm tyf tf <- typeCheck uf
    case typeEq tyt tyf of
        Just Refl -> return (ETerm tyt (TIf tcond tt tf))
        _         -> fail "branches have different types"
但是,我想,除非您尝试对非常高级的类型(例如GADT)建模,否则可能不需要这样做

上面的代码使用空格检查
eq
可以具有的所有可能值。由于它具有类型,例如
Int:~:Bool
,并且没有与该类型匹配的构造函数,因此我们没有
eq
的可能值,因此不需要case分支。这不会触发详尽性警告,因为确实没有未处理的案例(OT:我希望这些警告是实际错误)


除了使用
EmptyCase
之外,你还可以使用
case eq of u->undefined
,但是在上面这样的证明术语中使用bottoms是可疑的。

顺便说一句,你当然可以添加
typecheckbool(UIf a b c)
case来解决“但是
TIf TTrue TFalse TTrue
实际上是完全有效的”关注点。这很有帮助,特别是如果有两种以上的类型,谢谢。为什么doblock()中的模式匹配不起作用,而case语句起作用呢?
Just Refl您能给我一个提示,说明如何证明
a:~:b)->Void
?如果术语/类型语言包含变量,这仍然可以实现吗?
类型
数据类型能代表这样一种语言吗?@user2407038定义一种比Haskell的类型系统更具表现力的语言肯定是可能的;然后,您将无法使用Haskell的类型检查器来检查该语言中的术语是否正确。然而,在大多数情况下,如果您的语言的类型系统没有Haskell的表达能力强,那么您可以说服Haskell为您检查您的术语——当然,越努力,您的系统就越令人兴奋。
{-# LANGUAGE EmptyCase #-}
typeEq2 :: Type a -> Type b -> Either (a :~: b) ((a :~:b) -> Void)
typeEq2 TInt  TInt  = Left Refl
typeEq2 TInt  TBool = Right (\eq -> case eq of)
typeEq2 TBool TBool = Left Refl
typeEq2 TBool TInt  = Right (\eq -> case eq of)