首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将两个函数调用合并为一个函数?

如何将两个函数调用合并为一个函数?
EN

Stack Overflow用户
提问于 2016-01-07 13:07:08
回答 2查看 114关注 0票数 3

我要合并以下几点:

代码语言:javascript
运行
复制
let result1 = add (numbers, ",")
let result2 = add (numbers, "\n")

变成这样的东西:

代码语言:javascript
运行
复制
let resultX = add (numbers, ",") |> add (numbers, "\n")

我可以这样组合函数吗?

注意:

我正在学习F#,如果这个问题看起来很傻,我很抱歉。

代码如下:

代码语言:javascript
运行
复制
module Calculator

open FsUnit
open NUnit.Framework
open System

let add (numbers:string) =

    let add (numbers:string) (delimiter:string) =
        if (numbers.Contains(delimiter)) then
            numbers.Split(delimiter.Chars(0)) |> Array.map Int32.Parse
                                              |> Array.sum
        else 0

    let result1 = add numbers ","
    let result2 = add numbers "\n"

    if (result1 > 0 || result2 > 0) then 
        result1 + result2

    else let _ , result = numbers |> Int32.TryParse
         result

测试:

代码语言:javascript
运行
复制
[<Test>]
let ``adding empty string returns zero`` () =

    let result = add ""
    result |> should equal 0

[<Test>]
let ``adding one number returns number`` () =

    let result = add "3"
    result |> should equal 3

[<Test>]
let ``add two numbers`` () =

    let result = add "3,4"
    result |> should equal 7

[<Test>]
let ``add three numbers`` () =

    let result = add "3,4,5"
    result |> should equal 12

[<Test>]
let ``line feeds embedded`` () =

    let result = add "3\n4"
    result |> should equal 7

更新

我收到以下错误:

类型'int‘与类型'string’不匹配

代码语言:javascript
运行
复制
let add (numbers:string) =

    let add (numbers:string) (delimiter:string) =
        if (numbers.Contains(delimiter)) then
            numbers.Split(delimiter.Chars(0)) |> Array.map Int32.Parse
                                              |> Array.sum
        else 0

let resultX = numbers |> add ","
                      |> add "\n"

实现反馈:

代码语言:javascript
运行
复制
let add (numbers:string) =

    let add (numbers:string) (delimiters:char array) =
        if numbers.Length = 0 then 0
        else numbers.Split(delimiters) |> Array.map Int32.Parse
                                       |> Array.sum
    let delimiters = [|',';'\n'|]
    add numbers delimiters
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-07 15:03:57

这不是一个确切的答案,因为我不知道你的意思,但它应该给你一些想法。

代码语言:javascript
运行
复制
let add01 (numbers:string) =
    let delimiters : char array = [|',';'\n'|]
    let inputArray : string array = numbers.Split(delimiters)
    let numbers : string list = Array.toList(inputArray)
    let rec add (numbers : string list) (total : int) : int =
        match (numbers : string list) with
        | ""::t ->
            add t total
        | h::t -> 
            let number =  System.Int32.Parse h
            let total = total + number
            add t total
        | [] -> total        
    add numbers 0

let numbers = "1,2,3\n4,5,6\n\n"
let result = add01 numbers

当给定以下代码时,会发生以下错误,为什么?

代码语言:javascript
运行
复制
// Type mismatch. Expecting a
//     int -> 'a    
// but given a
//     string -> int    
// The type 'int' does not match the type 'string'
let result = numbers |> add ","
                     |> add "\n"

由于这是一个错误,说明两种类型不一致,因此需要了解类型推断以及如何解决此类问题。我不会在这里解释类型推断,因为这本身就是一个很大的主题,但是我将给出一个模式的示例,它在大多数时候对我解决这些错误都是成功的。

当F#编译代码时,它使用类型推断将缺失的类型添加到函数和值中,然后再进行类型检查,而失败的是类型检查。因此,为了查看编译器看到的类型,我们将在这里手动添加它们,并计算出代码中没有引起问题的部分,让我们有可能在某种程度上解决错误的原因,然后就变得显而易见了。

唯一有类型的东西是:

  • 结果
  • =
  • 数字
  • |>
  • 添加
  • ",“
  • "\n“

这些值的类型很简单:

  • 结果: int
  • 数字:字符串
  • ",“:字符串
  • "\n“:字符串

我不记得F#将等于(=)作为一个函数对待,但下面是如何看待它的方法。

=:'a -> 'a

管道操作员

代码语言:javascript
运行
复制
let (|>) (x : 'a) f = f (x : 'a)  

要解决这个问题,只需将管道操作符看作句法糖

为了更好的理解,请参阅下面的例子。

添加函数

代码语言:javascript
运行
复制
 add : string -> string -> int

因此,让我们把错误细化到它的本质。

