>在Haskell中未定义

我一直在阅读这个http://www.haskell.org/haskellwiki/Hask。 我正在努力与这部分..

undef1 = undefined :: a -> b
undef2 =  _ -> undefined

为什么他们的行为像这样..

seq undef1 () = undefined
seq undef2 () = ()
undef2 () = undefined

这是什么原因? 我想了解这种行为,但我甚至不知道从哪里开始。 特别是,为什么undef2在严格评估下表现不同?


特殊函数seq其第一个参数评估为弱头标准形式,然后返回其第二个参数。 WHNF的一个很好的解释可以在这里找到,但为了这个答案的目的,我将使用Haskell的wiki定义:

如果它是以下任一情况,则表达式处于弱头标准形式(WHNF):

  • 一个构造函数(最终应用于参数),如True,Just(square 42)或(:) 1
  • (+)2或sqrt的参数太少(可能没有)。
  • 或lambda抽象 x - >表达式。
  • 重要的一点是,当一个表达式是一个构造函数时, seq只会查看构造函数的标签。 因此, seq (Just undefined) 1计算结果为1

    另一个重要的一点是,Haskell中的所有类型都被解除了 - 也就是说,评估类型的值可能会导致无限循环被执行或引发异常(通常出现errorundefined )。 在我们评估过seq ab ,我们可以肯定,评估a WHNF不会导致无限循环或异常。

    有了这些知识,让我们看看你的例子:

    undef1 = undefined :: a -> b
    undef2 =  _ -> undefined
    

    seq undef1 ()被评估时, seq首先尝试找出undef1上面三个类别中的undef1属于。 但是undef1undefined ,所以整个表达式评估为undefined

    但是,在seq undef2 () = ()的情况下,第一个参数是lambda抽象。 由于seq无法看到lambda,它返回第二个参数。

    第三个例子undef2 () = undefined只是评估应用程序的简单结果(_ -> undefined) ()


    他们不是一回事。 undef1是从a到b的函数,但哪个函数是未定义的。 评估undef1头正常的形式让你不确定。

    undef2是从a到b的函数。 具体来说,它是一个忽略其参数并返回未定义的函数。 但是undef2本身并不是未定义的。 只有当你尝试评估函数时(如你的第三行),你会得到未定义的。 所以,当你评估undef2头正常形式,你会得到一个正确的功能,而不是未定义的。

    把它放在更加迫切的术语中(总是不准确的来源,但如果你更熟悉这一点,它很好地说明了这一点),将undef1看作是永不返回的属性获取器。 (在Haskell中,不返回和undefined在语义上是等价的。)undef2是一个返回函数的属性getter; 它是那个函数,如果你调用它,它将不会返回。 在C#中:

    Func<Object, Object> Undef1 {
      get {
        while (true) {}
        return null;
      }
    }
    
    Func<Object, Object> Undef2 {
      get {
        return _ -> {
          while (true) {}
          return null;
        }
      }
    }
    

    现在你的测试变成:

    var x = Undef1;
    var y = Undef2;
    var z = Undef2(null);
    

    为了这个问题,我们假设有三件事情可以迫使一个价值被实际评估:

  • 在该值上进行模式匹配
  • 将该值应用于参数
  • 用它作为seq的第一个参数
  • 实际情况稍微复杂一些,但这不是一个重要的方式。

    此外,这种强迫只发生在某种外在表达的背景下,因此,不要把这些看作是以某种抽象的方式“强迫评估”,而是有助于将它们视为对外部表达的评估取决于评估值。 这就是为什么,例如, seq xx在任何意义上都不强制x ,因为这是表达式的最终值; 它说当外部表达式(其值是x )被评估时,它也应该评估x ,这是多余的。

    最后,任何取决于强制未定义值的值本身都是未定义的。


    仔细阅读每个表达式:

    seq undef1 () = undefined
    

    在这种情况下, undef1是未定义的, seq undef1 x是一个表达式,其值为x并取决于评估undef1 。 因此,无论seq的第二个参数是什么,整个表达式都是不确定的。

    seq undef2 () = ()
    

    在这种情况下, undef2不是未定义的,但是应用它的结果是。 seq undef2 x是一个表达式,其值为x并取决于评估undef2 。 这不会引起任何问题,并且seq的第一个参数被丢弃,所以表达式的值是()

    undef2 () = undefined
    

    在这种情况下,我们直接应用undef2 。 表达式undef2 ()取决于对undef2的评估(这很好)并且评估应用undef2的结果,在这种情况下undef2undefined

    与第四种情况对比:

    undef1 () = undefined
    

    在这种情况下,我们应用undef1 ,因此表达式的值取决于评估undef1undef1是未定义的,因此整个表达式也是如此。 这与使用undef2的前一个表达式是相同的“值”,但出于完全不同的原因!

    链接地址: http://www.djcxy.com/p/42977.html

    上一篇: > undefined in Haskell

    下一篇: Does a function in Haskell always evaluate its return value?