Scala';“的概念;“部分函数”'&;这是一个很好的例子;。orElse“;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中有一个“部分函数”的概念,它与F#的
函数
关键字允许我实现的功能非常相似。然而,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”