代码语言:javascript
运行
复制
//Type mismatch. Expecting a
//    int -> 'a    
//but given a
//    string -> int    
//The type 'int' does not match the type 'string'
let result = numbers |> add ","
                     |> add "\n"

将类型签名添加到值中,并验证我们得到相同的错误。这就是类型推断应该做的,我们手动完成了。

代码语言:javascript
运行
复制
//Type mismatch. Expecting a
//    int -> int    
//but given a
//    string -> int    
//The type 'int' does not match the type 'string'
let (result : int) = (numbers : string) |> add ("," : string) 
                     |> add ("\n" : string)

现在,把代码看作是一个可以被分解的数学表达式。

计算出第一个管道操作符,并验证我们得到了相同的误差。注意,错误现在只是r2的一部分

代码语言:javascript
运行
复制
//Expecting a
//    int -> 'a    
//but given a
//    string -> int    
//The type 'int' does not match the type 'string'
let (result : int) = 
    let r1 = (numbers : string) |> add ("," : string) 
    let r2 = r1 |> add ("\n" : string)
    r2

撤消第二个管道操作符的语法糖,并验证我们得到了相同的错误。注意,错误现在只是r2的一部分,特别是r1参数。

代码语言:javascript
运行
复制
//This expression was expected to have type
//    string    
//but here has type
//    int
let (result : int) = 
    let r1 = (numbers : string) |> add ("," : string) 
    let r2 = add ("\n" : string) r1
    r2

将类型添加到r1并验证我们得到了相同的错误。

代码语言:javascript
运行
复制
//This expression was expected to have type
//    string    
//but here has type
//    int   
let (result : int) = 
    let (r1 : int) = (numbers : string) |> add ("," : string) 
    let r2 = add ("\n" : string) r1
    r2

此时,错误应该是显而易见的。第一个管道操作符的结果是一个int,并作为第二个参数传递给add函数。add函数期望第二个参数为string,但得到了一个int

为了更好地理解管道操作符的工作方式,我为本演示创建了一个等效的用户定义操作符。

这些是演示的一些助手函数。

代码语言:javascript
运行
复制
let output1 w =
    printfn "1: %A" w

let output2 w x =
    printfn "1: %A 2: %A" w x

let output3 w x y =
    printfn "1: %A 2: %A 3: %A" w x y

let output4 w x y z =
    printfn "1: %A 2: %A 3: %A 4: %A" w x y z

使用没有管道操作符的输出函数。

代码语言:javascript
运行
复制
output1 "a"  
1: "a"  

output2 "a" "b"  
1: "a" 2: "b"  

output3 "a" "b" "c"  
1: "a" 2: "b" 3: "c"  

output4 "a" "b" "c" "d"  
1: "a" 2: "b" 3: "c" 4: "d"  

注意,输出与输入的顺序相同。

与管道操作符一起使用输出函数。

// let (|>) x= fx

代码语言:javascript
运行
复制
"a" |> output1  
1: "a"  

"a" |> output2 "b"  
1: "b" 2: "a"  

"a" |> output3 "b" "c"  
1: "b" 2: "c" 3: "a"  

"a" |> output4 "b" "c" "d"  
1: "b" 2: "c" 3: "d" 4: "a"  

注意,输出函数的最后一个参数是管道操作符("a")左侧的值,因为使用了管道操作符(|>)。

//参见关于如何定义用户定义操作符的F#规范第3.7节。

与用户定义的管道操作符一起使用输出函数。

代码语言:javascript
运行
复制
let (@.) x f = f x  

"a" @. output1  
1: "a"  

"a" @. output2 "b"  
1: "b" 2: "a"  

"a" @. output3 "b" "c"  
1: "b" 2: "c" 3: "a"  

"a" @. output4 "b" "c" "d"  
1: "b" 2: "c" 3: "d" 4: "a"  
票数 3
EN

Stack Overflow用户

发布于 2016-01-07 16:04:33

我不知道像您所要求的那样编写函数的任何通用方法,但是如果您只需要更改一个参数,一种选择是创建一个参数列表,然后映射到这些参数上:

代码语言:javascript
运行
复制
let results = [","; "\n"] |> List.map (add numbers)

如果您这样做,那么results就是一个int list,然后您需要决定如何处理这个列表。在这种情况下,对列表进行求和似乎是合适的,但考虑到当前检查result1result2是否为正的条件,这似乎不合适。

尽管如此,考虑到当前提供的测试用例,没有理由让它变得更加复杂。该实现还通过了所有测试:

代码语言:javascript
运行
复制
let add =
    let split (x : string) =
        x.Split([| ','; '\n' |], StringSplitOptions.RemoveEmptyEntries)
    split >> Array.map Int32.Parse >> Array.sum

这不是一个特别健壮的实现,因为如果字符串包含不能解析为整数的字符,那么它将失败,但OP实现也会失败。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34655981

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档