提问人:Rhohen 提问时间:10/31/2023 最后编辑:Rhohen 更新时间:11/1/2023 访问量:71
OCaml 可加数字
OCaml Addable Numbers
问:
我正在学习 OCaml,从我为论文学习的一点 Haskell 中,我想知道是否有类似的机制(类型类)来表示两个数字是可加的(比如 int、float、string 等的泛型)。我知道在 OCaml 类型类中不存在,但我想知道类似的机制来表达同样的东西
我正在尝试制作一个具有通用“方法”添加的模块类型,但没有成功。
module type Addable = sig
type t
val add : t -> t -> t
val zero : t
val one : t
end
module Addable_int : Addable with type t = int = struct
type t = int
let add a b = a + b
let zero = 0
let one = 1
end
module Addable_float : Addable with type t = float = struct
type t = float
let add a b = a +. b
let zero = 0.
let one = 1.
end
let rec sum (type a) (module A : Addable with type t = a) =
match l with
| [] -> A.zero
| x::l -> A.add x (sum (module A) l)
更新:函数 sum 给出错误:“此表达式具有类型 'a,但表达式应为 a 类型构造函数 a 将脱离其作用域”
更新-更新:
module type NumberType = sig
type t
val add : t -> t -> t
val zero : t
val one : t
end
module IntNumber : NumberType with type t = int = struct
type t = int
let add x y = x + y
let zero = 0
let one = 1
end
module FloatNumber : NumberType with type t = float = struct
type t = float
let add x y = x +. y
let zero = 0.0
let one = 1.0
end
module Addbl (M: NumberType) = struct
type t = M.t
let add x y = M.add x y
let zero = M.zero
let one = M.one
end
let rec sum : type a. (module NumberType with type t = a) -> a list -> a =
fun (module M) l ->
match l with
| [] -> M.zero
| x::t -> M.add x (sum (module M) t)
let () =
let xs = [1.;2.;3.] in
let _ = print_float @@ sum (module FloatNumber) xs in
let _ = print_string "\n" in
let xsi = [1;2;3;4] in
print_int @@ sum (module IntNumber) xsi
此代码有效,并且 sum 函数是通用的。我不知道是否有办法消除在 sum 函数中传递 (模块 IntNumber) 或 (模块 FloatNumber) 的需要,以抽象这种行为
答:
1赞
Chris
10/31/2023
#1
不可以,OCaml 没有类型类。
但是,考虑到 Float
和 Int
模块都实现了几个常见的函数,如 、 、 等。add
sub
mul
div
它们也都具有类型,并以 的方式实现这些函数。这允许函子抽象出这些行为并以大致相同的方式工作。t
t
# module type NumberType = sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end
module Math (N : NumberType) = struct
type t = N.t
let ( + ) = N.add
let ( - ) = N.sub
let ( * ) = N.mul
let ( / ) = N.div
end;;
module type NumberType =
sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end
module Math :
functor (N : NumberType) ->
sig
type t = N.t
val ( + ) : t -> t -> t
val ( - ) : t -> t -> t
val ( * ) : t -> t -> t
val ( / ) : t -> t -> t
end
# let open Math (Int) in
45 + 67;;
- : int = 112
# let open Math (Float) in
45.6 + 87.2;;
- : float = 132.8
使用函子的类型示例:Addable
# module type Addable = sig
type t
val nil : t
val add : t -> t -> t
end;;
module type Addable =
sig type t val nil : t val add : t -> t -> t end
# module SumList (A : Addable) = struct
type t = A.t
let sum_list = List.fold_left A.add A.nil
end;;
module SumList :
functor (A : Addable) ->
sig type t = A.t val sum_list : t list -> t end
# let open SumList (struct include Int let nil = 0 end) in
sum_list [1; 2; 3; 4];;
- : int = 10
# let open SumList (struct
include String
let nil = ""
let add = (^)
end) in
sum_list ["foo"; "bar"; "baz"];;
- : string = "foobarbaz"
您还可以对第一类模块使用相同的模块签名,以避免对函子的需求,从而允许一个函数对不同类型的列表求和。Addable
# let sum_list
(type a)
(module A : Addable with type t = a)
(lst : a list) =
List.fold_left A.add A.nil lst;;
val sum_list : (module Addable with type t = 'a) -> 'a list -> 'a = <fun>
# module IntAdd = struct
type t = int
let nil = 0
let add = (+)
end;;
module IntAdd : sig type t = int val nil : t val add : t -> t -> t end
# module StringAdd = struct
type t = string
let nil = ""
let add = (^)
end;;
module StringAdd : sig type t = string val nil : t val add : t -> t -> t end
# module FloatAdd = struct
type t = float
let nil = 0.
let add = (+.)
end;;
module FloatAdd : sig type t = float val nil : t val add : t -> t -> t end
# sum_list (module IntAdd) [1; 2; 3; 4; 5];;
- : int = 15
# sum_list (module StringAdd) ["1"; "2"; "3"; "4"; "5"];;
- : string = "12345"
# sum_list (module FloatAdd) [1.; 2.; 3.; 4.; 5.];;
- : float = 15.
评论
0赞
Rhohen
10/31/2023
我已经尝试了此代码,但给了我错误。也许我不清楚我的意图。现在我已经上传了代码。目标是表示“实现”Addable 的任何类型都可以在采用 Addable 参数的泛型函数中使用。或者在我的示例中,可以使用的可添加项列表
0赞
Chris
10/31/2023
我已经修改以显示给定名称的模块签名。任何实现该签名的模块(可能更多)都可以传递给该函子或其他一些函子,从而获得一个完整的函数模块,这些函数适用于该模块描述的类型。NumberType
0赞
Rhohen
10/31/2023
但我不明白如何定义这些列表,并在函数中使用它们。我试过了,但没有成功
评论