F#短路模式匹配

时间:2011-08-05 04:23:50

标签: .net visual-studio f# functional-programming

F#的新手。以下问题可能毫无意义。

// an attempt at Huffman encoder 
let encodeValue x y = function ...

match ((encodeValue left value), (encodeValue right value)) with
    | ((true, encoded), (_, _)) -> (true, encoded + "1")
    | ((_, _), (true, encoded)) -> (true, encoded + "0")
    | ((false, _), (false, _)) -> (false, "")
    | _ -> failwith "Error"

在真实环境中,encodeValue可能非常昂贵。是否有可能(或合理)要求F#首先评估encodeValue left value,尝试匹配,然后在必要时执行encodeValue right value

4 个答案:

答案 0 :(得分:4)

您可以使用延迟值和活动模式很好地模拟短路:

//not sure why function Lazy.force is recognized in VS but not in FSI
//need to use member Force()
let (|Force|) (l:Lazy<_>) =
    l.Force()

let encodeValue x y = function ...

match (encodeValue left value), lazy(encodeValue right value) with
    | (true, encoded), _                    -> (true, encoded + "1")
    | _              , Force(true, encoded) -> (true, encoded + "0")
    | (false, _)     , Force(false, _)      -> (false, "")
    | _                                     -> failwith "Error"

Lazy值的计算值为0或1次:如果您从未对它们调用Force(),则永远不会计算它们。第一次拨打Force()时,系统会计算Force(),并在每次拨打(|Force|)时保存结果。

_这里是一个完整的活动模式,一个非常简洁的功能,允许您实现各种类型的自定义模式匹配结构。

注意@Brian指出你需要在可以进行短路的惰性值位置使用(true, encoded)。如果(|Force|)匹配,则永远不会强制进行懒惰,昂贵的计算。然后对于每个其他情况,使用(|Force|)活动模式的多个匹配将仅使用第一个事件的结果。

<强>更新

@Daniel指出,F#已经有一个活跃的模式,完全符合{{1}}的作用:http://msdn.microsoft.com/en-us/library/ee340223.aspx

答案 1 :(得分:2)

这是另一种活跃的模式解决方案。将部分应用的函数传递给活动模式:

let (|Encoded|_|) f x = 
  match f x with
  | true, encoded -> Some encoded
  | _ -> None

match value with
  | Encoded (encodeValue left) encoded -> (true, encoded + "1")
  | Encoded (encodeValue right) encoded -> (true, encoded + "0")
  | _ -> (false, "")

我放弃了最后一个模式,因为它永远不会匹配。

答案 2 :(得分:2)

活动模式解决方案更酷但我认为至少值得一提的是,一个简单的嵌套匹配在这里看起来也很顺利:

  match encodeValue left value with
    | true, e -> true, e + "1"
    | false, _ -> 
      match encodeValue right value with
        | true, f -> true, f + "0"
        | _ -> false, ""

答案 3 :(得分:1)

由于F#不是懒惰的函数式语言(你可以使表达式评估显式延迟)。 你可以做的是分解模式匹配,如下所示。

let a() = match encodeValue left value with
          | (true,encoded) -> (true,encoded + "1")
          | _ -> (false,"")
let b() = match encodeValue right value with
          | (true,encoded) -> (true,encoded + "0")
          | _ -> (false,"")
match a() with
| (false,_) -> b()
| r -> r