Scala';“的概念;“部分函数”'&;这是一个很好的例子;。orElse“;F中的方法#
在Scala中有一个“部分函数”的概念,它与F#的Scala';“的概念;“部分函数”'&;这是一个很好的例子;。orElse“;F中的方法#,scala,f#,partialfunction,Scala,F#,Partialfunction,在Scala中有一个“部分函数”的概念,它与F#的函数关键字允许我实现的功能非常相似。然而,Scala的部分函数也允许通过orElse方法进行合成,如下所示: def intMatcher:PartialFunction[Any,String]={ 案例:Int=>“Int” } def stringMatcher:PartialFunction[Any,String]={ 大小写:String=>“String” } def defaultMatcher:PartialFunction[任何,
函数
关键字允许我实现的功能非常相似。然而,Scala的部分函数也允许通过orElse
方法进行合成,如下所示:
def intMatcher:PartialFunction[Any,String]={
案例:Int=>“Int”
}
def stringMatcher:PartialFunction[Any,String]={
大小写:String=>“String”
}
def defaultMatcher:PartialFunction[任何,字符串]={
案例=>“其他”
}
瓦尔·姆斯甘德勒=
内匹配器
.orElse(stringMatcher)
.orElse(默认匹配器)
msgHandler(5)//res0:String=“Int”
我需要知道是否有办法在F#中实现相同的合成功能。我可能会在这里使用部分活动模式,这样您就可以使用模式匹配。有些(T)匹配,没有一个不匹配
let (|Integer|_|) (str: string) =
let mutable intvalue = 0
if System.Int32.TryParse(str, &intvalue) then Some(intvalue)
else None
let (|Float|_|) (str: string) =
let mutable floatvalue = 0.0
if System.Double.TryParse(str, &floatvalue) then Some(floatvalue)
else None
let parseNumeric str =
match str with
| Integer i -> "integer"
| Float f -> "float"
| _ -> "other"
但值得注意的是,在这个人为设计的情况下,您提供的语句可以只使用一个匹配语句。我想你的目标是把比赛条件分开
let msgHandler (x: obj) =
match x with
| :? int -> "integer"
| :? float -> "float"
| _ -> "other"
我想出了两个解决方案来实现我的确切目标。一种是通过使用活动模式:
让orElse(回退:a->(单位->'b)选项)(匹配器:a->(单位->'b)选项)(arg:(单位->'b)选项=
let first=匹配器(arg)
首当其冲
|首先是一些
|无->回退(arg)
let(| StringCaseHandler | |)(arg:obj)=
将arg与
| :? 字符串->一些(乐趣()->“字符串”)
|无
let(| IntCaseHandler | |)(arg:obj)=
将arg与
| :? int->Some(fun()->“integer”)
|无
let(| DefaultCaseHandler | |)(arg:'a)=
一些(乐趣()->“其他”)
让msgHandler=
``|StringCaseHandler | | ````>
orElse```IntCaseHandler```
orElse``DefaultCaseMandler|_|``
具有活动模式的解决方案是安全的,因为在没有正确匹配的情况下,它不会抛出MatchFailureException
;而是返回一个None
第二个涉及为'a->'b
类型的函数定义一个扩展方法,并且尽可能接近Scala的“部分函数”orElse
行为,该行为在生成的函数未产生正确匹配时引发异常:
[]
类型FunctionExtension()=
[]
静态成员内联OrElse(self:'a->'b,fallback:'a->'b):'a->'b=
有趣的arg->
尝试
自我(arg)
具有
| :? MatchFailureException->回退(arg)
let intMatcher:obj->string=function
| :? int->“整数”
让stringMatcher:obj->string=function
| :? 字符串->“字符串”
让defaultMatcher:obj->string=function
|——>“其他”
让msgHandler:obj->string=intMatcher
.OrElse(stringMatcher)
.OrElse(默认匹配器)
在Scala中编写它的方式相当于在C#中使用扩展方法。对于函数式编程来说,它不是特别惯用的。要严格使用F#中的可组合函数,您可以这样做
// reusable functions
let unmatched input = Choice1Of2 input
let orElse f =
function
| Choice1Of2 input -> f input
| Choice2Of2 output -> Choice2Of2 output
let withDefault value =
function
| Choice1Of2 _ -> value
| Choice2Of2 output -> output
// problem-specific functions
let matcher isMatch value x =
if isMatch x then Choice2Of2 value
else Choice1Of2 x
let isInt (o : obj) = o :? int
let isString (o : obj) = o :? string
let intMatcher o = matcher isInt "Int" o
let stringMatcher o = matcher isString "String" o
// composed function
let msgHandler o =
unmatched o
|> orElse intMatcher
|> orElse stringMatcher
|> withDefault "other"
这里,
Choice1Of2
表示我们还没有找到匹配项,并且包含不匹配的输入。而Choice2of2
意味着我们找到了一个匹配项并包含输出值。显然,部分模式的代价是,如果不涵盖所有可能的情况,就不会得到警告。这很接近。但是,与您的情况中的正确匹配相关的printf
行为不是由活动模式匹配器处理的,并且留给主parseNumeric
函数处理。我正在寻找一个函数中匹配及其相关行为的封装,就像Scala的例子一样。您可以返回字符串而不是打印它。我将更新我的答案。我发布了我自己的答案,其中显示了我如何在一个地方处理匹配和相关行为的封装。你的不是我想要的,因为它仍然将处理箭头的左侧留给主处理函数。在我的回答中,我清楚地展示了它是如何反转的,并且由活动模式本身决定要做什么return@shayan这就是F#中基于模式的编程是如何完成的。您考虑一个案例(即箭头的左侧)并基于该案例分派功能。你自己的答案并没有改变这一点,它只是把每个案例放在它自己的功能中。这可以用F#轻松完成,但并不是更好的解决方案。活动模式实际上只是一个名字怪异的函数,允许在模式匹配中使用它们。但是,由于在模式匹配中没有使用它们,您可能应该只编写名为stringCaseHandler
、intCaseHandler
和defaultCaseHandler
的函数。我的看起来很奇怪如果你真的想要异常,我想你可能不应该,你可以很容易地定义你的默认函数来抛出一个异常,而不是返回“other”
。