模式匹配时间复杂度 Haskell

Pattern Matching Time Complexity Haskell

我正在尝试了解模式匹配的时间复杂度。我认为 foo 中的匹配类型将花费恒定时间,而 bar 中的匹配模式将花费 O(n),但我无法通过调试器逐步解决。

module Main where

data Foo = Bar | Baz | Cat

main :: IO ()
main =
  do
  print $ foo Baz
  line <- getLine
  let x = read line :: Int
  print $ bar [x,2,3]

-- Constructors of Foo known in advance 
-- So this can be a jump table
foo :: Foo -> Int
foo Bar = 1
foo Baz = 2
foo Cat = 3

-- Elements of list can't be known in advance
-- So this should take O(n) ???
bar :: [Int] -> Int
bar [] = 0
bar (x:[]) = 1
bar (1:x:xs) = 2
bar (y:x:xs) = 3

这个模式的时间复杂度是多少?

我用 -O2 编译了你的 bar 并生成了这个核心。评论是我的,并显示 compiler-generated 附加标识符的定义。

bar
  = \ (ds_d35K :: [Int]) ->
      case ds_d35K of {
        [] -> Main.bar4;            -- GHC.Types.I# 0#
        : x_a13j ds1_d35U ->
          case ds1_d35U of {
            [] -> Main.bar3;        -- GHC.Types.I# 1#
            : ipv_s3na ipv1_s3nb ->
              case x_a13j of { GHC.Types.I# ds2_d35V ->
              case ds2_d35V of {
                __DEFAULT -> Main.bar2;  -- GHC.Types.I# 3#
                1# -> Main.bar1          -- GHC.Types.I# 2#
              }
              }
          }
      }

正如我们所见,编译器测试了第一个构造函数([] vs :),然后是第二个,依此类推。它没有在同一个块中对同一个构造函数进行重复测试。

据我所知,Haskell 报告本身并未强制要求模式匹配具有特定的复杂性。由 Haskell 实现(例如 GHC)提供良好的优化水平。您可以期望 pattern-matching 以一种相当有效的方式编译,因为它是该语言最基本和普遍存在的结构之一。

要重现这一点,您可以使用 -O2 -ddump-simpl 进行编译并观察输出。