为什么恒等函数有时会改变模式是否详尽?

Jos*_*ica 6 haskell pattern-matching compiler-warnings

考虑这个 GHCi 会话:

$ ghci
GHCi, version 8.6.5: http://www.haskell.org/ghc/  :? for help
Prelude> :set -Wincomplete-patterns -Wincomplete-uni-patterns
Prelude> foo t | (_, _) <- t = "Foo"
Prelude> bar t | (_, _) <- id t = "Foo"
Prelude> baz x | Just _ <- x = "Yes" | Nothing <- x = "No"
Prelude> qux x | Just _ <- id x = "Yes" | Nothing <- id x = "No"

<interactive>:3:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for ‘qux’: Patterns not matched: _
Prelude>
Run Code Online (Sandbox Code Playgroud)

为什么quxGHC 认为不完整?我们真的id x比我们知道的更多x吗?为什么也不会bar因为同样的原因而qux被认为是不完整的?

或者一个可能更清楚的例子:

foo f x
  | Just _ <- f x = "Yes"
  | Nothing <- f x = "No"

bar f x = case f x of
  Just _ -> "Yes"
  Nothing -> "No"
Run Code Online (Sandbox Code Playgroud)

据我所知,这些完全等效,但前者产生警告而后者则不会。

Car*_*arl 9

除非表达式是单个绑定,否则 GHC 似乎不会将相同的表达式视为模式保护中的相同值:

Prelude> f | Just x <- Just 1 = "foo" | Nothing <- Just 1 = "bar"

<interactive>:5:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for ‘f’: Guards do not cover entire pattern space
Run Code Online (Sandbox Code Playgroud)

这更愚蠢,因为很明显这些模式是详尽无遗的。它甚至不能分支。

我会说这可能是正确的做事方式,即使它很奇怪。它鼓励将表达式绑定到名称,这有助于确保表达式只计算一次。不过,这肯定是一种迂回的方式。

至于为什么你没有在 中得到那个错误bar,那是因为成对只有一个构造函数。您正在匹配 的所有可能输出id t,即使它是计算表达式。没有您不匹配的替代构造函数。

  • “因为表达式不同”——实际上它们不是,都是“id x”。 (3认同)