Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
498 views
in Technique[技术] by (71.8m points)

f# - Generic higher order function

Is there a reason why I can use a generic function with different type arguments when I pass it as a local value but not when passed as parameter? For example:

let f = id

let g (x,y) = (f x, f y)

g ( 1, '2')

works fine, but if I try to pass the function as parameter

let g f (x,y) = (f x, f y)

g id ( 1, '2')

it fails because it takes the version f < int > and it tries to apply it twice.

I've found a workaround but it forces me to write twice the function I'm passing:

let g f1 f2 (x,y) = (f1 x, f2 y)

g id id ( 1, '2')

This is the second time I face this problem.

Why it behaves this way, it's not supposed to be the same if the function is a local value or if it's passed as parameter?

Is there a way to do this without duplicating the function?

A hack, maybe using explicit type constraints, inline magic, quotations?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here's the inline magic. Let's take kvb's code and define a single gmap function that handles all cases:

let inline gmap f (x, y) = f $ x, f $ y

type One = One with static member ($) (One, x) = 1  // Example1 ConvertAll
type Id  = Id  with static member ($) (Id , x) = x  // Example2 PassThrough

type SeqSingleton  = SeqSingleton  with static member ($) (SeqSingleton , x) = seq [x]
type ListSingleton = ListSingleton with static member ($) (ListSingleton, x) = [x]
type ListHead      = ListHead      with static member ($) (ListHead, x) = List.head x

// Usage
let pair1 = gmap One ("test", true)
let pair2 = gmap Id  ("test", true)
let pair3 = gmap SeqSingleton  ("test", true)
let pair4 = gmap ListSingleton ("test", true)
let pair5 = gmap ListHead (["test";"test2"], [true;false])

let pair6 = ("test", true) |> gmap ListSingleton |> gmap ListHead

(* results
val pair1 : int * int = (1, 1)
val pair2 : string * bool = ("test", true)
val pair3 : seq<string> * seq<bool> = (["test"], [true])
val pair4 : string list * bool list = (["test"], [true])
val pair5 : string * bool = ("test", true)
val pair6 : string * bool = ("test", true)
*)

UPDATE

It's also possible to use the even more generic gmap function defined here then it will also work with n-uples (n < 9).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...