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
?
答案 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|)
活动模式的多个匹配将仅使用第一个事件的结果。
<强>更新强>
答案 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