Haskell:如何测试代码不是';不编译?

Haskell:如何测试代码不是';不编译?,haskell,typechecking,gadt,Haskell,Typechecking,Gadt,测试声明类型不正确的最佳方法是什么?对于GADTs,判断构造函数应用程序是否正确并非易事。如果要编写类型安全构造库,自然要确保不能创建非法构造。因此,作为测试套件的一部分,我希望确保类型检查器拒绝某些示例非法构造 作为示例,请参见大小检查向量表示。它比我想要确定的典型问题要简单得多,但它是检查测试方法的一个好例子 data Vector n t where EmptyVec :: Vector 0 t ConsVec :: t -> Vector n t -> Vector

测试声明类型不正确的最佳方法是什么?对于GADTs,判断构造函数应用程序是否正确并非易事。如果要编写类型安全构造库,自然要确保不能创建非法构造。因此,作为测试套件的一部分,我希望确保类型检查器拒绝某些示例非法构造

作为示例,请参见大小检查向量表示。它比我想要确定的典型问题要简单得多,但它是检查测试方法的一个好例子

data Vector n t where
  EmptyVec :: Vector 0 t
  ConsVec  :: t -> Vector n t -> Vector (n+1) t

// TODO: test that it does not typecheck
illegalVec = ConsVec 'c' (ConsVec "b" EmptyVec)

您可以从Haskell程序调用GHCi并使用它检查字符串<来自hackage的代码>提示为此提供了方便的包装:

{-# LANGUAGE DataKinds, TypeOperators, GADTs #-}

import GHC.TypeLits
import Language.Haskell.Interpreter

data Vector n t where
    EmptyVec :: Vector 0 t
    ConsVec  :: t -> Vector n t -> Vector (n + 1) t 

main = do
    print =<< runInterpreter (typeChecks "ConsVec 'c' (ConsVec \"b\" EmptyVec)")
    -- prints "Right False"
{-#语言数据类型、类型运算符、GADT}
导入GHC.TypeLits
导入Language.Haskell.Interpreter
数据向量n t在哪里
EmptyVec::向量0 t
ConsVec::t->Vector n t->Vector(n+1)t
main=do

print=我得到了一个不同的想法,基于(ab?)使用GHC的
-fdefer-type-errors
选项,这可能比嵌入完整的Haskell解释器(如
hint
)便宜。尽管它的输出有点混乱,因为在编译过程中仍然会打印警告,但是如果您愿意在文件和
GHC
命令行中使用GHC
-w
选项关闭警告,则可以清除警告

尽管我在这里将所有内容都包含在一个模块中进行演示,但我假设此测试的选项只应在相关测试模块中正确启用

请注意,此方法取决于是否能够深入评估有问题的值,以揭示其延迟类型错误,这在某些用例中可能很棘手

{-# OPTIONS_GHC -fdefer-type-errors #-}
{-# LANGUAGE TypeOperators, GADTs, DataKinds #-}
{-# LANGUAGE StandaloneDeriving #-}

import GHC.TypeLits
import Control.Exception
import Data.Typeable

data Vector n t where
  EmptyVec :: Vector 0 t
  ConsVec  :: t -> Vector n t -> Vector (n+1) t

-- Add a Show instance so we can evaluate a Vector deeply to catch any
-- embedded deferred type errors.
deriving instance Show t => Show (Vector n t)

illegalVec = ConsVec 'c' (ConsVec "b" EmptyVec)

test = do
    t <- try . evaluate $ length (show illegalVec)
    case t of
        Right _ -> error "Showing illegalVec gave no error"
        Left e -> putStrLn $ "\nOk: Showing illegalVec returned error:\n"
                    ++ show (e :: ErrorCall)
-- ErrorCall is the exception type returned by the error function and seems
-- also to be used by deferred type errors.
{-#选项_GHC-fdefer类型错误#-}
{-#语言类型运算符、GADT、数据种类}
{-#语言独立派生}
导入GHC.TypeLits
导入控制。异常
导入数据。可键入
数据向量n t在哪里
EmptyVec::向量0 t
ConsVec::t->Vector n t->Vector(n+1)t
--添加一个Show实例,这样我们就可以对向量进行深入评估,以捕获任何
--嵌入的延迟类型错误。
派生实例Show t=>Show(向量n t)
illegalVec=ConsVec'c'(ConsVec“b”EmptyVec)
测试=do
t错误“显示illegalVec未给出错误”
左e->putStrLn$“\n确定:显示非法向量返回错误:\n”
++显示(e::ErrorCall)
--ErrorCall是error函数返回的异常类型,似乎
--也可由延迟类型错误使用。

您可能需要进行“元测试”。编写一个小脚本,尝试编译您的代码,并确保编译器不会以代码0退出。我认为您正在尝试实现某种依赖类型,对吗。。。您希望在这里使用什么语言扩展?要让第一部分工作正常,@CarstenKönig:
TypeOperators
GADTs
datatypes
,以及导入
GHC.TypeLits