Streaming 方法类型不兼容
我最近试着玩一个类似肥皂的东西。。。有些代码使用OCaml类和C库进行编码,比如lame(通过OCaml lame)等 (=相同接口) 某个地方有两个高级类,它们继承自两个独立的Streaming 方法类型不兼容,streaming,ocaml,Streaming,Ocaml,我最近试着玩一个类似肥皂的东西。。。有些代码使用OCaml类和C库进行编码,比如lame(通过OCaml lame)等 (=相同接口) 某个地方有两个高级类,它们继承自两个独立的encoderbase虚拟类: (* Mp3_output module *) class virtual encoderbase = object (self) method encode ncoder channels buf offset size = if channels = 1
encoderbase
虚拟类:
(* Mp3_output module *)
class virtual encoderbase =
object (self)
method encode ncoder channels buf offset size =
if channels = 1 then
Lame.encode_buffer_float_part ncoder buf.(0) buf.(0) offset size
else
Lame.encode_buffer_float_part ncoder buf.(0) buf.(1) offset size
end
(* somewhere in the code *)
class to_shout sprop =
(* some let-s *)
object (self)
inherit
[Lame.encoder] Icecast2.output ~format:Format_mp3 (* more params *) as super
inherit base
(* ... *)
end
及
在以下情况下一切正常:
let icecast_out source format =
let sprop =
new Mp3_output.shout_sprop
in
(* some code here *)
new Mp3_output.to_shout sprop
但当我尝试这样的事情时:
let icecast_out source format =
let sprop =
if format = Format_other then
new Other_output.shout_sprop
else
new Mp3_output.shout_sprop
in
(* some code here *)
if format = Format_mp3 then
new Mp3_output.to_shout sprop
else
new Other_output.to_shout sprop
编译中断,出现错误@新的其他输出。要显示sprop
:
Error: This expression has type Other_output.to_shout
but an expression was expected of type Mp3_output.to_shout
Types for method encode are incompatible
有没有办法“说服”OCaml(公共祖先?包装类?类型转换?)同时使用这两个不同的类/绑定进行编译
更新(2015年12月15日):
代码示例:
有没有办法“说服”OCaml(公共祖先?包装类?类型转换?)同时使用这两个不同的类/绑定进行编译
人们相信OCaml是一种类型安全的语言,因此不可能说服OCaml编译一个会崩溃的程序,除非您使用了一些不安全的方法
您的示例中的以下代码片段说明了误解的根源:
type 'a term = Save of 'a
let enc_t =
if format_num = 1
then Save Lame.encoder
else Save Other.encoder
表达式Save Lame.encoder
具有类型Lame.encoder term
,而表达式Save Other.encoder
具有类型Other.encoder term
。从类型系统的角度来看,这是两种完全不同的类型,尽管它们是由相同的类型构造函数term
构建的。C.f.,int list
和float list
是不同的类型,您不能为这两种不同类型的变量值赋值。这不是OCAM本身的一个属性,这是任何参数多态性的一个属性,例如,<>代码> STD::vector < /COD>和let rec length = function
| [] -> 0
| _ :: xs -> 1 + length xs
是多态的,因为它可以应用于多态数据类型的任何实例'a list
,包括int list
,float list
,person list
,等等
另一方面,函数
let rec sum = function
| [] -> 0
| x :: xs -> x + sum xs
不是多态的,只能应用于int list
类型的值。原因是这个函数的实现依赖于一个事实,即每个元素都是一个整数。如果您能够说服类型系统,将此函数应用于float
列表,您将得到一个分段错误
但你可能会说,我们遗漏了一些东西,因为float
list的求和函数看起来基本相同:
let rec fsum = function
| [] -> 0.
| x :: xs -> x +. fsum xs
因此,有机会抽象出一个总结。当我们抽象某些东西时,我们会发现不同实现之间的差异,并将其抽象出来。OCaml中最简单的抽象原语是一个函数,所以让我们这样做:
let rec gsum zero plus xs =
let (+) = plus in
let rec sum = function
| [] -> zero
| x :: xs -> x + sum xs in
sum xs
我们抽象出zero
元素和plus
函数。所以我们得到了一个求和的抽象,它适用于任何类型,你可以为它提供一个加操作和元素中立的操作(在抽象代数中称为环数据结构)。gsum的类型为
'a -> ('b -> 'a -> 'a) -> 'b list -> 'a
它甚至太通用了,我们可以将它专门化一点,就像这种类型一样
'a -> ('a -> 'a -> 'a) -> 'a list -> 'a
更合适。我们可以将其聚合为记录类型,而不是逐个传递环结构的元素:
type 'a ring = {
zero : 'a;
plus : 'a -> 'a -> 'a
}
并按如下方式实施我们的通用sum
:
let rec gsum ring xs =
let (+) = ring.plus in
let rec sum = function
| [] -> ring.zero
| x :: xs -> x + sum xs in
sum xs
在这种情况下,我们将有一个很好的类型sum:'a ring->'a list->'a
。在某个时候,您会发现自己用新字段扩展了这个记录,并实现了越来越多的函数,这些函数接受这个环结构作为第一个参数。这将是一个很好的时间来使用一个更重的抽象,叫做functor
。functor
实际上是一个类固醇记录,隐式地传递给functor实现的每个函数。除了函数,函数和函子的记录还有其他抽象技术:第一类模块、对象、类,很快还有隐式(也称为类型类)。学习如何选择更适合于每个特定情况的抽象技术是编程专业知识的一部分。一般的建议是尽可能使用最轻的。事实上,95%的用户使用函数或函数记录就足够了
现在让我们回到你的例子。你在同一个洞里击球,
你把多病态和抽象混淆了:
let fmt =
if format_num = 1
then new Lamefmt.sout sp
else new Otherfmt.sout sp in
Lamefmt.sout
和Otherfmt.sout
是不同的类型,第一种类型有:
type sout = <
doenc : Lame.encoder -> float array array -> int -> int -> string;
encode : Lame.encoder -> float array array -> int -> int -> string
>
在哪里
然后我们可以构造不同的编码器:
let lame : encoder =
let encoder = Lame.create_encoder () in
Lame.encode_buffer_float_part encoder
let other : encoder =
let encoder = Other.create_encoder () in
Other.encode_buffer_float_part encoder
module Lame = struct
type encoder
let encode_buffer_float_part : encoder -> float -> unit = fun _ -> failwith "ocaml_lame_encode_buffer_float"
end
module Otherencoder = struct
type encoder
let encode_buffer_float_part : encoder -> float -> unit = fun _ -> failwith "ocaml_otherencoder_encode_buffer_float"
end
module Mp3_output = struct
class to_shout = object
method encode ncoder x =
Lame.encode_buffer_float_part ncoder x
end
end
module Other_output = struct
class to_shout = object
method encode ncoder x =
Otherencoder.encode_buffer_float_part ncoder x
end
end
type format = Format_other | Format_mp3
let icecast_out source format =
if format = Format_mp3 then new Mp3_output.to_shout
else new Other_output.to_shout
然后你可以交替使用这两个值。有时,不同的编码器需要不同的参数,在这种情况下,我们的任务是尽快发送它们,例如
let very_customizable_encoder x y z : encoder =
let encoder = VCE.create_encoder x y z in
Other.encode_buffer_float_part encoder
在这种情况下,您应该尽可能靠近用户解决定制问题,然后再使用抽象
通常使用哈希表或其他关联数据结构来存储编码器。这种方法甚至允许您表示一个插件体系结构,其中插件是动态加载的,并在某些表中注册它们自己(类型编码器的值)
结语。用一个函数来表示您的问题就足够了。也许在某个时候,您需要使用函数的记录。到目前为止,我认为没有必要使用类。通常,当您对开放递归感兴趣时,也就是说,当您的问题由一组相互递归f表示时,它们是必需的
type encoder = buffer -> buffer -> int -> int -> string
type buffer = float array array
let lame : encoder =
let encoder = Lame.create_encoder () in
Lame.encode_buffer_float_part encoder
let other : encoder =
let encoder = Other.create_encoder () in
Other.encode_buffer_float_part encoder
let very_customizable_encoder x y z : encoder =
let encoder = VCE.create_encoder x y z in
Other.encode_buffer_float_part encoder
module Lame = struct
type encoder
let encode_buffer_float_part : encoder -> float -> unit = fun _ -> failwith "ocaml_lame_encode_buffer_float"
end
module Otherencoder = struct
type encoder
let encode_buffer_float_part : encoder -> float -> unit = fun _ -> failwith "ocaml_otherencoder_encode_buffer_float"
end
module Mp3_output = struct
class to_shout = object
method encode ncoder x =
Lame.encode_buffer_float_part ncoder x
end
end
module Other_output = struct
class to_shout = object
method encode ncoder x =
Otherencoder.encode_buffer_float_part ncoder x
end
end
type format = Format_other | Format_mp3
let icecast_out source format =
if format = Format_mp3 then new Mp3_output.to_shout
else new Other_output.to_shout
Error: This expression has type Other_output.to_shout
but an expression was expected of type Mp3_output.to_shout
Types for method encode are incompatible
module Mp3_output = struct
class to_shout ncoder = object
method encode x =
Lame.encode_buffer_float_part ncoder x
end
end
module Other_output = struct
class to_shout ncoder = object
method encode x =
Otherencoder.encode_buffer_float_part ncoder x
end
end
type format = Format_other | Format_mp3
let icecast_out source format =
if format = Format_mp3 then new Mp3_output.to_shout Lame.ncoder
else new Other_output.to_shout Otherencoder.ncoder