F#多条件if / else与匹配 [英] F# multi-condition if/else versus matching
问题描述
我是F#的新手,并且一直在实施简单的算法来学习语言结构。我使用 if / else
实现了对分方法,然后想要学习如何使用匹配来完成。
<$ p $如果fc = 0.0,那么printfn%i /%i - f(%f)=%f,f(%f)=%f,f(%f)=%fnew_count na如果((b-a)* 0.5),则b bb bc fc
else else eps然后printfn%i /%i - f(%f)=%f,f(%f)=%f,f(%f)=%fnew_count na fa b fb c fc
else if new_count = n then printfn%i /%i - f(%f)=%f,f(%f)=%f,f(%f)=%fnew_count na fa b fb c fc
否则,如果fc * fa< 0.0然后平分c new_count
else if fc * fb< 0.0然后bisect cb new_count
我发现使用匹配a,b,fa ,fb,fc
会导致类型错误,如果我只接受一个参数,我可以忽略参数并检查我的条件。什么是惯用的F#/功能方式来使用匹配呢?还是应该坚持if / else?
匹配a和
| a when fc = 0.0 - > (%f)=%f,f(%f)=%fnew_count n a fa b fb c fc
| a((b-a)* 0.5) eps - > (%f)=%f,f(%f)=%fnew_count n a fa b fb c fc
| a when new_count = n - > (%f)=%f,f(%f)=%fnew_count n a fa b fb c fc
| a when fc * fa< 0.0 - > bisect c new_count
| a when fc * fb< 0.0 - > bisect cb new_count
您的条件都处理不同的事情,彼此无关,所以如果
s的字符串就好了。我推荐的唯一方法是使用 elif
而不是 else if
。
match
应该被理解为给出这个可以具有不同风味的东西,这里是如何处理这些风味的。 match
的一个特别的优势是编译器会找出并告诉你,如果你错过了任何风味。特别是,你在你的问题中给出的代码应该产生一个编译器警告,抱怨不完整的模式匹配这个表达式。考虑一下:当所有情况都不匹配时,表达的结果是什么?
如果 if
s ,这也将是这种情况。例如,这不会编译:
let x = if a< 5然后7
为什么?因为编译器知道 a< 5
(即它应该是 7
),但它应该是什么?编译器不能为你做出决定,所以它会产生一个错误。
另一方面,它会编译:
let x = if a< 5 then 7 else 8
但在您的特殊情况下,编译器可以让您摆脱这种情况,因为因为 printf
返回单位$ c $>所有分支都会返回一个
单位
c>,其他都是递归的)。换句话说,下面将编译:
let x = if a a< 5然后()
以下内容:
let x = if a< 5然后printf嘘!
编译器让你避开这个,因为 unit
是特殊的:它只能有一个值(即()
),所以编译器可以为你决定结果当条件不是 true
。
这个表达式的一个实际结果是,如果你没有仔细考虑你的条件,可以想象会发生这样的情况,以至于你的条件都不是 true ,所以整个事情将返回
unit
并且不打印任何东西。我不能说这是否会在您的特定情况下发生,因为我没有看到整个函数定义。
I'm new to F# and have been implementing simple algorithms to learn the language constructs. I implemented the bisection method using if/else
and then wanted to learn how to do it using matching.
if fc = 0.0 then printfn "%i/%i - f(%f) = %f, f(%f) = %f, f(%f) = %f" new_count n a fa b fb c fc
else if ((b - a) * 0.5) < eps then printfn "%i/%i - f(%f) = %f, f(%f) = %f, f(%f) = %f" new_count n a fa b fb c fc
else if new_count = n then printfn "%i/%i - f(%f) = %f, f(%f) = %f, f(%f) = %f" new_count n a fa b fb c fc
else if fc * fa < 0.0 then bisect a c new_count
else if fc * fb < 0.0 then bisect c b new_count
I found that using match a, b, fa, fb, fc
would cause type errors, where if I took just a single parameter I could essentially ignore the parameter and check my conditions. What is the idiomatic F#/Functional way to use matching for this? Or should I just stick to if/else?
match a with
| a when fc = 0.0 -> printfn "%i/%i - f(%f) = %f, f(%f) = %f, f(%f) = %f" new_count n a fa b fb c fc
| a when ((b - a) * 0.5) < eps -> printfn "%i/%i - f(%f) = %f, f(%f) = %f, f(%f) = %f" new_count n a fa b fb c fc
| a when new_count = n -> printfn "%i/%i - f(%f) = %f, f(%f) = %f, f(%f) = %f" new_count n a fa b fb c fc
| a when fc * fa < 0.0 -> bisect a c new_count
| a when fc * fb < 0.0 -> bisect c b new_count
Your conditions all deal with disparate things, unrelated to each other, so the string of if
s is just fine. The only thing I'd recommend is using elif
instead of else if
.
match
should be understood along the lines of "given this thing that can be of different flavors, here's how to handle those flavors". One particular strength of match
is that the compiler will figure out, and tell you, if you missed any of the "flavors". In particular, the code you gave in your question should produce a compiler warning, complaining that "Incomplete pattern matches on this expression". Think about it: what would be the result of that expression when none of the cases match?
With if
s, this will also be the case. For example, this doesn't compile:
let x = if a < 5 then 7
Why? Because the compiler knows what the result should be when a < 5
(i.e. it should be 7
), but what should it be otherwise? The compiler can't decide for you, so it will generate an error.
This, on the other hand, would compile:
let x = if a < 5 then 7 else 8
But in your particular case, the compiler lets you get away with this, because all your branches return a unit
(why? because printf
returns unit
, and all others are recursive). In other words, the following will compile:
let x = if a < 5 then ()
And the following:
let x = if a < 5 then printf "boo!"
The compiler lets you get away with this, because unit
is special: it can only ever have one value (namely, ()
), so the compiler can decide for you what the result of the expression would be when the condition isn't true
.
One practical upshot of this would be that, if you didn't think about your conditions very carefuly, it could conceivably happen so that none of your conditions are true
, and so the whole thing will return unit
and not print anything. I can't say if that could happen in your particular case, because I don't see the whole function definition.
这篇关于F#多条件if / else与匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!