可能的F#类型推断限制 [英] Possible F# type inference limitation

查看:47
本文介绍了可能的F#类型推断限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很确定自己会遇到某种限制,但我不明白:

I'm quite sure that I run into some kind of limitation, but I do not understand it:

type IRunner = 
    abstract member Run : (string -> 'a) -> 'a
type T() = 
    let run4 doFun = doFun "4"
    let run5 doFun = doFun "5"
    let parseInt s = System.Int32.Parse(s)
    let parseFloat s = System.Double.Parse(s)
    let doSomething () = 
        let i = parseInt |> run4
        let f = parseFloat |> run4
        f |> ignore

    // Make it more generic ->
    //let doSomething2 (runner:(string->'a)->'b) =
    let doSomething2 runner = 
        // Error on the following lines with both declarations
        let i = parseInt |> runner
        let f = parseFloat |> runner
        f |> ignore

    // Want to do something like
    let test () = 
        doSomething2 run4
        doSomething2 run5

    // Workaround
    let workaround (runner:IRunner) = 
        let run f = runner.Run f
        let i = parseInt |> run
        let f = parseFloat |> run
        f |> ignore

有人可以对此有所启发吗?我没有找到任何相关的问题,对不起,如果我重复了一些事情.

Can somebody bring some light over this? I did not find any related question, sorry if i duplicated something.

推荐答案

问题是,如果doSomething2具有类型((string->'a) -> 'b) -> unit,则'a'b在每次调用doSomething2时都是固定的,这不是您想要的-在您的情况下,在调用期间,'a需要同时作为intfloat对待.

The problem is, if doSomething2 has type ((string->'a) -> 'b) -> unit, then 'a and 'b are fixed during each invocation of doSomething2, which isn't what you want - in your case 'a needs to treated as both int and float during a single invocation of doSomething2.

您似乎真正想要的更像是:doSomething2 : (forall 'a. (string -> 'a) -> 'a) -> unit,但是F#中不存在这种直接的通用量化.如您所见,解决此问题的方法是将类型与泛型方法一起使用.

It seems like what you really want is more like: doSomething2 : (forall 'a. (string -> 'a) -> 'a) -> unit, but that kind of direct universal quantification doesn't exist in F#. As you've discovered, the way to work around this is to use a type with a generic method.

即使F#支持forall类型,正如我在评论中提到的那样,仍然是不可能的.考虑您的doSomething2函数-我们知道runner需要能够将类型为string -> int的输入转换为某种输出类型,并将类型为string -> float的输入转换为某种(可能是不同的)输出类型.以下是doSomething2的几个不同的签名,都满足此要求:

And even if F# did support forall types, as I mentioned in a comment inference still wouldn't be possible. Consider your doSomething2 function - we know that runner needs to be able to take an input of type string -> int to some output type and an input of type string -> float to some (possibly different) output type. Here are several different signatures for doSomething2 that all meet this requirement:

  1. forall 'a. 'a -> 'a
  2. forall 'a. (string -> 'a) -> 'a
  3. forall 'a. 'a -> unit
  1. forall 'a. 'a -> 'a
  2. forall 'a. (string -> 'a) -> 'a
  3. forall 'a. 'a -> unit

请注意,这些类型都不比其他类型更通用,它们都是不兼容的.在第一种情况下,可以将id传递给函数,在第二种情况下,可以将run4传递给该函数,在第三种情况下,可以将ignore传递给该函数(但是这些函数都不是与其他可能的签名兼容!).

Note that none of these types is more general than the others, they are all incompatible. In the first case, we could pass id to the function, in the second case, we could pass run4 to it, and in the third case, we could pass ignore to it (but none of those functions is compatible with the other possible signatures!).

这篇关于可能的F#类型推断限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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