Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 在什么条件下,机组是a型的?_Generics_F# - Fatal编程技术网

Generics 在什么条件下,机组是a型的?

Generics 在什么条件下,机组是a型的?,generics,f#,Generics,F#,在将其标记为重复之前:我知道这个问题与使用unit作为类型参数时有关编译错误的各种问题有关。一些例子: 这些都遇到了与此类似的问题: type Interface<'a> = abstract member MyFunc : unit -> 'a let implementingInstance = { new Interface<_> with member __.MyFunc () = () } // Compiler

在将其标记为重复之前:我知道这个问题与使用unit作为类型参数时有关编译错误的各种问题有关。一些例子:

这些都遇到了与此类似的问题:

type Interface<'a> = 
    abstract member MyFunc : unit -> 'a

let implementingInstance =
  { new Interface<_> with
        member __.MyFunc () = () } // Compiler error!
如果我用lambda或
let
绑定的模块函数替换
ignore
,这同样有效

对我来说,这只是完全相同事物的另一种表述。(尽管与F#设计指南不一致,后者建议优先选择接口而不是承载函数的记录类型。)

我对设计API感兴趣,这些API的用户可以指定所使用的行为和类型。因此,我希望避免出现意外和令人困惑的编译器错误。但我不太确定该怎么做。看起来F#的“函数”函数确实将单元视为一种类型


这种装置产生虚假错误的确切条件是什么?我是否可以在API中通过违反设计准则并使用函数记录而不是接口来避免它们?(我不太介意,但我不确定它是否能很好地解决问题。)

您的工作示例和非工作示例之间的区别在于,非工作示例是一种方法,在这种情况下(仅在这种情况下),F#编译器生成的IL代码实际接受或返回
void
。在工作情况下,它是一个类型为
Microsoft.FSharp.Core.FSharpFunc
(又称
unit->unit
)的属性,它不会“优化”到接收或返回
void

所以,是的,使用记录确实很好地解决了这个问题。另一种可能是与属性建立接口:

type Interface<'a> = 
    // Note the parentheses to make this member a property rather than a method
    abstract member MyFunc : (unit -> 'a)

let implementingInstance =
    { new Interface<_> with
        // Must use an explicit `fun () ->` instead of a method arg list
        member __.MyFunc = fun () -> () }
type Interface`而不是方法参数列表
成员_uu.MyFunc=fun()->()}

如果您的问题是将unit作为参数,那么可以通过编写一个将
(())
作为参数的方法(即显式
unit
值,而不是空的参数列表)来解决。但是对于返回值,我认为没有任何方法可以使该方法工作:/

我相信规则是静态已知的返回类型为
单位的方法将在.NET类型系统中编译为返回类型为
无效的.NET方法(静态已知,我的意思是与泛型方法或泛型类型上使用类型参数作为返回类型的方法相反)。在调用时,编译器隐藏了在CLR级别返回
void
的方法和返回true
unit
值的方法之间的区别

示例中出现的问题是因为正确实现通用接口实际上需要CLR级别的
单元
返回类型(CLR确实关心
单元
无效
之间的区别)。换句话说,当且仅当您希望通过静态已知返回
unit
的方法重写返回泛型类的类型参数的方法时,才会出现问题(基于将该类型参数替换为
unit
).这里的重写是指在类或接口上实现抽象方法,或者在类上重写非密封方法


正如泰米尔所指出的,解决这一限制的一种方法是确保使用F#函数而不是方法。另一种解决方法是在层次结构中引入一个额外的具体类,该类有一个伪泛型类型参数(比如额外的类是
T
,而不是
()
任何可能导致问题的地方。然后你可以从
T
派生出一个额外的非泛型具体类
T
,一切都会正常工作。

荒谬的::Void->a(Haskell)我认为这有点相关;-)因为这是关于通用API的设计,这可能是相关的:似乎这个问题只发生在实现抽象成员方法时?但是为什么除了泛型和方法之外,这个问题还特定于继承/接口?比如,我做了一个
类型,这解释了它!谢谢,我有点希望你能过来回答这个问题一个。:)
type Interface<'a> = 
    // Note the parentheses to make this member a property rather than a method
    abstract member MyFunc : (unit -> 'a)

let implementingInstance =
    { new Interface<_> with
        // Must use an explicit `fun () ->` instead of a method arg list
        member __.MyFunc = fun () -> () }