Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 更自然地表达断言_Haskell_Pattern Matching_Assertions - Fatal编程技术网

Haskell 更自然地表达断言

Haskell 更自然地表达断言,haskell,pattern-matching,assertions,Haskell,Pattern Matching,Assertions,假设我写了一个函数 f [x, y] = x + y f [x, y, z] = z - x - y 这是由编译器用一行额外的内容填写的,如 f _ = error "pattern match failed" f l = assert (atLeastTwo l) $ let (x,r1) = (unsafeHead l, unsafeTail l) in let (y,r2) = (unsafeHead r1, unsafeTail

假设我写了一个函数

f [x, y] = x + y
f [x, y, z] = z - x - y
这是由编译器用一行额外的内容填写的,如

f _ = error "pattern match failed"
f l = assert (atLeastTwo l) $
        let (x,r1) = (unsafeHead l, unsafeTail l) in
          let (y,r2) = (unsafeHead r1, unsafeTail r1) in
            case r2 of
              [] -> x + y
              (z,r3) -> assert (r3 == []) $ z - x - y 
如果未导出
f
,并且我知道它只能正确应用,并且函数对性能至关重要,我可能希望避免在生产代码中使用额外的模式。我可以把它改写得很不自然

f _ = error "pattern match failed"
f l = assert (atLeastTwo l) $
        let (x,r1) = (unsafeHead l, unsafeTail l) in
          let (y,r2) = (unsafeHead r1, unsafeTail r1) in
            case r2 of
              [] -> x + y
              (z,r3) -> assert (r3 == []) $ z - x - y 
我想做的是用一行额外的代码编写原始函数定义:

f _ = makeDemonsComeOutOfMyNose "This error is impossible."
当断言或推断的安全Haskell被启用时,以描述方式命名的神奇函数将被编译为
error
,当断言被禁用时,该函数将被标记为不可访问(使模式匹配不安全)。有没有办法做到这一点,或者类似的事情

编辑 为了解决jberryman对是否存在真正的性能影响的担忧:

  • 这是一个假设问题。我怀疑在更复杂的情况下,如果存在多个“不可能发生”的情况,至少可能会有性能优势,错误情况可能会在指令缓存中使用额外的空间

  • 即使没有真正的性能问题,我认为断言和错误之间也存在明显的区别。我怀疑最灵活的断言形式是“此代码应该是不可访问的”,可能有一个或三个参数指示编译器应该如何认真对待该声明。如果数据结构不变量被破坏并导致程序泄漏机密信息,则安全性是相对的,这不一定比无效内存访问更严重。请注意,粗略地说,
    assert px=if p then x else makeDemonsFlyioutofmynose NO\u REAL\u DEMONS\u请“assertion failed”
    ,但无法根据
    assert
    定义demon函数


  • GHC足够聪明,可以优化未使用的模式匹配。这里有一个简单的程序

    module Foo (foo) where
    
    data List a = Nil | Cons a (List a)
    
    link :: List a -> List a -> List a
    link Nil        _   = error "link: Nil"
    link (Cons a _) xs  = Cons a xs
    
    l1 = Cons 'a' (Cons 'b' Nil)
    
    foo = link l1
    
    这是一个非常做作的示例,但它演示了这样一种情况:GHC可以证明
    link
    (或者在您的情况下
    f
    )正在静态已知构造函数上被调用(或者可以通过内联、简化等证明哪种模式匹配会成功)

    以下是核心输出:

    foo1 :: Char
    foo1 = C# 'a'
    
    foo :: List Char -> List Char
    foo = \ (ds :: List Char) -> Cons foo1 ds
    

    错误
    案例不会出现在
    Foo
    的核心中的任何位置。因此,您可以放心,在这种情况下,使用额外的未使用模式匹配绝对不会产生性能差异。

    您只是出于性能原因而这样做吗?您以前是否能够测量额外案例调用错误的影响?另外,一个从未达到的案例的性能成本是多少?因为您使用的是链接列表,所以应该考虑性能级别。只有在避免任何非连续内存数据结构固有的缓存未命中的情况下,类似C的最后手段优化(我不需要,这应该是最后手段!)才有意义。@leftaroundabout,这是一个假设的示例。我怀疑这是否可能。Haskell在使用核心语言时被设计成内存安全的。我认为这太简单了。我想到的那种用例是一个模块,它实现了一个数据结构,其中包含一些应该由断言检查的不变量。内联没有帮助,因为数据结构和对其执行的操作不是静态的。好吧,你的问题是(除其他外)GHC如何处理未使用的模式匹配,我在这里展示了可以完全优化未使用的模式匹配。如果您问的是如何在没有运行时开销的情况下维护数据结构的不变量,那么您可能能够在类型级别表达这些不变量,这样在运行时就没有开销了。您具体考虑什么样的数据结构和不变量?