How SML achieve abstraction? [closed] - sml

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am new in SML and it is my first time to learn a functional language. I suppose there is abstraction of SML. I have not found perfect explanation of how to achieve abstraction in SML. Does anyone can offer a explanation?

Generally speaking, there are at least two forms of "abstraction" in programming:
Abstracting the client (parameterisation)
Abstracting the implementation (encapsulation)
(If you care, these correspond to universal and existential quantification in logic and type theory.)
In ML, parameterisation can be done on two levels. Either in the small, using functions (abstraction over values) and polymorphism (abstraction over types). Note in particular that functions are first-class, so you can parameterise one function over another. For example:
fun map f [] = []
| map f (x::xs) = f x :: map f xs
abstracts list transformation over the transforming function f as well as the element types.
In the large, parameterisation can be done using the module system: a functor abstracts a whole module over another module (i.e., over both values and types). For example, you could also write the map function as a functor:
functor Mapper(type t; type u; val f : t -> u) =
struct
fun map [] = []
| map (x::xs) = f x :: map xs
end
But usually you use functors for mass abstraction, i.e., in cases where there is more than just a single function you need to parameterise.
Encapsulation is also achieved by using modules. Specifically, by sealing them, i.e., hiding details of their types behind a signature. For example, here is a (naive) implementation of integer sets:
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
Outside the structure IntSet, its type set is fully abstract, i.e., it cannot be interchanged with lists. That is the purpose of the so-called sealing operator :> for modules.
Both forms of abstraction can occur together. For example, in ML one would usually implement a set as a functor:
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
This implementation of sets works for any type for which an ordering function can be provided. Unlike the naive implementation before, it also uses a more efficient search tree as its implementation. However, that is not observable outside, because the type's implementation is again hidden.

SML programs frequently are build on a descriptive types for the problem at hand. The language then uses pattern matching to figure out what case your are working with.
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
Does this help to explain a little about sml?

In SML you can define "abstractions" by means of using a combination of things like algebraic data types and signatures.
Algebraic data types let you define new types specific to the problem domain and signatures let you provide functionality/behavior around those types and provide a convenient way to implement information hiding and extensibility and reusability.
Combining this things you can create "abstractions" whose implementation details are hidden from you and that you simply understand through their public interfaces (whatever the signature expose).

Related

How can I place functions in a set in Ocaml?

