为什么模式匹配定义不能成为Haskell中的闭包?

1 closures haskell scope pattern-matching

为什么不接受这些伪Haskell函数定义?

f n = if n<3 then n else g 2 2 1 0 where
    g n a b c = a  -- note that 'n' is a value of the enclosing scope
    g k a b c = g (k+1) (a+2*b+3*c) a b
Run Code Online (Sandbox Code Playgroud)

计算这个"运动功能": f(n) = n if n<3 else f(n-1) + 2*f(n-2) + 3*f(n-3)

fib n = let
     f n a b = b  -- note that 'n' is a value of the enclosing scope
     f k a b = f (k+1) b (a+b)
  in f 1 0 1
Run Code Online (Sandbox Code Playgroud)

用于计算斐波那契数.当然这有效:

fib n = let { f k a b = if k==n then b else f (k+1) b (a+b);} in f 1 0 1
Run Code Online (Sandbox Code Playgroud)

但是在这个例子中where和一个中let,我得到了

Warning: Pattern match(es) are overlapped
Run Code Online (Sandbox Code Playgroud)

为什么我不能使用模式匹配来定义函数闭包,并使用从封闭范围获取的值?

这是因为封闭范围的值是在运行时确定的(通常)由于某种原因(什么原因?)编译器无法编排它?

Nic*_*las 10

这是语言设计选择:不能对变量进行模式匹配.它可以避免棘手的大脑体操来决定你是否与现有变量进行模式匹配,或者你是否声明了一个局部变量.实际上,看一下这个例子:

Foo.hs:

module Foo where

foo: Int = 42
Run Code Online (Sandbox Code Playgroud)

Bar.hs:

module Bar where

import Foo

bar :: Int -> Bool
bar foo = True
bar _ = False
Run Code Online (Sandbox Code Playgroud)

foo通过查看Bar.hs ,你不能轻易猜到这是受约束的.具有需要上下文来决定是声明新变量还是使用现有变量的语法具有误导性.

作为一种解决方法,您仍然可以使用警卫:

f n = if n<3 then n else g 2 2 1 0 where
    g k a _ _ | k == n = a
    g k a b c = g (k+1) (a+2*b+3*c) a b
Run Code Online (Sandbox Code Playgroud)

要么

f n = if n<3 then n else g 2 2 1 0 where
    g k a b c | k == n = a
              | otherwise = g (k+1) (a+2*b+3*c) a b
Run Code Online (Sandbox Code Playgroud)

  • 在(长期死亡的)函数语言ALFL(来自耶鲁大学)中你可以说`#n`而不是`n`来表示你想要匹配变量的值而不是绑定.在Haskell你必须说'... n'... | n'== n`.或者使用`ViewPatterns`,你可以说`(True < - (== n))`. (2认同)