如何将两个函数调用合并为一个? [英] How can I consolidate two function calls into one?

查看:209
本文介绍了如何将两个函数调用合并为一个?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想合并以下几行:

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

变成这样:

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

我可以编写这样的函数吗?

注意:

我正在学习F#,如果这个问题看起来很愚蠢,我会道歉.

I am learning F# and apologize if this question seems silly.

代码如下:

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

测试:

[<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'不匹配

The type 'int' does not match the type 'string'

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"

已实施的反馈意见:

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

推荐答案

这不是确切的答案,因为我不确定您的意思,但是应该可以给您一些想法.

This is not an exact answer as I am not sure what you mean but it should give you some ideas.

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

给出以下代码后,会发生以下错误,为什么?

When given the following code the following error occurs, why?

// 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"

由于这是一个错误,指出两种类型不同意一种需要理解类型推断以及如何解决此类问题.我不会在这里解释类型推断,因为这本身就是一个大话题,但是我将给出一个模式示例,该模式在大多数情况下对我来说都是成功的,可以解决此类错误.

Since this is an error stating that two types do not agree one needs to understand type inferencing and how to resolve such problems. I will not explain type inferencing here as that is a large topic in itself, however I will give an example of a pattern that works successfully most of time for me in resolving such errors.

当F#编译代码时,它使用类型推断将缺少的类型添加到函数和值中,然后再进行类型检查,这是类型检查失败的原因.因此,要查看编译器对这些类型所看到的内容,我们将在此处手动添加它们,并剔除那些不会引起问题的代码部分,希望我们将错误原因留给我们,以便于修复某些问题.

When F# compiles code it uses type inferencing to add the missing types to functions and values before doing a type check and it is the type check that is failing. So to see what the compiler sees for the types we will manually add them here and factor out the parts of the code that are not causing a problem leaving us with the cause of the error hopefully in something then becomes obvious to fix.

唯一具有类型的东西是:

The only things that have types are:

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

这些值的类型很简单:

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

我不记得F#将equals(=)当作一个函数了,但这是怎么想的.
=:'a->'a

I don't recall F# treating equals (=) as a function but here is how to think of it.
= : 'a -> 'a

管道运算符

let (|>) (x : 'a) f = f (x : 'a)  

要解决此问题,只需将管道运算符视为语法糖.
请参阅下面的示例以更好地理解.

For resolving the problem just think of the pipeline operator as syntactic sugar.
See examples below for better understanding.

添加功能
添加:字符串->字符串->整数

The add function
add : string -> string -> int

因此,让我们将错误细化到本质.

So lets refine the error down to its essence.

//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"

将类型签名添加到值中,并验证我们是否遇到相同的错误.这就是类型推断的作用,我们是手动完成的.

Add the type signatures to the values and verify we get the same error. This is what type inferencing would do and we did it manually.

//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)

现在将代码视为可以分解的数学表达式.

Now think of the code as a mathematical expression which can be factored.

找出第一个管道运算符,并验证我们是否遇到相同的错误.请注意,错误现在只是r2的一部分

Factor out the first pipeline operator and verify we get the same error. Notice the error is now only part of r2

//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参数

Undo the syntactic sugar for the second pipeline operator and verify we get the same error. Notice the error is now only part of r2; specifically the r1 argument

//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并验证我们是否遇到相同的错误.

Add the type to r1 and verify we get the same error.

//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 .

At this point the error should be obvious. The result of the first pipeline operator is an int and is passed to the add function as the second argument. The add function expects a string for the second argument but was given an int.

为了更好地理解管道运算符的工作原理,我为此演示创建了一个等效的用户定义运算符.

To better understand how the pipeline operator works I created an equivalent user defined operator for this demonstration.

这些是演示的一些帮助功能.

These are some helper functions for the demonstration.

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

使用不带管道运算符的输出功能.

Using the output functions without the pipeline operator.

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"  

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

Notice that the output is in the same order as the input.

将输出函数与管道运算符一起使用.

Using the output functions with the pipeline operator.

//让(|>)x f = fx

// let (|>) x f = fx

"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")左侧的值.

NOTICE that the last argument for the output functions is the value on the left of the pipeline operator ("a") because of the use of the pipeline operator (|>).

//参见 F#规范关于如何定义用户定义的运算符.

// See section 3.7 of the F# specification on how to define user defined operators.

将输出函数与用户定义的管道运算符一起使用.

Using the output functions with the user defined pipeline operator.

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"  

这篇关于如何将两个函数调用合并为一个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