I'd like make a Set module containing functions. But there seems to be no way to compare functions, which Set needs. This obvious-looking thing compiles:
module Action = struct
type t = unit -> unit
let compare : t -> t -> int = Stdlib.compare
end
module Actions = Set.Make(Action)
But if I attempt to use it:
Fatal error: exception Invalid_argument("compare: functional value")
I just want compare that the functions are the same object, I am not trying to do something silly like compare them for equal behaviour.
Am I supposed to use something from the Obj module here?
The semantics of Stdlib.compare is to look arbitrarily deep inside the objects to see how their subparts compare. This doesn't really work for functions, as you point out. So OCaml doesn't allow compare to be applied to functions.
There isn't really a useful order that can be applied to functions, even if you're willing to use physical equality. Function values are immutable and can be duplicated or moved physically by the runtime system, at least in theory.
Since the ordering would necessarily be arbitrary, you can get the same effect by making your own arbitrary order: pair the functions with an int value that increases monotonically as you create new pairs.
Add an identity to your actions, e.g., you can compare actions by name,
module Action = struct
type t = {
name : string;
func : (unit -> unit);
}
let compare x y = String.compare x.name y.name
end
You should also ensure that all actions have different names, for example by introducing a global hash table that records all created actions. Make sure that actions are only creatable via the Action module, by adding an appropriate signature.
OCaml Stdlib compare documentation states ...
val compare : 'a -> 'a -> int
compare x y returns 0 if x is equal to y, a negative integer if x is less than y, and a positive integer if x is greater than y. The ordering implemented by compare is compatible with the comparison predicates =, < and > defined above, with one difference on the treatment of the float value nan. Namely, the comparison predicates treat nan as different from any other float value, including itself; while compare treats nan as equal to itself and less than any other float value. This treatment of nan ensures that compare defines a total ordering relation.
compare applied to functional values may raise Invalid_argument. compare applied to cyclic structures may not terminate.
The compare function can be used as the comparison function required by the Set.Make and Map.Make functors, as well as the List.sort and Array.sort functions.
Now we have two notion(s) of equality in OCaml, namely...
Structural Equality: Expressed using operator =, the type of which is
# (=);;
- : 'a -> 'a -> bool = <fun>
Physical Equality: Expressed using operator ==, the type of which is
# (==);;
- : 'a -> 'a -> bool = <fun>
As we can see, the type of both is same, but the function application of both of them is different when it comes to function value as arguments.
Structural Equality doesn't hold over function values, but Physical Equality may. Trying to compare(as in =) with function values throws. And as stated in the documentation of Stdlib.compare, it uses structural equality.
Illustration: Structural Equality with Function Values
# let f x = x;;
val f : 'a -> 'a = <fun>
# let g x = x;;
val g : 'a -> 'a = <fun>
# f = g;;
Exception: Invalid_argument "compare: functional value".
# g = f;;
Exception: Invalid_argument "compare: functional value".
Illustration: Physical Equality with Function Values
# let f x = x;;
val f : 'a -> 'a = <fun>
# let g x = x;;
val g : 'a -> 'a = <fun>
# f == g;;
- : bool = false
# f == f;;
- : bool = true
# g == g;;
- : bool = true
# g == f;;
- : bool = false
# let h x y = x + y;;
val h : int -> int -> int = <fun>
# h == f;;
Error: This expression has type int -> int
but an expression was expected of type int -> int -> int
Type int is not compatible with type int -> int
So in short, I don't think we can use Stdlib.compare with Set.Make with function values.
So ...
Either, we will have to keep the type t in Action module to something over which structural equality can be applied if we have to continue using Stdlib.compare.
Or, implement compare of your own so that it can do something with those function values as arguments, along with satisfying the function contract of val compare : t -> t -> int as mandated by Set.OrderedType module type.
WYSIWYG => WHAT YOU SHOW IS WHAT YOU GET

Declaring type of function in SML

I'm new to ML, but in other languages that use type inference, I have learned the habit of omitting the type of a thing whenever the inference on the right hand side is obvious to a human reader, and explicitly declaring the type of a thing whenever the inference is not obvious to a human. I like this convention, and would like to continue with it in my ML code.
I have the following example function declarations, that are equivalent:
fun hasFour [] = false
| hasFour (x::xs) = (x = 4) orelse hasFour xs
is equivalent to
val rec hasFour: int list -> bool =
fn [] => false
| (x::xs) => (x = 4) orelse hasFour xs
I like the latter form not only because it's easier for me to figure out what type the function is when I read it, but also because it explicitly declares the type of the function, and hence, if I screw something up in my implementation, there is no chance of accidentally declaring something that's syntactically valid but the wrong type, which is harder to debug later.
My question is: I want to use fun instead of val rec, because anonymous fn's can only take one parameter. So the latter technique is not syntactically valid for a function like int -> int -> bool. Is there a way to explicitly declare the type in fun? Or have I named all the preferred alternatives in this post, and should simply follow one of these patterns? The only way I could find to use fun with explicit type declaration was to add a type declaration to each parameter in the pattern, which is quite ugly and horrible, like so:
fun hasFour ([]:int list):bool = false
| hasFour (x::xs) = (x = 4) orelse hasFour xs
A colleague showed me some code following a pattern like this:
fun hasFour [] = false
| hasFour (x::xs) = (x = 4) orelse hasFour xs
val _ = op hasFour: int list -> bool
By declaring an unnamed variable and setting it to an instance of the function with a forced type, we effectively achieve the desired result, but the val _ must appear below the fully defined function, where it's less obvious to a human reader, unless you simply get used to this pattern and learn to expect it.
I asked a very similar question, Can I annotate the complete type of a fun declaration?, recently.
Your current solution would have been a nice answer to that.
You can have multiple curried arguments with multiple fn, e.g. like:
val rec member : ''a -> ''a list -> bool =
fn x => fn [] => false
| y::ys => x = y orelse member x ys
Or you can do as you currently do, or as matt suggests:
local
fun member _ [] = false
| member x (y::ys) = x = y orelse member x ys
in
val member = member : ''a -> ''a list -> bool
end
But the combination of using fun and having the complete type signature listed first is yet elusive.
For production-like code, the norm is to collect type signatures in a module signature. See ML for the Working Programmer, ch. 7: Signatures and abstraction, pp. 267-268. Although I imagine you'd want to use Ocaml then.

