Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions lib/List.fram
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,38 @@ pub let tlErr { ~onError } xs =
| x :: xs => xs
end

{##
Returns the list without the last element or returns `None` if it already
was empty.
##}
pub let dropLast xs =
let rec dropLastAux y xs =
match xs with
| [] => []
| x :: xs => y :: dropLastAux x xs
end in
match xs with
| [] => None
| x :: xs => Some (dropLastAux x xs)
end

{##
Returns the list without the last element or calls `~onError` if it already
was empty.

@param ~onError Fallback function in case of an empty list.
##}
pub let dropLastErr { ~onError } xs =
let rec dropLastAux y xs =
match xs with
| [] => []
| x :: xs => y :: dropLastAux x xs
end in
match xs with
| [] => ~onError ()
| x :: xs => dropLastAux x xs
end

{##
Returns the n-th element of a list or `None` if n is negative or the list
is too short. The first element is at position 0.
Expand All @@ -82,6 +114,74 @@ pub let nthErr { ~onError } xs (n : Int) =
end
in if n < 0 then ~onError () else nthErrAux xs n

{##
Returns the last element of a list or `None` if the list is empty.
##}
pub let last xs =
let rec lastAux y xs =
match xs with
| [] => y
| x :: xs => lastAux x xs
end in
match xs with
| [] => None
| x :: xs => Some (lastAux x xs)
end

{##
Returns the last element of a list or calls `~onError` if list is empty.

@param ~onError Fallback for an empty list.
##}
pub let lastErr { ~onError } xs =
let rec lastErrAux y xs =
match xs with
| [] => y
| x :: xs => lastErrAux x xs
end in
match xs with
| [] => ~onError ()
| x :: xs => lastErrAux x xs
end

{##
Returns pair of combined results of `last` and `dropLast` functions,
but performs this computation in more optimized manner. Returns
`None` for an empty list.
##}
pub let dropTakeLast xs =
let rec dropTakeLastAux y xs =
match xs with
| [] => ([], y)
| x :: xs =>
let (init, last) = dropTakeLastAux x xs in
(y :: init, last)
end in
match xs with
| [] => None
| x :: xs => Some (dropTakeLastAux x xs)
end

{##
Returns pair of combined results of `last` and `dropLast` functions,
but performs this computation in more optimized manner. Calls `~onError` for
an empty list.

@param ~onError Fallback for an empty list.
##}
pub let dropTakeLastErr { ~onError } xs =
let rec dropTakeLastErrAux y xs =
match xs with
| [] => ([], y)
| x :: xs =>
let (init, last) = dropTakeLastErrAux x xs in
(y :: init, last)
end in
match xs with
| [] => ~onError ()
| x :: xs => dropTakeLastErrAux x xs
end

## Appends `ys` to `xs`.
pub let rec append xs ys =
match xs with
Expand Down Expand Up @@ -332,13 +432,67 @@ pub let rec foldLeft f acc xs =
| x :: xs => foldLeft f (f acc x) xs
end

{##
`foldLeft1 f [x1, x2, ... ,xn]` is `f (... (f (f x1 x2) x3) ...) xn`.
Returns `None` in case of an empty list.
##}
pub let rec foldLeft1 f xs =
match xs with
| [] => None
| x :: xs => Some (foldLeft f x xs)
end

{##
`foldLeft1Err f [x1, x2, ... ,xn]` is `f (... (f (f x1 x2) x3) ...) xn`.
Returns `~onError` in case of an empty list.

@param ~onError Fallback for an empty list.
##}
pub let rec foldLeft1Err { ~onError } f xs =
match xs with
| [] => ~onError ()
| x :: xs => foldLeft f x xs
end

## `foldRight f [x1, x2, ..., xn] init` is `f x1 (f x2 (... (f xn init)))`.
pub let rec foldRight f xs acc =
match xs with
| [] => acc
| x :: xs => f x (foldRight f xs acc)
end

{##
`foldRight1 f [x1, x2, ..., xn]` is `f x1 (... (f x(n-1) xn)))`.
Returns `None` for an empty list.
##}
pub let foldRight1 f xs =
let rec foldRight1Aux y xs =
match xs with
| [] => y
| x :: xs => f y (foldRight1Aux x xs)
end in
match xs with
| [] => None
| x :: xs => Some (foldRight1Aux x xs)
end

{##
`foldRight1Err f [x1, x2, ..., xn]` is `f x1 (... (f x(n-1) xn)))`.
Calls `~onError` for an empty list.

@param ~onError Fallback for an empty list.
##}
pub let foldRight1Err { ~onError } f xs =
let rec foldRight1ErrAux y xs =
match xs with
| [] => y
| x :: xs => f y (foldRight1ErrAux x xs)
end in
match xs with
| [] => ~onError ()
| x :: xs => foldRight1ErrAux x xs
end

{##
`foldLeft2 f init xs ys` works the same as `List.foldLeft` but `f` is
applied to consecutive pairs of elements from `xs` and `ys`.
Expand Down Expand Up @@ -610,8 +764,14 @@ pub method hd = hd
pub method hdErr = hdErr
pub method tl = tl
pub method tlErr = tlErr
pub method dropLast = dropLast
pub method dropLastErr = dropLastErr
pub method nth = nth
pub method nthErr = nthErr
pub method last = last
pub method lastErr = lastErr
pub method dropTakeLast = dropTakeLast
pub method dropTakeLastErr = dropTakeLastErr
pub method append = append
pub method add = append
pub method revAppend = revAppend
Expand All @@ -631,7 +791,11 @@ pub method dropWhile self p = dropWhile p self
pub method iter self f = iter f self
pub method iteri { ?i : Int } self f = iteri { ?i = i } f self
pub method foldLeft self f acc = foldLeft f acc self
pub method foldLeft1 self f = foldLeft1 self f
pub method foldLeft1Err self f = foldLeft1Err self f
pub method foldRight self f acc = foldRight f self acc
pub method foldRight1 self f = foldRight1 f self
pub method foldRight1Err self f = foldRight1Err f self
pub method forAll self p = forAll p self
pub method exists self p = exists p self
pub method find self p = find p self
Expand Down
69 changes: 69 additions & 0 deletions test/stdlib/stdlib0003_List.fram
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ parameter ~onError
let ~onError _ = exit 1
let retEmpty _ = []

let isNone opt =
match opt with
| Some _ => False
| None => True
end

let xs = [1,2,3,4]
let ys = [5,6,7,8]

Expand Down Expand Up @@ -73,6 +79,18 @@ let _ =
assert { msg = "tlErr" }
(List.isEmpty (List.tlErr { ~onError = retEmpty } ([] : List Int)))

let _ =
assert {msg = "dropLast"}
(List.dropLast [1, 2, 3] >.unwrapOr [] == [1, 2])
let _ = assert {msg = "dropLast"} (isNone (List.dropLast ([] : List Int)))

let _ =
assert {msg = "dropLastErr"}
(List.dropLastErr {~onError=retEmpty} [1, 2, 3] == [1, 2])
let _ =
assert {msg = "dropLastErr"}
(List.dropLastErr {~onError=retEmpty} ([] : List Int) >.isEmpty)

let _ =
assert { msg = "nth" }
(match List.nth xs 2 with
Expand All @@ -90,6 +108,28 @@ let _ =
assert { msg = "nthErr" }
(List.nthErr {~onError = fn _ => -1} xs 10 == -1)

let _ = assert {msg="last"} (isNone (List.last ([] : List Int)))
let _ = assert {msg="last"} (List.last [1, 2] >.unwrapOr 0 == 2)

let _ = assert {msg="lastErr"} (List.lastErr {~onError = fn _ => 0} [] == 0)
let _ = assert {msg="lastErr"} (List.lastErr {~onError = fn _ => 0} [1, 2] == 2)

let _ = assert {msg="dropTakeLast"}
match List.dropTakeLast [1, 2, 3] with
| Some (xs, x) => (3 == x) && ([1, 2] == xs)
| None => False
end
let _ = assert {msg="dropTakeLast"}
(isNone (List.dropTakeLast ([] : List Int)))

let _ = assert {msg="dropTakeLastErr"}
(let (xs, x) = List.dropTakeLastErr {~onError = fn _ => ([], 0)} [1, 2, 3]
in [1, 2] == xs && 3 == x)

let _ = assert {msg="dropTakeLastErr"}
(let (xs, x) = List.dropTakeLastErr {~onError = fn _ => ([], 0)} []
in ([] : List Int) == xs && 0 == x)

let _ = assert { msg = "append" } (xs + ys == [1,2,3,4,5,6,7,8])

let _ = assert { msg = "rev" } (List.rev xs == [4,3,2,1])
Expand Down Expand Up @@ -180,9 +220,38 @@ let _ = assert { msg = "init" } (List.init 5 id == [0,1,2,3,4])
let _ =
assert { msg = "foldLeft" }
(List.foldLeft (fn (a : Int) b => a + b) 0 xs == 10)
let _ =
assert {msg = "foldleft1"}
(List.foldLeft1 (fn (a : Int) b => a + b) xs >.unwrapOr 0 == 10)
let _ =
assert {msg = "foldleft1"}
(List.foldLeft1 (fn (a : Int) b => a + b) ([] : List Int) >.unwrapOr 0 == 0)
let _ =
assert {msg = "foldleft1Err"}
(List.foldLeft1Err {~onError = fn _ => 0}
(fn (a : Int) b => a + b) xs == 10)
let _ =
assert {msg = "foldleft1Err"}
(List.foldLeft1Err {~onError = fn _ => 0}
(fn (a : Int) b => a + b) ([] : List Int) == 0)

let _ =
assert { msg = "foldRight" }
(List.foldRight (fn (a : Int) b => a + b) xs 0 == 10)
let _ =
assert {msg = "foldRight1"}
(List.foldRight1 (fn (a : Int) b => a + b) xs >.unwrapOr 0 == 10)
let _ =
assert {msg = "foldRight1"}
(List.foldRight1 (fn (a : Int) b => a + b) ([] : List Int) >.unwrapOr 0 == 0)
let _ =
assert {msg = "foldRight1Err"}
(List.foldRight1Err {~onError = fn _ => 0}
(fn (a : Int) b => a + b) xs == 10)
let _ =
assert {msg = "foldRight1Err"}
(List.foldRight1Err {~onError = fn _ => 0}
(fn (a : Int) b => a + b) ([] : List Int) == 0)
let _ =
assert { msg = "foldLeft2" }
(List.foldLeft2 (fn (a : Int) b c => a + b + c) 0 xs ys == 36)
Expand Down