3

我编写了一个函数,它将一个数组作为输入并返回一个大小相等的数组作为输出。例如:

myFunc [| "apple"; "orange"; "banana" |]
> val it : (string * string) [] =
    [|("red", "sphere"); ("orange", "sphere"); ("yellow", "oblong")|]

现在我想通过 let 绑定来分配结果。例如:

let [|
        ( appleColor, appleShape );
        ( orangeColor, orangeShape );
        ( bananaColor, bananaShape )
    |] = 
    myFunc [| "apple"; "orange"; "banana" |]

哪个效果很好...

> val orangeShape : string = "sphere"
> val orangeColor : string = "orange"
> val bananaShape : string = "oblong"
> val bananaColor : string = "yellow"
> val appleShape : string = "sphere"
> val appleColor : string = "red"

...除了它会产生警告:

warning FS0025: Incomplete pattern matches on this expression. For example, the value '[|_; _; _; _|]' may indicate a case not covered by the pattern(s).

警告的来源和原因已经介绍过,我只是在寻找一个简洁的解决方法。这个函数调用发生在我的函数顶部附近,我不喜欢将整个函数体放在一个匹配项中的想法:

let otherFunc =
    match myFunc [| "apple"; "orange"; "banana" |] with
    | [|
        ( appleColor, appleShape );
        ( orangeColor, orangeShape );
        ( bananaColor, bananaShape )
      |] ->
        // ... the rest of my function logic
    | _ -> failwith "Something impossible just happened!"

那只是闻起来很糟糕。我也不喜欢忽略警告的想法——违背了我更好的判断。是否有其他选择可供我选择,还是我只需要完全找到不同的方法?

4

2 回答 2

5

如果您希望这种调用模式频繁出现,一种可能性是制作对您期望的元组大小起作用的包装器,例如

myFunc3 (in1,in2,in3) =
    match myFunc [|in1;in2;in3|] with
    [|out1;out2;out3|] -> out1, out2, out3
    _ -> failwith "Internal error"

等等。但它所做的只是将丑陋的代码移动到标准位置,并且写出包装器会很不方便。

我不认为这个 API 有更好的选择,因为没有办法告诉编译器myFunc总是返回它传递的相同数量的元素。

另一种选择可能是myFunc用一个IDisposable类替换:

type MyClass() =
   let expensiveResource = ...


   member this.MyFunc(v) = ...calculate something with v using expensiveResource

   interface IDisposable with
       override this.Dispose() = // cleanup resource

然后在一个块中使用它

use myClass = new MyClass()
let appleColor, appleShape = myClass.MyFunc(apple)
...
于 2014-01-29T21:48:27.003 回答
0

改编@Ganesh的答案,这是解决问题的一种原始方法:

let Tuple2Map f (u, v) 
    = (f u, f v)

let Tuple3Map f (u, v, w) 
    = (f u, f v, f w)

let Tuple4Map f (u, v, w, x) 
    = (f u, f v, f w, f x)

例子:

let Square x = x * x
let (a,b) = Tuple2Map Square (4,6)
// Output:
// val b : int = 36 
// val a : int = 16

但我想更原始的东西是这样的:

let Square x = x * x
let (a,b) = (Square 4, Square 6)

如果函数名太长,例如

// Really wordy way to assign to (a,b)
let FunctionWithLotsOfInput w x y z = w * x * y * z
let (a,b) = 
    (FunctionWithLotsOfInput input1 input2 input3 input4A,
     FunctionWithLotsOfInput input1 input2 input3 input4B)

我们可以定义临时函数

let FunctionWithLotsOfInput w x y z = w * x * y * z
// Partially applied function, temporary function 
let (a,b) =
    let f = (FunctionWithLotsOfInput input1 input2 input3)
    (f input4A, f input4B)
于 2017-09-06T06:36:14.360 回答