Monads and SML modules

signature MAPPABLE = sig
type 'a mappable
val fmap : ('a -> 'b) -> 'a mappable -> 'b mappable
end
structure Option : MAPPABLE = struct
type 'a mappable = 'a option
fun fmap f v =
case v of
(SOME x) => SOME (f x)
| NONE => NONE;
end
structure List : MAPPABLE = struct
type 'a mappable = 'a list
fun fmap f v = map f v
end
fun incByFive x = x + 5
Really just to have a function that does stuff with fmap
fun mapToPair f x =
let val b = List.fmap f x
in (b,b)
end
val lst = mapToPair incByFive [1,2,3];
Suppose you want to make a generic implementation, that works for
all instances of MAPPABLE. The following does not work
fun mapToPair f x =
let val b = MAPPABLE.fmap f x
in (b,b)
end
It seems, that SML people point to Functors, if that needs to be done.
I tried implementing one, for a generic implementation of mapToPair
functor FMAPFUNCTOR (structure Q : MAPPABLE)
= struct
fun mapToPair f x =
let val b = Q.fmap f x
in (b,b)
end
end;
However, to use it with what in Haskell I'd call a functor
instance, I need to instantiate the functor (this reminds me of C++
templates for some reason)
structure MAPPABLE_TO_PAIR = FMAPFUNCTOR (structure Q = List);
val lstByPoly = MAPPABLE_TO_PAIR.mapToPair incByFive [1,2,3]
I would have to repeat that instantiation for every MAPPABLE
instance I want to use. I guess Haskell performs something like this,
too. Just implicitly.
Now I wonder if there is any shortcut / sugar for a better "user
experience" in SML that I have missed. Because really, it seems kind
of a lot of boilerplate in the way in order to use this in a code
base.
I guess Haskell performs something like this, too. Just implicitly.
The Haskell standard library defines and imports a ton of type class instances. Given a sufficient set of ML functors, their applications and their implicit compile-time imports, you could achieve something quite convenient.
But Haskell does let you automate type class instance declarations in ways that SML doesn't.
For example, instance Foo t => Bar t where ... is comparable to SML's higher-order functors, but in SML you explicitly have to generate a module that corresponds to Bar t for each concrete Foo t. Haskell also lets you derive instances syntactically.
OCaml had modular implicits from 2014 (example), but they mainly give you syntax sugar to refer to defined functor instances, rather than generate them.
I suspect that the reason ML module systems are still more explicit than Haskell's is because of things like overlapping instances.
Andreas Rossberg contributed 1ML in 2014 in which modules are first-class citizens. That means a function could take a module as an argument, e.g. like this:
;; Higher-kinded polymorphism
type MONAD (m : type => type) =
{
return 'a : a -> m a;
bind 'a 'b : m a -> (a -> m b) -> m b;
};
map 'a 'b (m : type => type) (M : MONAD m) (f : a -> b) mx =
M.bind mx (fun x => M.return (f x));
do map :
'a => 'b => (m : type => type) => (M : MONAD m) => (a -> b) -> m a -> m b;
This is still research-y in the sense that the compiler has "TOY" in its name, but it'd be an example of an ML (although not Standard ML) that does something comparably generic with modules.

OCaml - Expression was expected of type 'b list

