It ends up returning nothing. Also, when run, it says it is:
- val merge_sort = fn : ('a * 'a -> bool) -> 'b list -> 'a list
When I know it should be this:
- val merge_sort = fn : ('a * 'a -> bool) -> 'a list -> 'a list
The function:
fun merge_sort f =
let
fun merge(nil, ylist) = ylist
| merge(xlist, nil) = xlist
| merge(x::xend, y::yend) =
if f (x,y) then
x::merge(xend, y::yend)
else
y::merge(x::xend, yend)
fun split nil = (nil, nil)
| split [x] = ([x], nil)
| split (x::y::xy) =
let
val (low, up) = split xy
in
(x::low, y::up)
end
in
let
fun real nil = nil
| real L =
let
val (list1,list2) = split L
in
merge (real list1,real list2)
end
in
fn last => real last
end
end;
merge_sort (op >) [0, 5, 1, ~4, 9, 11]
The funny type is actually somewhat related to the bug that makes your function never terminate.
Removing the custom comparison and separating the helpers (and collapsing merge_sort and real):
fun split nil = (nil, nil)
| split [x] = ([x], nil)
| split (x::y::xy) =
let
val (low, up) = split xy
in
(x::low, y::up)
end;
fun merge (nil, ylist) = ylist
| merge (xlist, nil) = xlist
| merge (x::xend, y::yend) =
if x < y then
x::merge (xend, y::yend)
else
y::merge (x::xend, yend);
fun merge_sort nil = nil
| merge_sort L =
let
val (list1,list2) = split L
in
merge (merge_sort list1, merge_sort list2)
end;
we get these types:
val split = fn : 'a list -> 'a list * 'a list
val merge = fn : int list * int list -> int list
val merge_sort = fn : 'a list -> int list
and merge_sort takes a list of anything and produces an int list.
That's weird.
Let's look at how that was arrived at.
fun merge_sort nil = nil
nil can be a list of anything, so that gives 'a list -> 'a list.
| merge_sort L =
let
val (list1,list2) = split L
in
merge (merge_sort list1, merge_sort list2)
end;
Now, the result must be int list, because that's what merge produces, and that also agrees with the parameters of merge.
But there is still no way to infer a more specific type from merge_sort's parameter - it's only passed back to merge_sort, and 'a list is what we've already got, so we end up with 'a list -> int list.
Look at what happens when you sort a singleton list:
merge-sort [1]
--> let val (list1, list2) = split [1] in merge (merge_sort list1, merge_sort list2)
--> merge (merge_sort [1], merge_sort [])
and we have a recursion that doesn't terminate.
You need a separate base case for a singleton list:
| merge_sort [x] = [x]
and when you add that, the types are what they should be.
Since this is a debugging problem, here is how I might go about finding the problem:
First, I run the program and realize it throws an Out_of_memory exception. So I know that there's some infinite recursion going on. Somewhere a recursive call is supposed to hit a base case, but it isn't, and instead it calls itself until it eventually runs out of memory.
The function consists of multiple helper functions. See if they all work as intended.
Because merge is embedded as an inner function of merge_sort, it is hard to test in isolation because you can't refer directly to it, and if you move it out, it fails to compile because it expects the comparison function f from its parent scope. So I'm going to change merge slightly for testability purposes.
The split function doesn't need a similar modification, and the real function seems kind of unnecessary since it is just the merge-sort function; the let within a let also seems unnecessary, but since I'm moving all the helper functions out, those will be removed as a consequence anyway. So I'm going to remove real and just call it mergeSort.
The result (with some extra renaming of nil into [] and so on, which is just my preference):
fun merge p ([], ys) = ys
| merge p (xs, []) = xs
| merge p (x::xs, y::ys) =
if p (x,y) then
x::merge p (xs, y::ys)
else
y::merge p (x::xs, ys)
fun split [] = ([], [])
| split [x] = ([x], [])
| split (x::y::xys) =
let
val (lo, hi) = split xys
in
(x::lo, y::hi)
end
fun mergeSort p [] = []
| mergeSort p zs =
let
val (xs, ys) = split zs
in
merge p (mergeSort p xs, mergeSort p ys)
end
Testing this, it still throws an Out_of_memory error, so I didn't actually fix anything.
Let's try and run it by hand on a small input;
Every line that begins with = below signifies a term rewrite where I've replaced some part of the former expression with its definition. For example, mergeSort (op >) [1,2,3], which is the starting point, is replaced with the definition of mergeSort on the input that pattern matches [1,2,3].
Every line that begins with `- is my attempt to expand on a sub-part of an expression without including that in the total rewrite of the above expression -- otherwise that might get a bit messy.
mergeSort (op >) [1,2,3]
= let val (xs, ys) = split [1,2,3] in merge (op >) (mergeSort (op >) xs, mergeSort (op >) ys) end
`- split [1,2,3]
= let val (lo, hi) = split [3] in (1::lo, 2::hi) end
= let val (lo, hi) = ([3], []) in (1::lo, 2::hi) end
= (1::[3], 2::[])
= ([1,3], [2])
= let val (xs, ys) = ([1,3], [2]) in merge (op >) (mergeSort p xs, mergeSort p ys) end
= merge (op >) (mergeSort (op >) [1,3], mergeSort (op >) [2])
`- mergeSort (op >) [1,3]
= let val (xs, ys) = split [1,3] in merge (op >) (mergeSort (op >) xs, mergeSort (op >) ys) end
`- split [1,3]
= let val (lo, hi) = split [] in (1::lo, 3::hi) end
= let val (lo, hi) = ([], []) in (1::lo, 3::hi) end
= (1::[], 3::hi)
= ([1], [3])
= let val (xs, ys) = ([1], [3]) in merge (op >) (mergeSort (op >) xs, mergeSort (op >) ys) end
= merge (op >) (mergeSort (op >) [1], mergeSort (op >) [3])
`- mergeSort (op >) [1]
= let val (xs, ys) = split [1] in merge (op >) (mergeSort (op >) xs, mergeSort (op >) ys) end
= let val (xs, ys) = ([1], []) in merge (op >) (mergeSort (op >) xs, mergeSort (op >) ys) end
= merge (op >) (mergeSort (op >) [1], mergeSort (op >) [])
`- OOPS!
I don't know if you noticed, but in my attempt to calculate mergeSort (op >) [1], I was very quickly asked to calculate mergeSort (op >) [1] as part of its result. But doing that I'll quickly end up doing that again, and again, and again. So it appears, from running the function by hand, that the infinite recursion is located in what I call mergeSort and what your code calls real.
This is a bug in the algorithm that can be fixed by stating something about the sortedness of a singleton list.
As a side note, here's how I might rewrite this function entirely:
fun merge cmp ([], ys) = ys
| merge cmp (xs, []) = xs
| merge cmp (xs as x::xs', ys as y::ys') =
case cmp (x, y) of
GREATER => y :: merge cmp (xs, ys')
| _ => x :: merge cmp (xs', ys)
fun sort cmp [] = []
| sort cmp [x] = [x]
| sort cmp xs =
let
val ys = List.take (xs, length xs div 2)
val zs = List.drop (xs, length xs div 2)
in
merge cmp (sort cmp ys, sort cmp zs)
end
fun down LESS = GREATER
| down GREATER = LESS
| down EQUAL = EQUAL
(I've preserved the bug.)
Sorting integers is now:
sort (fn (x,y) => down (Int.compare (x,y))) [1,2,3]
I want to be able to compare two items of type "list" in Coq and get a boolean "true" or "false" for their equivalence.
Right now, I'm comparing the two lists this way:
Eval vm_compute in (list 1 = list 2).
I get a Prop of the form:
= nil
:: (2 :: 3 :: nil)
:: (2 :: nil)
:: (3 :: nil) :: nil =
nil
:: (2 :: 3 :: nil)
:: (2 :: nil)
:: (3 :: nil) :: nil
: Prop
Obviously list1 = list2, so how do I get it to just return true or false?
I use the Mathematical Components Library boolean equality operators:
From mathcomp Require Import all_ssreflect.
...
Eval vm_compute in list 1 == list 2
You can generate a boolean list equality function that takes as input a boolean equality over the elements automatically using Coq's commands:
Require Import Coq.Lists.List Coq.Bool.Bool.
Import Coq.Lists.List.ListNotations.
Scheme Equality for list.
This prints:
list_beq is defined
list_eq_dec is defined
where list_beq is a boolean equality function on lists that takes as first parameter a comparison function for the lists elements and then two lists:
Print list_beq.
Gives
list_beq =
fun (A : Type) (eq_A : A -> A -> bool) =>
fix list_eqrec (X Y : list A) {struct X} : bool :=
match X with
| [] => match Y with
| [] => true
| _ :: _ => false
end
| x :: x0 => match Y with
| [] => false
| x1 :: x2 => eq_A x x1 && list_eqrec x0 x2
end
end
: forall A : Type, (A -> A -> bool) -> list A -> list A -> bool
and
Check list_eq_dec
gives
list_eq_dec
: forall (A : Type) (eq_A : A -> A -> bool),
(forall x y : A, eq_A x y = true -> x = y) ->
(forall x y : A, x = y -> eq_A x y = true) -> forall x y : list A, {x = y} + {x <> y}
showing that list equality is decidable if the underlying types equality is agrees with leibniz equality.
I'm supposed to right a function less(e, L) int * int list -> int list that returns a list of all the elements in L that are smaller then e. I wrote this:
fun less(_, nil) = nil
| less(e, L) =
let
val x::xs = less (e, tl L)
in
if e > hd L then hd L::x::xs
else nil # x::xs
end;
I'm getting a binding failure, surely in the let in bit. I tried a lot of different thinfs already, and I can't figure out why this is wrong. Can anyone shed a light?
val x::xs = less (e, tl L)
This does not match the case where the result of less (e, t1 L) is the empty list.
A correct implementation of the function is this:
fun less (_, nil) = nil
| less (y, x::xs) =
let
val xs' = less (y, xs)
in
if x < y then x::xs' else xs'
Assume you have the following definition:
abstract class IntSet {
def incl(x: Int): IntSet
def contains(x: Int): Boolean
def union(other: IntSet): IntSet
}
case class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet {
def incl(x: Int) =
if (x < elem) NonEmpty(elem, left incl x, right)
else if (x > elem) NonEmpty(elem, left, right incl x)
else this
def contains(x: Int) =
if (x < elem) left contains x
else if (x > elem) right contains x
else true
def union(other: IntSet) = (left union (right union other)) incl elem
}
object Empty extends IntSet {
def incl(x: Int) = NonEmpty(x, Empty, Empty)
def contains(x: Int) = false
def union(other: IntSet) = other
}
and the following proposition has to be proven:
(xs union ys) contains x = xs contains x || ys contains x
From here I deduce two base cases. xs = Empty and ys = Empty. It is the second base case where I got stuck because of the following reasoning:
// substituting ys = Empty
(xs union Empty) contains x = xs contains x || Empty contains x
// RHS:
xs contains x || false
xs contains x
// LHS:
((left union (right union Empty)) incl elem) contains x // By definition of NonEmpty.union
How can I reduce the LHS to xs contains x? Do I have to do another Induction Hypothesis on xs union Empty = xs and if so, how can that be used to the expression?
To Prove:
(xs union ys) contains x = xs contains x || ys contains x
Given:
Definitions above
Empty contains x = false
(s incl x) contains x = true
(s incl y) contains x = s contains x ; if x != y
Induction Step and Structural Proof using xs only, not ys, please refer to the original problem
Case I:
if xs = Empty
Left Hand Side:
(Empty union ys) contains x
= ys contains x => Definition of Empty union other
Right Hand Side:
Empty contains x || ys contains x
= false || ys contains x => Definition of Empty contains x
= ys contains x => Truth table of OR ( false OR true = true, false OR false = false)
Left Hand Side = Right Hand Side hence Induction step proved, the statement is true for all subtrees
Case II:
if (xs is NonEmpty(z, l, r) and z = x)
Left Hand Side:
(NonEmpty(x, l, r) union ys) contains x
= ((l union(r union ys)) incl x) contains x => From definition of union on NonEmpty
= true => from (3) above (s incl x) contains x = true
Right Hand Side:
xs contains x || ys contains x
= NonEmpty(x, l, r) contains x || ys contains x => From definition of xs
= true || ys contains x => From definition of contains on NonEmpty
= true => Truth table of OR (true OR false = true, true OR true = true)
Left Hand Side = Right Hand Side
Case III:
if ( xs is NonEmpty(z, l, r) and z < x )
Left Hand Side:
(NonEmpty(z, l, r) union ys) contains x
= (l union(r union ys) incl z) contains x => From definition of union
= (l union(r union ys)) contains x => From (4) above (s incl x) contains y = s contains y; if x != y
= (l contains x || (r union ys) contains x) => From induction step, the statement is true for all subtrees
= (l contains x || r contains x || ys contains x) => From induction step, the statement is true for all subtrees
= r contains x || ys contains x => since z < x, definition of contains (l contains x) returns false
Right Hand Side:
(if z < x)
NonEmpty(z, l, r) contains x || ys contains x
= r contains x || ys contains x => definition of contains,
Left Hand Side = Right Hand Side,
The case if ( xs is NonEmpty(z, l, r) and z > x ) is analogous to Case III above
Hence proved
I am following the Functional Programming in Scala lecture on Coursera and at the end of the video 5.7, Martin Odersky asks to prove by induction the correctness of the following equation :
(xs ++ ys) map f = (xs map f) ++ (ys map f)
How to handle proof by induction when there are multiple lists involved ?
I have checked the base cases of xs being Nil and ys being Nil.
I have proven by induction that the equation holds when xs is replaced by x::xs, but do we also need to check the equation with ys replaced by y::ys ?
And in that case (without spoiling the exercise too much...which is not graded anyway) how do you handle : (xs ++ (y::ys)) map f ?
This is the approach I have used on a similar example, to prove that
(xs ++ ys).reverse = ys.reverse ++ xs.reverse
Proof (omitting the base case, and easy x::xs case) :
(xs ++ (y::ys)).reverse
= (xs ++ (List(y) ++ ys)).reverse //y::ys = List(y) ++ ys
= ((xs ++ List(y)) ++ ys).reverse //concat associativity
= ys.reverse ++ (xs ++ List(y)).reverse //by induction hypothesis (proven with x::xs)
= ys.reverse ++ List(y).reverse ++ xs.reverse //by induction hypothesis
= ys.reverse ++ (y::Nil).reverse ++ xs.reverse //List(y) = y :: Nil
= ys.reverse ++ Nil.reverse ++ List(y) ++ xs.reverse //reverse definition
= (ys.reverse ++ List(y)) ++ xs.reverse //reverse on Nil (base case)
= (y :: ys).reverse ++ xs.reverse //reverse definition
Is this right ?
The property involves multiple lists, but ++ only recurses on its left argument. That's a hint that you can prove by induction on that left argument. In general, when proving a proposition about some recursive function, the first thing you try is inducting on the same argument that function recurses on.
I'll do this one for you as an example:
Claim: (xs ++ ys) map f = (xs map f) ++ (ys map f)
Proof: by induction on xs.
Base case: xs = Nil
lhs = (Nil ++ ys) map f = ys map f
(by ++'s definition)
rhs = (Nil map f) ++ (ys map f) = Nil ++ ys map f = ys map f
(by map's, then ++'s definitions)
Hence lhs = rhs
Inductive case: xs = z :: zs
hypothesis: (zs ++ ys) map f = (zs map f) ++ (ys map f)
goal: ((z :: zs) ++ ys) map f = ((z :: zs) map f) ++ (ys map f)
lhs = (z :: (zs ++ ys)) map f = f(z) :: ((zs ++ ys) map f) (1)
(by map's definition)
rhs = ((z :: zs) map f) ++ (ys map f) = (f(z) :: (zs map f)) ++ (ys map f)
(by map's definition)
in turn, rhs = f(z) :: ((zs map f) ++ (ys map f)) (2)
(by ++'s definition)
From hypothesis, (1) and (2), we have proven goal.
Therefore, we have proven the claim to be true reguardless of xs, ys, and f.
As the comment of #Phil says, first is a good understaning of what the methods ++ and :: are doing on the lists the better way is the documentation
How can we prove properties of list programs?
The answer is by Structural induction!
Proof rule for proving a list property P(xs) via structural induction:
P(Nil) (base case)
for all x,xs : P(xs) => P(x::xs) (induction step)
for all xs : P(xs) (consequence)
P(xs) in induction step is called induction hypothesis
for as the only important thing is xs, ys is fix proper List with lenght l, after proving for xs you can proof for ys, or see that is commutative
So let's apply induction and the definitions of the functions
P(xs): (xs ++ ys) map f = (xs map f) ++ (ys map f)
Base case we substitue xs by nil
(nil ++ ys) map f [definition of ++ ]
ys map f on the other hand
(xs map f) ++ (ys map p) [apply map over NIL]
(NIL) ++ (ys map p) [definition pf ++]
ys map p
Induction Step
((x::xs) ++ ys) map f [definition ++]
(x:: (xs ++ ys)) map f [definition map]
f(x) :: ((xs ++ ys) map f) [induction hypothesis]
f(x) :: ((xs map f) ++ (ys map f)) [definition ++]
(f(x) :: (xs map f)) ++ (ys map f) [definition map]
(x::xs) map f ++ ys map f
q.e.d
for example another case in a scala work sheet
import scala.util.Random
// P : length ( append(as,bs) )) = length ( as ) + length (bs)
def length[T](as: List[T]): Int = as match {
case Nil => 0
case _::xs => 1 + length(xs)
}
def append[T](as: List[T], bs: List[T]): List[T] = as match {
case Nil => bs
case x :: xs => x :: append(xs, bs)
}
// base case we substitute Nil for as in P
val a:List[Int] = Nil
val n = 10
val b:List[Int] = Seq.fill(n)(Random.nextInt).toList
length((append(a,b)))
length(a)
length(b)
import scala.util.Random
length: length[T](val as: List[T]) => Int
append: append[T](val as: List[T],val bs: List[T]) => List[T]
a: List[Int] = List()
n: Int = 10
b: List[Int] = List(1168053950, 922397949, -1884264936, 869558369, -165728826, -1052466354, -1696038881, 246666877, 1673332480, -975585734)
res0: Int = 10
res1: Int = 0
res2: Int = 10
here you can find more examples