Generic higher order function

后端 未结 5 491
滥情空心
滥情空心 2020-11-30 11:55

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:



        
5条回答
  •  执笔经年
    2020-11-30 12:19

    As rkhayrov mentioned in a comment, type inference is impossible when you can have higher ranked types. In your example, you have

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

    Here are two possible types for g which are incompatible (written in a sort of hybrid F#/Haskell syntax):

    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)

    Given the first type, we could call g (fun x -> 1) ("test", true) and get (1,1). Given the second type, we could call g id ("test", true) and get ("test", true). Neither type is more general than the other.

    If you want to use higher ranked types in F#, you can, but you have to be explicit and use an intermediate nominal type. Here's one way to encode each of the possibilities above:

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

提交回复
热议问题