haskell - 如何使用 GADT 和 Data.Map 创建类型化的玩具语言环境映射?
问题描述
我在玩 Haskell,想法是在 GADT 的帮助下创建一种玩具语言。解释器通常具有将变量名称映射到值的环境映射。
我的玩具语言 int 和 bool 基本上有两种类型,例如,用I 10
and表示B True
。
问题是我无法创建包含这两者的地图,这是我的代码
{-# LANGUAGE GADTs, RankNTypes #-}
module Foo where
import qualified Data.Map as M
import Data.Maybe
data Expr a where
V :: Char -> Expr a
B :: Bool -> Expr Bool
I :: Int -> Expr Int
If :: Expr Bool -> Expr a -> Expr a -> Expr a
type Env a = M.Map Char (Expr a)
env = M.fromList [('x', B True), ('y', I 10)]
-- Error here ----^^^^
-- [typecheck -Wdeferred-type-errors] [E] • Couldn't match type ‘Int’ with ‘Bool’
-- Expected type: Expr Bool
-- Actual type: Expr Int
-- • In the expression: I 10
-- In the expression: ('y', I 10)
-- In the first argument of ‘M.fromList’, namely
-- ‘[('x', B True), ('y', I 10)]’
我怎样才能创建这样的映射?
解决方案
对于这么小的类型集合,我会使用其中一个:
type Env = Map Variable (Either (Expr Int) (Expr Bool))
type Env = (Map Variable (Expr Int), Map Variable (Expr Bool))
...取决于您是否想要为每种类型使用单独的命名空间。当有更多类型可用时,我会使用其中一种:
data UntypedExpr = forall a. UE (TypeRep a) (Expr a)
type Env = Map Variable UntypedExpr
-- OR
newtype SingleTypeEnv a = STE (Map Variable (Expr a))
type Env = TypeRepMap SingleTypeEnv
...再次取决于您是否想要为每种类型使用单独的命名空间。
TypeRep
来自基本包(或者您可以制作一些更特定于您的 EDSL 类型的新 GADT),并且TypeRepMap
来自typerep-map。
推荐阅读
- mysql - MySQL如何选择最大的两列0和null
- javascript - 使用 Deno 读取文件的文件大小和最后修改日期
- php - 如何在 php 中为电报机器人创建内联按钮
- java - Dockerfile 构建提高了不足的_scope:使用公共 openjdk 映像授权失败
- r - R根据特定标准对所有列中的数据进行分组并减去行
- tensorflow - 对 keras.text.preprocessing.one_hot 的输出感到困惑
- flutter - 无法为颤振应用构建 apk
- c# - 如何确定事件中发送者的 Parent.Parent 的对象类型?
- python - 在 Visual Studio 2019 中运行 python matplotlibcpp
- python - 使用另一个数组创建一个由 1 和 0 组成的数组