Nim lang 尼姆:如何证明不是零?

Nim lang 尼姆:如何证明不是零?,nim-lang,Nim Lang,对我来说,Nim最有趣的特性之一是not nil注释,因为它基本上允许在编译器的帮助下静态地完全排除各种NPE/access违规错误。然而,我在实践中很难使用它。让我们考虑一个最基本的用例: 类型 SafeSeq[T]=序列[T]不是零 这里的一个直接陷阱是,即使实例化这样的SafeSeq也不是那么容易。尝试 s:SafeSeq[int]=newSeq[int](100) 出现错误时失败无法证明'newSeq(100)'不是零,这令人惊讶,因为人们可能会认为newSeq根本不是零。解决方案似

对我来说,Nim最有趣的特性之一是
not nil
注释,因为它基本上允许在编译器的帮助下静态地完全排除各种NPE/access违规错误。然而,我在实践中很难使用它。让我们考虑一个最基本的用例:

类型
SafeSeq[T]=序列[T]不是零
这里的一个直接陷阱是,即使实例化这样的
SafeSeq
也不是那么容易。尝试

s:SafeSeq[int]=newSeq[int](100)
出现错误时失败
无法证明'newSeq(100)'不是零
,这令人惊讶,因为人们可能会认为
newSeq
根本不是零。解决方案似乎使用以下帮助器:

proc newSafeSeq*[T](大小:int):SafeSeq[T]=
#我想只有@[]表达式可以证明不是零
结果=@[]
结果设置(大小)
下一个问题出现在尝试使用
SafeSeq
执行某些操作时。例如,当您映射到一个
SafeSeq
时,您可能会期望结果不会再次为零。但是,类似的方法也失败了:

让a:SafeSeq[int]=@[1,2,3]
设b:SafeSeq[string]=a.mapIt(string,$it)
一般的问题似乎是,一旦返回类型变成普通的
seq
时,编译器似乎忘记了
not nil
属性,无法再证明它

我现在的想法是引入一个小的(可以说是丑陋的)助手方法,它允许我实际证明
而不是nil

proc proveNotNil*[T](a:seq[T]):SafeSeq[T]=
如果是零:
结果=a#意外,仍然错误“无法证明‘a’不是零”
其他:
引发新异常(ValueError,“无法转换”)
#这应该允许:
设a:SafeSeq[int]=@[1,2,3]
设b:SafeSeq[string]=a.mapIt(string,$it).proveNotNil
但是,编译器在这里也无法证明
不是nil
。我的问题是:

  • 在这种情况下,我应该如何帮助编译器推断
    而不是nil

  • 此功能的长期目标是什么,即是否有计划使推断
    而不是nil
    更强大?手动
    proveNotNil
    的问题在于它可能不安全,而且违背了编译器负责证明它的想法。但是,如果只在非常罕见的情况下才需要
    proveNotNil
    ,则不会造成太大的伤害


注:我知道
seq
试图成为
nil
不可知论者,即,即使在
nil
情况下,一切都正常。但是,这仅适用于Nim内部。当与C代码接口时,nil隐藏原则成为错误的危险来源,因为
nil
序列仅在Nim端无害…

使用isNil魔法检查nil:

type SafeSeq[T] = seq[T] not nil
proc proveNotNil[T](s: seq[T]): SafeSeq[T] =
  if s.isNil: # Here is the magic!
    assert(false)
  else:
    result = s
let s = proveNotNil newSeq[int]()

我想标准库需要做一些工作,例如注释
newSeq
返回
not nil
seqNice,谢谢,这正是我想要的。我以前从未听说过
isNil
,例如,手册中没有提到它。但是,从条件中推断“非零”需要编译器魔法,这是有道理的。在2020年,激活nil跟踪“编译器魔法”不再需要.isNil<如果s==nil足以满足编译器的要求,则为code>。