I'm trying to write a function that checks whether a set (denoted by a list) is a subset of another.
I already wrote a helper function that gives me the intersection:
let rec intersect_helper a b =
match a, b with
| [], _ -> []
| _, [] -> []
| ah :: at, bh :: bt ->
if ah > bh then
intersect_helper a bt
else if ah < bh then
intersect_helper at b
else
ah :: intersect_helper at bt
I'm trying to use this inside of the subset function (if A is a subset of B, then A = A intersect B):
let subset a_ b_ =
let a = List.sort_uniq a_
and b = List.sort_uniq b_
in intersect_helper a b;;
Error: This expression has type 'a list -> 'a list but an expression was expected of type 'b list
What exactly is wrong here? I can use intersect_helper perfectly fine by itself, but calling it with lists here does not work. From what I know about 'a, it's just a placeholder for the first argument type. Shouldn't the lists also be of type 'a list?
I'm glad you could solve your own problem, but your code seems exceedingly intricate to me.
If I understood correctly, you want a function that tells whether a list is a subset of another list. Put another way, you want to know whether all elements of list a are present in list b.
Thus, the signature of your function should be
val subset : 'a list -> 'a list -> bool
The standard library comes with a variety of functions to manipulate lists.
let subset l1 l2 =
List.for_all (fun x -> List.mem x l2) l1
List.for_all checks that all elements in a list satisfy a given condition. List.mem checks whether a value is present in a list.
And there you have it. Let's check the results:
# subset [1;2;3] [4;2;3;5;1];;
- : bool = true
# subset [1;2;6] [4;2;3;5;1];;
- : bool = false
# subset [1;1;1] [1;1];; (* Doesn't work with duplicates, though. *)
- : bool = true
Remark: A tiny perk of using List.for_all is that it is a short-circuit operator. That means that it will stop whenever an item doesn't match, which results in better performance overall.
Also, since you specifically asked about sets, the standard library has a module for them. However, sets are a bit more complicated to use because they need you to create new modules using a functor.
module Int = struct
type t = int
let compare = Pervasives.compare
end
module IntSet = Set.Make(Int)
The extra overhead is worth it though, because now IntSet can use the whole Set interface, which includes the IntSet.subset function.
# IntSet.subset (IntSet.of_list [1;2;3]) (IntSet.subset [4;2;3;5;1]);;
- : bool = true
Instead of:
let a = List.sort_uniq a_
Should instead call:
let a = List.sort_uniq compare a_

OCaml Signature with multiple types

I would like to represent some scalar value (e.g. integers or strings)
by either it's real value or by some NA value and later store them
in a collection (e.g. a list). The purpose is to handle missing values.
To do this, I have implemented a signature
module type Scalar = sig
type t
type v = Value of t | NA
end
Now I have some polymorphic Vector type in mind that contains Scalars. Basically, some of the following
module Make_vector(S: Scalar) = struct
type t = S.v list
... rest of the functor ...
end
However, I cannot get this to work. I would like to do something like
module Int_vector = Make_vector(
struct
type t = int
end
)
module Str_vector = Make_vector(
struct
type t = string
end
)
... and so on for some types.
I have not yet worked a lot with OCaml so maybe this is not the right way. Any advises on how to realize such a polymorphic Scalar with a sum type?
The compiler always responds with the following message:
The parameter cannot be eliminated in the result type.
Please bind the argument to a module identifier.
Before, I have tried to implement Scalar as a sum type but ran into
complexity issues when realizing some features due to huge match clauses. Another (imo not so nice) option would be to use option. Is this a better strategy?
As far as I can see, you are structuring v as an input type to your functor, but you really want it to be an output type. Then when you apply the functor, you supply only the type t but not v. My suggestion is to move the definition of v into your implementation of Make_vector.
What are you trying to do exactly with modules / functors? Why simple 'a option list is not good enough? You can have functions operating on it, e.g.
let rec count_missing ?acc:(acc=0) = function
| None::tail -> count_missing ~acc:(acc+1) tail
| _::tail -> count_missing ~acc tail
| [] -> acc ;;
val count_missing : ?acc:int -> 'a option list -> int = <fun>
count_missing [None; Some 1; None; Some 2] ;;
- : int = 2
count_missing [Some "foo"; None; Some "bar"] ;;
- : int = 1