假设我写了一个函数
f [x, y] = x + y
f [x, y, z] = z - x - y
这是由编译器用额外的行填写的,例如
f _ = error "pattern match failed"
如果f
未导出,而我知道它只能正确应用,并且该功能对性能至关重要,我可能希望避免使用额外的模式生产代码。我可以重写这个非常不自然的东西,比如
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
当断言或推断的安全Haskell被启用时,描述性命名的魔法函数将编译为 解决jberryman对是否存在真正的性能影响的担忧: 这是一个假设的问题。我怀疑在更复杂的情况下,有多个"不会发生"在某些情况下,可能会有性能优势 - 至少,错误情况可能会在指令缓存中占用额外的空间。 即使不是真正的性能问题,我认为断言和错误之间也存在表达的区别。我怀疑最灵活的断言形式是"这段代码应该是无法访问的,而且可能带有一个或三个参数,表明编译器应该认真对待这个声明。安全性是相对的 - 如果数据结构不变被破坏并导致程序泄露机密信息,那么不一定比无效的存储器访问更严重。请注意,粗略地说,f _ = makeDemonsComeOutOfMyNose "This error is impossible."
error
,并在禁用断言时标记为无法访问(使模式匹配不安全)。有没有办法做到这一点,或类似的东西?修改
assert p x = if p then x else makeDemonsFlyOutOfMyNose NO_REAL_DEMONS_PLEASE "assertion failed"
,但没有办法根据assert
定义恶魔函数。
答案 0 :(得分:3)
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
error
案例未显示在核心Foo
的任何位置。因此,您可以放心,在这种情况下,通过额外的未使用模式匹配绝对没有性能差异。