我是SML的新手,这是我第一次学习函数式语言。我想有SML的抽象。我还没有找到如何在SML中实现抽象的完美解释。有人可以提供解释吗?
答案 0 :(得分:5)
一般来说,至少有两种形式的"抽象"在编程中:
(如果你关心,这些对应于逻辑和类型理论中的普遍和存在量化。)
在ML中,参数化可以在两个级别上完成。在小型中,使用函数(对值进行抽象)和多态(对类型进行抽象)。请特别注意,函数是一流的,因此您可以将一个函数参数化为另一个函数。例如:
fun map f [] = []
| map f (x::xs) = f x :: map f xs
通过转换函数f
以及元素类型抽象列表转换。
在大型参数化中,可以使用模块系统完成参数化:仿函数将整个模块抽象到另一个模块上(即,在值和类型上)。例如,您也可以将地图函数编写为仿函数:
functor Mapper(type t; type u; val f : t -> u) =
struct
fun map [] = []
| map (x::xs) = f x :: map xs
end
但通常你会使用仿函数来进行大规模抽象,也就是说,如果你需要参数化的函数不止一个。
使用模块也可以实现封装。具体来说,通过密封它们,即隐藏签名后面的类型细节。例如,这是整数集的(天真)实现:
signature INT_SET =
sig
type set
val empty : set
val add : int * set -> set
val mem : int * set -> bool
end
structure IntSet :> INT_SET = (* ':>' hides the implementation of type set *)
struct
type set = int list
val empty = []
fun add(x, s) = x::s
fun mem(x, s) = List.exists (fn y => y = x) s
end
在结构IntSet
之外,其类型set
完全是抽象,即它不能与列表互换。这就是模块的所谓密封运算符:>
的目的。
两种形式的抽象可以一起发生。例如,在ML中,通常会将一个集实现为仿函数:
signature ORD =
sig
type t
val compare : t * t -> order
end
signature SET =
sig
type elem
type set
val empty : set
val add : elem * set -> set
val mem : elem * set -> bool
end
functor Set(Elem : ORD) :> SET where type elem = Elem.t =
struct
type elem = Elem.t
datatype set = Empty | Branch of set * elem * set
val empty = Empty
fun add(x, Empty) = Branch(Empty, x, Empty)
| add(x, Branch(l, y, r)) =
case Elem.compare(x, y) of
LESS => Branch(add(x, l), y, r)
| EQUAL => Branch(l, y, r)
| GREATER => Branch(l, y, add(x, r))
fun mem(x, Empty) = false
| mem(x, Branch(l, y, r)) =
case Elem.compare(x, y) of
LESS => mem(x, l)
| EQUAL => true
| GREATER => mem(x, r)
end
这个集合的实现适用于可以提供排序功能的任何类型。与之前的朴素实现不同,它还使用更高效的搜索树作为其实现。但是,这在外部是不可观察的,因为类型的实现再次被隐藏。
答案 1 :(得分:1)
SML程序经常建立在手头问题的描述性类型上。然后,该语言使用模式匹配来确定您正在使用的案例。
datatype Shape = Circle of real | Rectangle of real*real | Square of real
val a = Circle(0.2)
val b = Square(1.3)
val c = Rectangle(4.0,2.0)
fun area (Circle(r)) = 3.14 * r * r
| area (Square(s)) = s * s
| area (Rectangle(b,h)) = b * h
这有助于解释一下sml吗?
答案 2 :(得分:0)
在SML中,您可以通过使用代数数据类型和签名等组合来定义“抽象”。
代数数据类型允许您定义特定于问题域的新类型,签名允许您提供围绕这些类型的功能/行为,并提供实现信息隐藏和可扩展性以及可重用性的便捷方式。
结合这些东西,您可以创建“抽象”,其实现细节对您隐藏,您只需通过其公共接口(无论签名暴露)了解。