(* Check if a list of integers consists of alternating 1's and 0's *)
fun one _ [] = true
| one f (1::tail) = f tail
| one _ _ = false
fun zero ([]) = true
| zero (0::tail) = one zero tail
| zero _ = false
fun is_alternating (1::tail) = zero tail
| is_alternating (0::tail) = one zero tail
| is_alternating [] = true
| is_alternating _ = false
fun is_alt xs = one zero xs orelse zero xs
(* This works. Higher order function workaround take an arbitrary function in
the earlier part, *)
(* Aaand as a little segue. Let's put this in a module *)
signature FSM =
sig
val is_alternating : int list -> bool
end
structure MyFSM :> FSM =
struct
fun one _ [] = true
| one f (1::tail) = f tail
| one _ _ = false
fun zero ([]) = true
| zero (0::tail) = one zero tail
| zero _ = false
fun is_alternating (1::tail) = zero tail
| is_alternating (0::tail) = one zero tail
| is_alternating [] = true
| is_alternating _ = false
fun is_alt xs = one zero xs orelse zero xs
end
(* This signature allows only authenticated users to query their account
balance, protecting their sensitive information *)
signature ACCOUNT =
sig
type authentication
type account = int
val authenticate : string * string -> authentication option
val query_balance : account * authentication -> int
end
(* This implementation would ideally be in another file, hidden from the user *)
structure BankAccount :> ACCOUNT =
struct
type authentication = string * string
type account = int
val private_data = [("Nick", "Password"),
("Barack Obama", "Senoritis"),
("Sofia Coppola", "Dreamer"),
("Darren Aronofsky", "Requiem")]
fun authenticate (uname, passwd) =
List.find (fn (a,b) => a=uname andalso b=passwd) private_data
(* Presumably a real bank would have actual data *)
(* However, in this bank, everyone has a constant bank balance of 42. *)
fun query_balance (acc, auth) = 42
end
(* Currying and High order functions *)
val numbers = [1, 1, 2, 3, 4, 5, 6, 7, 9, 13, 11, 81]
fun is_valid (x, y) = (x + y = 17)
val all_pairs = List.map (fn x => List.map (fn y => (x, y)) numbers) numbers
val valid_pairs = List.map (List.filter is_valid) all_pairs
val non_empty = List.filter (fn x => not(null x)) valid_pairs
val flattened = List.foldl (fn (x, acc) => (x @ acc)) [] non_empty
(* Only flattens lists that are one nested once. Remember, in SML all the elements
in a list must be of the same type. The depth of all of the lists will be the
same *)
(* flatten is already in the List standard library as List.concat but is here
for practice. *)
(* Type of the list is supplied to get around the "value restriction"
warning. *)
val flatten = List.foldr (fn (x : (int * int) list, acc) => x @ acc) []
(* This might look like unnecessary function wrapping but it is used to get
around the "value restriction" waring as well. This one works for types
'a list list *)
fun flatten2 xs = List.foldr (fn (x, acc) => x @ acc) [] xs