Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.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-GADT类型安全评估器:多个类型的常量项。_Haskell - Fatal编程技术网

Haskell-GADT类型安全评估器:多个类型的常量项。

Haskell-GADT类型安全评估器:多个类型的常量项。,haskell,Haskell,我一直在学习一些Haskell教程,使用typesafe evaluator示例介绍GADT。许多求值器同时对布尔类型和Int类型进行操作。因此,具有函数(常量整数、常量布尔、加法、乘法和检查相等)的计算器的GADT类型具有以下形式: data Expr a where I :: Int -> Expr Int B :: Bool -> Expr Bool Add :: Expr Int -> Expr Int -> Expr Int Mul :

我一直在学习一些Haskell教程,使用typesafe evaluator示例介绍GADT。许多求值器同时对布尔类型和Int类型进行操作。因此,具有函数(常量整数、常量布尔、加法、乘法和检查相等)的计算器的GADT类型具有以下形式:

data Expr a where
  I   :: Int  -> Expr Int
  B   :: Bool -> Expr Bool
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool
我对这个例子基本上没什么意见,但我希望能够将常规常量类型定义为Int或Bool类型,而不是为Int和Bool分别设置条目。这可能吗

如果我只是在GADT中使用类型变量而不是Int或Bool,这似乎是可行的

这使得上面的例子:

data Expr a where
  Con :: t -> Expr t
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool
到那时,常量类型没有受到足够的限制,因为我可以有一个常量列表输入,或者一个常量字符串/浮点,其中我只希望常量是Int或Bool

我曾经考虑过使用TypeClass(我认为)来解决这个问题,因为这似乎能够限制类型变量的“域”,例如使用“Ord”类将限制typevariable t在行中可能采用的类型

Con :: Ord t => t -> Term t
不幸的是,我不知道如何编写自己的类来实现这一点,从而将类型变量限制为布尔或整数。这条路对吗


谢谢

使用您要求的约束的想法可以实现如下:

class Constant a

instance Constant Int
instance Constant Bool

data Expr a where
  C :: Constant a => a -> Expr a
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool
我想这很管用

eval :: Expr a -> a
eval (C a) = a
eval (Add a b) = eval a + eval b
eval (Mul a b) = eval a * eval b
eval (Eq a b) = eval a == eval b

另一方面,如果要匹配常数本身,可以使用另一个GADT:

module SO where

data Const a where
  ConstB :: Bool -> Const Bool
  ConstI :: Int -> Const Int

data Expr a where
  C :: Const a -> Expr a
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool

使用
使用您要求的约束的想法可以实现如下:

class Constant a

instance Constant Int
instance Constant Bool

data Expr a where
  C :: Constant a => a -> Expr a
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool
我想这很管用

eval :: Expr a -> a
eval (C a) = a
eval (Add a b) = eval a + eval b
eval (Mul a b) = eval a * eval b
eval (Eq a b) = eval a == eval b

另一方面,如果要匹配常数本身,可以使用另一个GADT:

module SO where

data Const a where
  ConstB :: Bool -> Const Bool
  ConstI :: Int -> Const Int

data Expr a where
  C :: Const a -> Expr a
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool

使用
请注意,使用第一种基于类的方法,不可能实现“将1添加到给定表达式中的每个Int常量”。对于第二个,这是可行的。@chi感谢你的评论-我想说一些关于这一点的话,但在Haskell,这样的事情总是有我愚蠢的危险(也就是说:我只是为了看到出路而变得愚蠢)这两种方法通常通过向类中添加方法
const::const a
进行组合-这样,如果需要,您可以随时访问显式证明,而无需显式传递。请注意,使用第一种基于类的方法,不可能实现“将1添加到给定表达式中的每个Int常量”。对于第二个,这是可行的。@chi感谢你的评论-我想说一些关于这一点的话,但在Haskell,这样的事情总是有我愚蠢的危险(也就是说:我只是为了看到出路而变得愚蠢)这两种方法通常通过向类中添加一个方法
const::const a
进行组合-这样,如果需要,您可以随时访问显式证明,而无需显式传递它。