F# 在F中使用类型和整数约束进行设计#
如何在F#中设计一个整数类型,该类型初始化为0,并且有一些方法总是单调地增加值,即第一次调用该方法返回1,第二次调用2等 下面是OCAML代码,描述了我希望在F中实现的功能#F# 在F中使用类型和整数约束进行设计#,f#,ocaml,F#,Ocaml,如何在F#中设计一个整数类型,该类型初始化为0,并且有一些方法总是单调地增加值,即第一次调用该方法返回1,第二次调用2等 下面是OCAML代码,描述了我希望在F中实现的功能# 您可以将其直接转换为类型(在ML中也可以): 当然,它可能不是性能最好的,因此您可能会选择这样的方式(也更接近您的版本): 遗憾的是,F#没有Ocaml拥有的强大模块,因此我在这里修复了int 通用版本 如果您真的想要,您可以让它更通用一些: module Term = type T<'a> =
您可以将其直接转换为类型(在ML中也可以): 当然,它可能不是性能最好的,因此您可能会选择这样的方式(也更接近您的版本): 遗憾的是,F#没有Ocaml拥有的强大模块,因此我在这里修复了
int
通用版本
如果您真的想要,您可以让它更通用一些:
module Term =
type T<'a> =
private T of 'a with
override x.ToString () =
match x with
| (T i) -> i.ToString()
let inline init () = T LanguagePrimitives.GenericZero
let inline succ (T i) = T (i + LanguagePrimitives.GenericOne)
let compare (T a) (T b) = compare a b
let getValue (T i) = i
将按预期工作:
> let one = Term.init () |> Term.succ;;
val one : Term.T<int>
> let two = Term.succ one;;
val two : Term.T<int>
> one = Term.succ (Term.init ());;
val it : bool = true
> one < two;;
val it : bool = true
> one >= two;;
val it : bool = false
> compare one two;;
val it : int = -1
>让one=Term.init()|>Term.such;;
val一:术语
>设二=项。成功一;;
val二:术语
>一=Term.such(Term.init());;
val it:bool=true
>一小于二;;
val it:bool=true
>一个>=两个;;
val-it:bool=false
>比较两者;;
val it:int=-1
如果您关心结构/值类型
按照@vandroys的回答或进行以下微调:
module Term =
type [<Struct>] T<'a> internal (a : 'a) =
member internal __.value = a
let inline init () = T (LanguagePrimitives.GenericZero)
let inline succ (i : T<_>) = T (i.value + LanguagePrimitives.GenericOne)
模块术语=
type[]T最小值类型实现:
type [<Struct>] Term private (i : int) =
member __.Value = i
member __.Next = Term (i + 1)
// optional static members
static member Zero = Term ()
static member value (t : Term) = t.Value
static member next (t : Term) = t.Next
这种方法的泛化不允许下一个
实例成员(静态成员可以),因为类型上不支持F#的成员约束。如果这是一个要求,我也会考虑一个<代码>内部< /代码>构造函数,或者使用单元素DU允许模块私有构造的方法。
如果有人来这里只是寻找一个返回递增整数的函数,Str在问题的注释中暗示的是: 不幸的是,F#并不完全支持ML样式的模块(或函子)。现有答案涵盖了使用惯用F#处理某些情况的方法,这些情况下可以使用现有模块,但受到相当的限制 一个更忠实、但不那么惯用、更麻烦的翻译可能看起来更像这样:
type TermRec<'t> = {
succ: 't -> 't
init: unit -> 't
compare: 't -> 't -> int
}
type TermUser<'z> =
abstract Use : TermRec<'t> -> 'z
type Term =
abstract Apply : TermUser<'z> -> 'z
let mkTerm r = { new Term with member this.Apply(u) = u.Use r }
let term1 = mkTerm { succ = (fun i -> i + 1); init = (fun() -> 0); compare = compare }
let term2 = mkTerm { succ = (fun i -> not i); init = (fun() -> false); compare = compare }
let user = {
new TermUser<_> with
member this.Use(t) =
t.compare (t.init() |> t.succ |> t.succ) (t.init()) }
let v1 = term1.Apply user
let v2 = term2.Apply user
类型TermRec't
初始:单位->'t
比较:'t->'t->int
}
键入TermUser->'z
类型术语=
摘要适用:术语用户i+1);init=(fun()->0);比较=比较}
让term2=mkTerm{such=(fun i->not i);init=(fun()->false);compare=compare}
让用户={
新用户
成员。使用(t)=
t、 比较(t.init()|>t.such |>t.such)(t.init())}
设v1=term1。应用用户
设v2=term2。应用用户
请特别注意:
int
s、bool
s等)TermRec
的类型参数,并且会泄漏此类型值的用户将不会编译(尽管您可以创建一个TermUser
,它使用.NET反射在运行时中断封装并返回例如类型的字符串名称)如果我理解正确,并且您希望创建一个函数,该函数每次被调用时都提供一个新值,那么通常的解决方案是使用计数器的ref并将其保持为私有。在OCaml中,代码是:
let create_counter initial_value =
let counter = ref initial_value in
fun () ->
let result = !counter in
incr counter;
result
其用途如下:
# let new_id = create_counter 0;;
val new_id : unit -> int = <fun>
# new_id ();;
- : int = 0
# new_id ();;
- : int = 1
# new_id ();;
- : int = 2
# new_id ();;
- : int = 3
#让新的_id=create_计数器0;;
val new_id:unit->int=
#新的_id();;
-:int=0
#新的_id();;
-:int=1
#新的_id();;
-:int=2
#新的_id();;
-:int=3
谢谢。我将尝试一下,看看泛型版本如何工作。如果你想放弃花哨的类型工作,一个int-ref的闭包就可以了。
module Term =
type [<Struct>] T<'a> internal (a : 'a) =
member internal __.value = a
let inline init () = T (LanguagePrimitives.GenericZero)
let inline succ (i : T<_>) = T (i.value + LanguagePrimitives.GenericOne)
type [<Struct>] Term private (i : int) =
member __.Value = i
member __.Next = Term (i + 1)
// optional static members
static member Zero = Term ()
static member value (t : Term) = t.Value
static member next (t : Term) = t.Next
Term.Zero.Next = (Term.Zero |> Term.next) // true
Term.Zero < Term.Zero.Next // true
/// Returns 1 on first call, otherwise last issued + 1
let intSource =
let i = ref 0
fun () -> incr i; i
type TermRec<'t> = {
succ: 't -> 't
init: unit -> 't
compare: 't -> 't -> int
}
type TermUser<'z> =
abstract Use : TermRec<'t> -> 'z
type Term =
abstract Apply : TermUser<'z> -> 'z
let mkTerm r = { new Term with member this.Apply(u) = u.Use r }
let term1 = mkTerm { succ = (fun i -> i + 1); init = (fun() -> 0); compare = compare }
let term2 = mkTerm { succ = (fun i -> not i); init = (fun() -> false); compare = compare }
let user = {
new TermUser<_> with
member this.Use(t) =
t.compare (t.init() |> t.succ |> t.succ) (t.init()) }
let v1 = term1.Apply user
let v2 = term2.Apply user
let create_counter initial_value =
let counter = ref initial_value in
fun () ->
let result = !counter in
incr counter;
result
# let new_id = create_counter 0;;
val new_id : unit -> int = <fun>
# new_id ();;
- : int = 0
# new_id ();;
- : int = 1
# new_id ();;
- : int = 2
# new_id ();;
- : int = 3