OCaml 可加数字

OCaml Addable Numbers

提问人:Rhohen 提问时间:10/31/2023 最后编辑:Rhohen 更新时间:11/1/2023 访问量:71

问:

我正在学习 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) 的需要,以抽象这种行为

函数式编程 OCAML 单子

评论

2赞 Daniel Wagner 10/31/2023
如果您不向我们展示您的尝试,我们将无法帮助您修复您的尝试。
0赞 Rhohen 10/31/2023
对不起,我现在已经上传了我的代码

答:

1赞 Chris 10/31/2023 #1

不可以,OCaml 没有类型类。

但是,考虑到 FloatInt 模块都实现了几个常见的函数,如 、 、 等。addsubmuldiv

它们也都具有类型,并以 的方式实现这些函数。这允许函子抽象出这些行为并以大致相同的方式工作。tt

# 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
但我不明白如何定义这些列表,并在函数中使用它们。我试过了,但没有成功