避免使用计算表达式的厄运金字塔



我遇到了有关f#中的"厄运金字塔"的问题。那里接受的答案涉及使用主动模式,但是我的理解是,它也可以使用计算表达式来解决。

如何使用计算表达式从此代码中删除"厄运的金字塔"?

match a.TryGetValue(key) with
| (true, v) -> v
| _ -> 
  match b.TryGetValue(key) with
  | (true, v) -> v
  | _ -> 
    match c.TryGetValue(key) with
    | (true, v) -> v
    | _ -> defaultValue

f#以获取乐趣,利润有一个特定情况的示例:

type OrElseBuilder() =
    member this.ReturnFrom(x) = x
    member this.Combine (a,b) = 
        match a with
        | Some _ -> a  // a succeeds -- use it
        | None -> b    // a fails -- use b instead
    member this.Delay(f) = f()
let orElse = new OrElseBuilder()

但是,如果要与IDictionary一起使用它,则需要一个返回选项的查找功能:

let tryGetValue key (d:System.Collections.Generic.IDictionary<_,_>) =
    match d.TryGetValue key with
    | true, v -> Some v
    | false, _ -> None

现在,这是其使用 f#的修改示例。

let map1 = [ ("1","One"); ("2","Two") ] |> dict
let map2 = [ ("A","Alice"); ("B","Bob") ] |> dict
let map3 = [ ("CA","California"); ("NY","New York") ] |> dict
let multiLookup key = orElse {
    return! map1 |> tryGetValue key
    return! map2 |> tryGetValue key
    return! map3 |> tryGetValue key
    }
multiLookup "A" // Some "Alice"

我喜欢的"毁灭性金字塔"去除的模式是:

1)创建一个懒惰的输入集合2)用计算功能映射它们3)跳过所有产生不可接受结果的计算4)选择符合您条件的第一个。

但是,这种方法不使用计算表达式

open System.Collections
let a = dict [1, "hello1"]
let b = dict [2, "hello2"]
let c = dict [2, "hello3"]
let valueGetter (key:'TKey) (d:Generic.IDictionary<'TKey, 'TVal>) =
    (
        match d.TryGetValue(key) with
        | (true, v) -> Some(v)
        | _ -> None
    )
let dicts = Seq.ofList [a; b; c] // step 1
let computation data key =
    data
    |> (Seq.map (valueGetter key)) // step 2
    |> Seq.skipWhile(fun x -> x = None) // step 3
    |> Seq.head // step 4
computation dicts 2

如果我们颠覆Bind方法,可以实现短路表达式,在该方法中,我们可以简单地忽略其余的计算并将其替换为成功匹配。另外,我们可以迎合标准字典查找的bool*string签名。

type OrElseBuilder() =
    member __.Return x = x
    member __.Bind(ma, f) =
        match ma with
        | true, v -> v
        | false, _ -> f ()
let key = 2 in OrElseBuilder() {
    do! dict[1, "1"].TryGetValue key
    do! dict[2, "2"].TryGetValue key
    do! dict[3, "3"].TryGetValue key
    return "Nothing found" }
// val it : string = "2"

相关内容

  • 没有找到相关文章

最新更新