How do you curry the 2nd (or 3rd, 4th, …) parameter in F# or any functional language?

前端 未结 5 1499
予麋鹿
予麋鹿 2021-02-19 06:58

I\'m just starting up with F# and see how you can use currying to pre-load the 1st parameter to a function. But how would one do it with the 2nd, 3rd, or whatever other paramet

5条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-02-19 07:58

    It's possible to do this without declaring anything, but I agree with Brian that a lambda or a custom function is probably a better solution.

    I find that I most frequently want this for partial application of division or subtraction.

    > let halve = (/) >> (|>) 2.0;;
    > let halfPi = halve System.Math.PI;;
    
    val halve : (float -> float)
    val halfPi : float = 1.570796327
    

    To generalize, we can declare a function applySecond:

    > let applySecond f arg2 = f >> (|>) arg2;;
    val applySecond : f:('a -> 'b -> 'c) -> arg2:'b -> ('a -> 'c)
    

    To follow the logic, it might help to define the function thus:

    > let applySecond f arg2 =
    -     let ff = (|>) arg2
    -     f >> ff;;
    val applySecond : f:('a -> 'b -> 'c) -> arg2:'b -> ('a -> 'c)
    

    Now f is a function from 'a to 'b -> 'c. This is composed with ff, a function from 'b -> 'c to 'c that results from the partial application of arg2 to the forward pipeline operator. This function applies the specific 'b value passed for arg2 to its argument. So when we compose f with ff, we get a function from 'a to 'c that uses the given value for the 'b argument, which is just what we wanted.

    Compare the first example above to the following:

    > let halve f = f / 2.0;;
    > let halfPi = halve System.Math.PI;;
    
    val halve : f:float -> float
    val halfPi : float = 1.570796327
    

    Also compare these:

    let filterTwoDigitInts = List.filter >> (|>) [10 .. 99]
    let oddTwoDigitInts = filterTwoDigitInts ((&&&) 1 >> (=) 1)
    let evenTwoDigitInts = filterTwoDigitInts ((&&&) 1 >> (=) 0)
    
    let filterTwoDigitInts f = List.filter f [10 .. 99]
    let oddTwoDigitInts = filterTwoDigitInts (fun i -> i &&& 1 = 1)
    let evenTwoDigitInts = filterTwoDigitInts (fun i -> i &&& 1 = 0)
    

    Alternatively, compare:

    let someFloats = [0.0 .. 10.0]
    let theFloatsDividedByFour1 = someFloats |> List.map ((/) >> (|>) 4.0)
    let theFloatsDividedByFour2 = someFloats |> List.map (fun f -> f / 4.0)
    

    The lambda versions seem to be easier to read.

提交回复
热议问题