在 F#/.NET 中实现标准 ML 签名
Implementing Standard ML signatures in F# / .NET
(问题在底部以粗体显示。)
我正在研究 Chris Okasaki's Purely Functional Data Structures,我试图将第一个数据结构及其实现从标准 ML 转换为 F#。 ML如下(从书中翻译而来):
signature STACK =
sig
type 'a Stack
val empty : 'a Stack
val isEmpty : 'a Stack -> bool
val cons : 'a * 'a Stack -> 'a Stack
val head : 'a Stack -> 'a (* raises EMPTY if stack is empty *)
val tail : 'a Stack -> 'a Stack (* raises EMPTY if stack is empty *)
end
及其第一个实现:
structure List:STACK =
struct
type 'a Stack = 'a list
val empty = []
fun isEmpty s = null s
fun cons (x,s) = x :: s
fun head s = hd s
fun tail s = tl s
end
并且,为了清楚起见,它的第二个实现:
structure CustomStack:STACK =
struct
datatype 'a Stack = NIL | CONS of 'a * 'a Stack
val empty = NIL
fun isEmpty NIL = true | isEmpty _ = false
fun cons (x, s) = CONS(x, s)
fun head NIL = raise EMPTY
| head (CONS(x, s)) = x
fun tail NIL = raise EMPTY
| tail (CONS(x, s)) = s
end
我能够将 ML signature
移植到 F# 几乎一个学期一个学期:
type 'a Stack = Stack of 'a
type 'a STACK =
val Stack : 'a Stack
val empty : 'a Stack
val isEmpty : 'a Stack -> bool
val cons : 'a * 'a Stack -> 'a Stack
val head : 'a Stack -> 'a
val tail : 'a Stack -> 'a Stack
尽管显然无法将 F# 类型实现为任何实质性内容,但此代码仍可编译,因为没有构造函数并且未 将其识别为接口(并且不能写成一个,因为 val Stack
和 val empty
不是函数)。它在 fsi
中编译为 class,但显然没有构造函数或任何东西来实现它。上一个片段的 fsi
签名是:
type 'a Stack = | Stack of 'a
type 'a STACK =
class
val Stack: 'a Stack
val empty: 'a Stack
val isEmpty: 'a Stack -> bool
val cons: 'a * 'a Stack -> 'a Stack
val head: 'a Stack -> 'a
val tail: 'a Stack -> 'a Stack
end
1.有什么方法可以在 .NET 生态系统中利用它,只拥有像这样的纯类型,实用与否?另外,这是否被认为是某种能够创建不可实现的数据类型的错误?
2。是否可以在不使用接口和抽象 classes 的情况下在 F# 中实现标准 ML 数据结构,或者由于 .NET 的结构方式,它们是强制性的吗?
1。有什么方法可以在 .NET 生态系统中利用它,只拥有像这样的纯类型,实用与否?另外,这是否被认为是某种能够创建不可实现的数据类型的错误?
你已经实现了编译,但它肯定不是你打算实现的。它只是在语法上相似——你使用的是 explicit class syntax,你的 STACK
类型是 class 表面上没有 public 构造函数和一堆 getter-仅属性。
这是你可以通过反思自己检查的东西API。如果您在 FSI 中使用此代码,您可能会发现无论如何都会为该类型生成一个构造函数,并且您可以使用 Activator.Create
来实例化它 - 您会看到所有属性都具有默认的空值。
open System
open System.Reflection
let typ = typeof<STACK<int>>
typ.GetProperties()
let stack = Activator.CreateInstance<STACK<int>>()
这是 FSI 使用 afaik 的产物,在编译代码中你无法构造这种类型的值。
2。无论如何在 F# 中实现标准 ML 数据结构而不使用接口和抽象 classes,或者它们是强制性的,因为 .NET 的结构方式?
就转换概念而言,抽象 classes 及其子类型是 SML 签名和结构最直接的 F# 等价物。
这与 F# 避开 OCaml 模块系统(带有签名、结构和函子)以支持 OOP 系统已经存在的 .NET 中间语言有关。相比之下,F# 模块受到严重限制,它们更像是一个类似于 Haskell 的 grouping/namespacing 工具。
不确定您的体验是什么 - 我知道来自 OOP 背景的语言新手通常急于完全放弃 classes、接口以及他们与 OOP 相关的任何东西,但这是相当误入歧途的方法。这些概念是 F# 的一部分是有原因的,如果不使用它们,您将放弃表达能力的重要部分。
检查 以获取与 F# "translation" 相似的 ML 示例。请注意,这是比 "solid library code" 级别更高的 "toy example" 级别 - 因为建议使用根深蒂固的 .NET 集合接口,以便它与更广泛的生态系统很好地融合。例如,这就是 FSharp.Core
集合所做的。
(问题在底部以粗体显示。)
我正在研究 Chris Okasaki's Purely Functional Data Structures,我试图将第一个数据结构及其实现从标准 ML 转换为 F#。 ML如下(从书中翻译而来):
signature STACK =
sig
type 'a Stack
val empty : 'a Stack
val isEmpty : 'a Stack -> bool
val cons : 'a * 'a Stack -> 'a Stack
val head : 'a Stack -> 'a (* raises EMPTY if stack is empty *)
val tail : 'a Stack -> 'a Stack (* raises EMPTY if stack is empty *)
end
及其第一个实现:
structure List:STACK =
struct
type 'a Stack = 'a list
val empty = []
fun isEmpty s = null s
fun cons (x,s) = x :: s
fun head s = hd s
fun tail s = tl s
end
并且,为了清楚起见,它的第二个实现:
structure CustomStack:STACK =
struct
datatype 'a Stack = NIL | CONS of 'a * 'a Stack
val empty = NIL
fun isEmpty NIL = true | isEmpty _ = false
fun cons (x, s) = CONS(x, s)
fun head NIL = raise EMPTY
| head (CONS(x, s)) = x
fun tail NIL = raise EMPTY
| tail (CONS(x, s)) = s
end
我能够将 ML signature
移植到 F# 几乎一个学期一个学期:
type 'a Stack = Stack of 'a
type 'a STACK =
val Stack : 'a Stack
val empty : 'a Stack
val isEmpty : 'a Stack -> bool
val cons : 'a * 'a Stack -> 'a Stack
val head : 'a Stack -> 'a
val tail : 'a Stack -> 'a Stack
尽管显然无法将 F# 类型实现为任何实质性内容,但此代码仍可编译,因为没有构造函数并且未 将其识别为接口(并且不能写成一个,因为 val Stack
和 val empty
不是函数)。它在 fsi
中编译为 class,但显然没有构造函数或任何东西来实现它。上一个片段的 fsi
签名是:
type 'a Stack = | Stack of 'a
type 'a STACK =
class
val Stack: 'a Stack
val empty: 'a Stack
val isEmpty: 'a Stack -> bool
val cons: 'a * 'a Stack -> 'a Stack
val head: 'a Stack -> 'a
val tail: 'a Stack -> 'a Stack
end
1.有什么方法可以在 .NET 生态系统中利用它,只拥有像这样的纯类型,实用与否?另外,这是否被认为是某种能够创建不可实现的数据类型的错误?
2。是否可以在不使用接口和抽象 classes 的情况下在 F# 中实现标准 ML 数据结构,或者由于 .NET 的结构方式,它们是强制性的吗?
1。有什么方法可以在 .NET 生态系统中利用它,只拥有像这样的纯类型,实用与否?另外,这是否被认为是某种能够创建不可实现的数据类型的错误?
你已经实现了编译,但它肯定不是你打算实现的。它只是在语法上相似——你使用的是 explicit class syntax,你的 STACK
类型是 class 表面上没有 public 构造函数和一堆 getter-仅属性。
这是你可以通过反思自己检查的东西API。如果您在 FSI 中使用此代码,您可能会发现无论如何都会为该类型生成一个构造函数,并且您可以使用 Activator.Create
来实例化它 - 您会看到所有属性都具有默认的空值。
open System
open System.Reflection
let typ = typeof<STACK<int>>
typ.GetProperties()
let stack = Activator.CreateInstance<STACK<int>>()
这是 FSI 使用 afaik 的产物,在编译代码中你无法构造这种类型的值。
2。无论如何在 F# 中实现标准 ML 数据结构而不使用接口和抽象 classes,或者它们是强制性的,因为 .NET 的结构方式?
就转换概念而言,抽象 classes 及其子类型是 SML 签名和结构最直接的 F# 等价物。
这与 F# 避开 OCaml 模块系统(带有签名、结构和函子)以支持 OOP 系统已经存在的 .NET 中间语言有关。相比之下,F# 模块受到严重限制,它们更像是一个类似于 Haskell 的 grouping/namespacing 工具。
不确定您的体验是什么 - 我知道来自 OOP 背景的语言新手通常急于完全放弃 classes、接口以及他们与 OOP 相关的任何东西,但这是相当误入歧途的方法。这些概念是 F# 的一部分是有原因的,如果不使用它们,您将放弃表达能力的重要部分。
检查 FSharp.Core
集合所做的。