通用高阶函数

Mic*_*ael 6 generics f# inline

当我将其作为本地值传递但不作为参数传递时,我是否可以使用具有不同类型参数的泛型函数?例如:

let f = id

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

g ( 1, '2')
Run Code Online (Sandbox Code Playgroud)

工作正常,但如果我尝试将函数作为参数传递

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

g id ( 1, '2')
Run Code Online (Sandbox Code Playgroud)

它失败,因为它采用版本f <int>并尝试将其应用两次.

我找到了一个解决方法,但它迫使我写两次我正在传递的函数:

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

g id id ( 1, '2')
Run Code Online (Sandbox Code Playgroud)

这是我第二次遇到这个问题.

为什么它以这种方式运行,如果函数是本地值或者它作为参数传递,它不应该是相同的?

有没有办法在不重复功能的情况下执行此操作?

一个黑客,可能使用显式类型约束,内联魔术,引用?

Gus*_*Gus 7

这是内联魔术.让我们采用kvb的代码并定义一个gmap处理所有情况的函数:

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)
*)
Run Code Online (Sandbox Code Playgroud)

UPDATE

也可以使用此处gmap定义的更通用的函数,然后它也可以使用n-uples(n <9).


kvb*_*kvb 6

正如rkhayrov在评论中提到的,当你可以拥有更高排名的类型时,类型推断是不可能的.在你的例子中,你有

let g f (x,y) = (f x, f y)
Run Code Online (Sandbox Code Playgroud)

以下是两种可能g不兼容的类型(用一种混合的F#/ Haskell语法编写):

  1. forall'b,'c,'d.((forall'a.'a - >'b) - >'c*'d - >'b*'b)
  2. forall'c,'d.(forall'a.'a - >'a) - >'c*'d - >'c*'d)

鉴于第一种类型,我们可以打电话来g (fun x -> 1) ("test", true)获取(1,1).鉴于第二种类型,我们可以打电话来g id ("test", true)获取("test", true).两种类型都不比另一种更通用.

如果你想在F#中使用排名较高的类型,你可以,但你必须明确并使用中间名义类型.以下是编码上述每种可能性的一种方法:

module Example1 = 
    type ConvertAll<'b> =
        abstract Invoke<'a> : 'a -> 'b

    let g (f:ConvertAll<'b>) (x,y) = (f.Invoke x, f.Invoke y)

    //usage
    let pair = g { new ConvertAll<int> with member __.Invoke(x) = 1 } ("test", true)

module Example2 = 
    type PassThrough =
        abstract Invoke<'a> : 'a -> 'a

    let g (f:PassThrough) (x,y) = (f.Invoke x, f.Invoke y)

    //usage
    let pair = g { new PassThrough with member __.Invoke(x) = x } ("test", true)
Run Code Online (Sandbox Code Playgroud)