Idris:函数与Nat参数一起使用,并且使用Integer参数进行类型检查失败

时间:2016-05-27 09:13:54

标签: idris partial-functions

我是伊德里斯的新手。我正在尝试类型,我的任务是创建一个"洋葱":一个带有两个参数的函数:一个数字和任何东西,并将任何内容放入List嵌套这么多次。

例如,mkOnion 3 "Hello World"的结果应为[[["Hello World"]]]。 我已经做了这样的功能,这是我的代码:

onionListType : Nat -> Type -> Type
onionListType Z b = b
onionListType (S a) b = onionListType a (List b)

mkOnionList : (x : Nat) -> y -> onionListType x y 
mkOnionList Z a = a
mkOnionList (S n) a = mkOnionList n [a]

prn : (Show a) => a -> IO (); 
prn a = putStrLn $ show a;

main : IO()
main = do
    prn $ mkOnionList 3 4
    prn $ mkOnionList 2 'a'
    prn $ mkOnionList 5 "Hello"
    prn $ mkOnionList 0 3.14

计划工作的结果:

[[[4]]]  
[['a']]  
[[[[["Hello"]]]]]  
3.14

这正是我所需要的。 但是当我做同样的事情,但是像这样将Nat改为Integer

onionListTypeI : Integer -> Type -> Type
onionListTypeI 0 b = b
onionListTypeI a b = onionListTypeI (a-1) (List b)

mkOnionListI : (x : Integer) -> y -> onionListTypeI x y 
mkOnionListI 0 a = a
mkOnionListI n a = mkOnionListI (n-1) [a]

我收到错误:

When checking right hand side of mkOnionListI with expected type   
    onionListTypeI 0 y

Type mismatch between  
    y (Type of a) and   
    onionListTypeI 0 y (Expected type)

为什么类型检查失败?

我认为这是因为Integer可以采用负值,并且在负值的情况下无法计算Type。如果我是对的,编译器如何理解这一点?

1 个答案:

答案 0 :(得分:2)

你是对的,无法计算类型。但那是因为onionListTypeI不是全部。您可以在REPL中查看此内容

*test> :total onionListTypeI
Main.onionListTypeI is possibly not total due to recursive path:
    Main.onionListTypeI, Main.onionListTypeI

(甚至更好,在源代码中要求%default total,这会引起错误。)

因为类型构造函数不是完全的,所以编译器不会将onionListTypeI 0 y规范化为y。由于案例onionListTypeI a b = onionListTypeI (a-1) (List b),这不是全部。编译器只知道从Integer结果中减去1到Integer,而不是从哪个数字中减去(与使用Nat时不同)。这是因为使用Integer等主要函数定义了IntDoubleBits和各种prim__subBigInt的算术。如果这些函数不是盲目的,那么编译器应该遇到负值的问题,就像你假设的那样。