假设我有一个Stack定义的开头,如下所示:
signature STACK = sig
type 'a stack
end;
structure Stack :> STACK = struct
type 'a stack = 'a list
end;
显然这不起作用,因为我无法将列表转换为堆栈:
- [5] : int Stack.stack;
stdIn:1.2-1.23 Error: expression doesn't match constraint [tycon mismatch]
expression: int list
constraint: int Stack.stack
in expression:
5 :: nil: int Stack.stack
这意味着如果我创建了一个Stack.push或Stack.pop函数,我无法传入int列表,因为它会期望一个堆栈。
希望我更了解标准ML来制定一个真正的问题,我只知道这不起作用,我不知道如何处理签名和结构。
答案 0 :(得分:4)
当你宣布你的结构时,你是使用不透明签名匹配(:>
)这样做的。
不透明签名匹配意味着什么,隐藏在结构内部声明的任何类型背后的基础类型。
如果您不希望出现这种情况,可以使用透明签名匹配(:
)。
透明签名匹配的示例:
structure Stack : STACK = struct
type 'a stack = 'a list
end;
在执行此操作之前,请考虑不这样做的优点:如果使用不透明签名匹配,则隐藏底层实现。如果您希望更改底层实现(例如,更改为树结构),您可以知道结构外部的任何内容都不能使用您提供的任何其他功能。
您可能希望提供toList
和fromList
功能来执行转换:
(* in the signature *)
val toList : 'a stack -> 'a list
val fromList : 'a list -> 'a stack
(* in your structure *)
fun toList s = s
fun fromList s = s
如果您随后更改了底层实现,则只需更改这两个函数,而不必在整个程序中进行更改。
答案 1 :(得分:3)
正如塞巴斯蒂安建议的那样创建函数toList
和fromList
非常好。或者,您可以创建一个限制性更强的界面,该界面不允许直接导入和导出,只能由push
,pop
和empty
创建:
signature STACK =
sig
type 'a stack
val push : 'a -> 'a stack -> 'a stack
val pop : 'a stack -> ('a * 'a stack)
val peek : 'a stack -> 'a
val empty : 'a stack
end
structure LStack :> STACK =
struct
type 'a stack = 'a list
fun push = ...
fun pop = ...
fun peek = ...
val empty = []
end