diff --git a/hackett-doc/scribblings/hackett/reference.scrbl b/hackett-doc/scribblings/hackett/reference.scrbl index ddc9bb6..b6e12b2 100644 --- a/hackett-doc/scribblings/hackett/reference.scrbl +++ b/hackett-doc/scribblings/hackett/reference.scrbl @@ -637,41 +637,132 @@ The @deftech{list} type, which describes lazy linked lists. Since a list is lazy as long as the entire list is never demanded. The @racket[::] constructor is pronounced “cons”, and it is generally intended to be used infix.} -@defthing[head (t:forall [a] {(t:List a) t:-> (t:Maybe a)})]{ +@defproc[(head [xs (t:List a)]) (t:Maybe a)]{ -Returns @racket[Just] the first element of a list, or @racket[Nothing] if the list is @racket[Nil]. +Returns @racket[Just] the first element of @racket[xs], or @racket[Nothing] if @racket[xs] is @racket[Nil]. @(hackett-examples (head {1 :: 2 :: 3 :: Nil}) (head (: Nil (t:List t:Integer))))} -@defthing[tail (t:forall [a] {(t:List a) t:-> (t:Maybe (t:List a))})]{ +@defproc[(last [xs (t:List a)]) (t:Maybe a)]{ -Returns @racket[Just] a list without its first element, or @racket[Nothing] if the list is +Returns @racket[Just] the last element of @racket[xs], or @racket[Nothing] if @racket[xs] is @racket[Nil]. +This function is @tech[#:key "partial function"]{partial}, since it diverges on an infinitely long +input, e.g. @racket[(letrec ([ones {1 :: ones}]) (last ones))]. + +@(hackett-examples + (last {1 :: 2 :: 3 :: Nil}) + (last (: Nil (t:List t:Integer))))} + +@defproc[(tail [xs (t:List a)]) (t:Maybe (t:List a))]{ + +Returns @racket[Just] @racket[xs] without its first element, or @racket[Nothing] if @racket[xs] is @racket[Nil]. @(hackett-examples (tail {1 :: 2 :: 3 :: Nil}) (tail (: Nil (t:List t:Integer))))} -@defthing[head! (t:forall [a] {(t:List a) t:-> a})]{ +@defproc[(init [xs (t:List a)]) (t:Maybe a)]{ + +Returns @racket[Just] @racket[xs] without its the last element, or @racket[Nothing] if @racket[xs] is +@racket[Nil]. This function is @tech[#:key "partial function"]{partial}, since it diverges on an +infinitely long input, e.g. @racket[(letrec ([ones {1 :: ones}]) (init ones))]. -A @tech[#:key "partial function"]{partial} version of @racket[head] that returns the first element of -a list. If the list is empty, it raises an error. +@(hackett-examples + (init {1 :: 2 :: 3 :: Nil}) + (init (: Nil (t:List t:Integer))))} + +@defproc[(head! [xs (List a)]) a]{ + +A @tech[#:key "partial function"]{partial} version of @racket[head] which returns the first element of +@racket[xs]. If @racket[xs] is empty, @racket[head!] raises an error. @(hackett-examples (head! {1 :: 2 :: 3 :: Nil}) (eval:error (head! (: Nil (t:List t:Integer)))))} -@defthing[tail! (t:forall [a] {(t:List a) t:-> (t:List a)})]{ +@defproc[(last! [xs (t:List a)]) a]{ -A @tech[#:key "partial function"]{partial} version of @racket[tail] that returns a list without its -first element. If the list is empty, it raises an error. +A less-safe version of @racket[last] which returns the last element of @racket[xs]. This function +is @tech[#:key "partial function"]{partial}, since when @racket[xs] is empty, @racket[last!] raises +an error, and if @racket[xs] is infinitely long, @racket[last!] will never return. + +@(hackett-examples + (last! {1 :: 2 :: 3 :: Nil}) + (eval:error (last! (: Nil (t:List t:Integer)))))} + +@defproc[(tail! [xs (t:List a)]) (t:List a)]{ + +A @tech[#:key "partial function"]{partial} version of @racket[tail] that returns @racket[xs] without +its first element. If @racket[xs] is empty, @racket[tail!] raises an error. @(hackett-examples (tail! {1 :: 2 :: 3 :: Nil}) (eval:error (tail! (: Nil (t:List t:Integer)))))} +@defproc[(init! [xs (t:List a)]) a]{ + +A less-safe version of @racket[init] which returns the last element of @racket[xs]. This function +is @tech[#:key "partial function"]{partial}, since when @racket[xs] is empty, @racket[init!] raises an +error, and if @racket[xs] is infinitely long, @racket[init!] will never return. + +@(hackett-examples + (init! {1 :: 2 :: 3 :: Nil}) + (eval:error (init! (: Nil (t:List t:Integer)))))} + +@defproc[(inits [xs (t:List a)]) (t:List (t:List a))]{ + +Returns a list of the inital segments of @racket[xs]. + +@(hackett-examples + (inits {1 :: 2 :: 3 :: Nil}) + (inits (: Nil (t:List t:Integer))))} + +@defproc[(tails [xs (t:List a)]) (t:List (t:List a))]{ + +Returns a list of the terminal segments of @racket[xs]. + +@(hackett-examples + (tails {1 :: 2 :: 3 :: Nil}) + (tails (: Nil (t:List t:Integer))))} + +@defproc[(uncons [xs (t:List a)]) (t:Maybe (t:Tuple a (t:List a)))]{ + +When @racket[xs] is @racket[Nil], @racket[uncons xs] is @racket[Nothing]. Otherwise, if @racket[xs] +is @racket[{y :: ys}] then @racket[uncons xs] is @racket[Just (Tuple y ys)]. + +@(hackett-examples + (uncons {1 :: 2 :: 3 :: Nil}) + (uncons (: Nil (t:List t:Integer))))} + +@defproc[(uncons! [xs (t:List a)]) (t:Tuple a (t:List a))]{ + +A @tech[#:key "partial function"]{partial} version of @racket[uncons] that returns +@racket[Tuple (head! xs) (tail! xs)]. If @racket[xs] is empty, it instead raises an error. + +@(hackett-examples + (uncons! {1 :: 2 :: 3 :: Nil}) + (eval:error (uncons! (: Nil (t:List t:Integer)))))} + +@defproc[(nil? [xs (t:List a)]) (t:Bool)]{ + +This predicate is @racket[True] when @racket[xs] is of the form @racket[Nil], and is false otherwise. + +@(hackett-examples + (nil? {1 :: 2 :: 3 :: Nil}) + (nil? (: Nil (t:List t:Integer))))} + +@defproc[(length [xs (t:List a)]) t:Integer]{ + +Returns the length of @racket[xs] when @racket[xs] is finite. Since the function diverges on an +infinitely long input, @racket[length] is @tech[#:key "partial function"]{partial}. + +@(hackett-examples + (length {1 :: 2 :: 3 :: Nil}) + (length (: Nil (t:List t:Integer))))} + @defproc[(take [n t:Integer] [xs (t:List a)]) (t:List a)]{ Produces a list with the first @racket[n] elements of @racket[xs]. If @racket[xs] contains fewer than @@ -679,7 +770,18 @@ Produces a list with the first @racket[n] elements of @racket[xs]. If @racket[xs @(hackett-examples (take 2 {1 :: 2 :: 3 :: Nil}) - (take 2 {1 :: Nil}))} + (take 2 {1 :: Nil}) + (take 2 (: Nil (t:List t:Integer))))} + +@defproc[(take-while [p {a t:-> t:Bool}] [xs (t:List a)]) (t:List a)]{ + +Returns the longest initial segment of @racket[xs] such that every element satisfies @racket[p]. + +@(hackett-examples + (take-while (λ [x] {(remainder! x 2) == 1}) {1 :: 3 :: 6 :: 9 :: Nil}) + (let ([is-just (maybe False (const True))]) + (take-while is-just {(Just 1) :: (Just 2) :: Nothing :: (Just 3) :: Nil})) + (take-while (λ [x] {(remainder! x 2) == 0}) (: Nil (t:List t:Integer))))} @defproc[(drop [n t:Integer] [xs (t:List a)]) (t:List a)]{ @@ -688,7 +790,71 @@ then @racket[n] elements, the result is @racket[Nil]. @(hackett-examples (drop 2 {1 :: 2 :: 3 :: Nil}) - (drop 2 {1 :: Nil}))} + (drop 2 {1 :: Nil}) + (drop 2 (: Nil (t:List t:Integer))))} + +@defproc[(drop-while [p {a t:-> t:Bool}] [xs (t:List a)]) (t:List a)]{ + +Returns the longest terminal segment of @racket[xs] which is either @racket[Nil] or starts with an +element @racket[x] such that @racket[(not (p x))]. + +@(hackett-examples + (drop-while (λ [x] {(remainder! x 2) == 1}) {1 :: 3 :: 6 :: 9 :: Nil}) + (let ([is-just (maybe False (const True))]) + (drop-while is-just {(Just 1) :: (Just 2) :: Nothing :: (Just 3) :: Nil})) + (drop-while (λ [x] {(remainder! x 2) == 0}) (: Nil (t:List t:Integer))))} + +@defproc[(nth [xs (t:List a)] [n t:Integer]) (t:Maybe a)]{ + +Returns @racket[Just] the nth element of @racket[xs] if it exists, starting at 0, and +@racket[Nothing] if it doesn't. + +@(hackett-examples + (nth {1 :: 2 :: 3 :: Nil} 2) + (nth {1 :: 2 :: 3 :: Nil} -1) + (nth {1 :: Nil} 2) + (nth (: Nil (t:List t:Integer)) 2))} + +@defproc[(nth! [xs (t:List a)] [n t:Integer]) a]{ + +Returns the nth element of @racket[xs], starting at 0. This function is +@tech[#:key "partial function"]{partial}, because it errors when @racket[{n >= (length xs)}]. + +@(hackett-examples + (nth! {1 :: 2 :: 3 :: Nil} 2) + (eval:error (nth! {1 :: 2 :: 3 :: Nil} -1)) + (eval:error (nth! {1 :: Nil} 2)) + (eval:error (nth! (: Nil (t:List t:Integer)) 2)))} + +@defproc[(find-index [p {a t:-> Bool}] [xs (t:List a)]) (t:Maybe t:Integer)]{ + +Finds the first element of @racket[xs] which satisfies @racket[p], and returns @racket[Just] its +index. If there is no such element, the function returns @racket[Nothing]. + +@(hackett-examples + (find-index (λ [x] {(remainder! x 2) == 0}) {1 :: 2 :: 3 :: Nil}) + (find-index (λ [x] {x < 0}) {1 :: 2 :: 3 :: Nil}) + (find-index (const True) (: Nil (t:List t:Integer))))} + +@defproc[(index-of [_ (Eq a)] [x a] [xs (t:List a)]) (t:Maybe t:Integer)]{ + +Finds the first occurrence of @racket[x] in @racket[xs] and returns @racket[Just] its index. If +@racket[x] is not contained in @racket[xs], the function returns @racket[Nothing]. This is +equivalent to @racket[(find-index (== x) xs)]. + +@(hackett-examples + (index-of 2 {1 :: 2 :: 3 :: Nil}) + (index-of -1 {1 :: 2 :: 3 :: Nil}) + (index-of 2 Nil))} + +@defproc[(find [p {a t:-> t:Bool}] [xs (t:List a)]) (t:Maybe a)]{ + +Returns @racket[Just] the first element @racket[_x] of @racket[xs] such that @racket[(p _x)] is +@racket[True]. If no element in @racket[xs] satisfies @racket[p], @racket[Nothing] is returned. + +@(hackett-examples + (find (λ [x] {x > 5}) {3 :: 7 :: 2 :: 9 :: 12 :: 4 :: Nil}) + (find (λ [x] {x > 5}) {1 :: 2 :: 3 :: Nil}))} @defproc[(filter [f {a t:-> t:Bool}] [xs (t:List a)]) (t:List a)]{ @@ -731,6 +897,37 @@ the following expression: (foldl * 1 {1 :: 2 :: 3 :: 4 :: 5 :: Nil}) (foldl - 0 {1 :: 2 :: 3 :: 4 :: 5 :: Nil}))} +@defproc[(unfoldr [step {b t:-> (t:Maybe (t:Tuple a b))}] [seed b]) (t:List a)]{ + +@racket[unfoldr] constructs a list from an initial value, stopping when @racket[(step seed)] is +@racket[Nothing]. In a certain way, @racket[unfoldr] acts as a dual to @racket[foldr]. More +specifically, @racket[{(unfoldr g (foldr f z xs)) == xs}] when @racket[{(g z) == Nothing}] and +@racket[{(g (f x y)) == (Just (tuple x y))}] for any @racket[x] in @racket[xs]. + +@(hackett-examples + (unfoldr (λ [x] (if {x == 1} Nothing + (Just (Tuple (show x) (quotient! x 2))))) + 128) + (take 5 (unfoldr (λ [x] (Just (Tuple x {x + 2}))) 0)))} + +@defproc[(concat [_ (Monoid m)] [ms (t:List m)]) m]{ +Returns the result of appending each element of @racket[ms] together. Equivalent to +@racket[(foldr ++ mempty)]. + +@(hackett-examples + (eval:check (concat {"a" :: "b" :: "c" :: Nil}) "abc") + (eval:check (concat {{1 :: Nil} :: {2 :: 3 :: Nil} :: {4 :: 5 :: 6 :: Nil} :: Nil}) + (:: 1 (:: 2 (:: 3 (:: 4 (:: 5 (:: 6 Nil))))))))} + +@defproc[(fold-map [_ (Monoid m)] [f {a t:-> m}] [xs (List a)]) m]{ + +Applies @racket[f] to each element of @racket[xs] and concatenates each resulting list. Equivalent +to @racket[=<<] when @racket[m] is @racket[(List b)] for some @racket[b]. + +@(hackett-examples + (fold-map show {1 :: 2 :: 3 :: Nil}) + (fold-map tail {{1 :: Nil} :: Nil :: {2 :: 3 :: Nil} :: {4 :: 5 :: 6 :: Nil} :: Nil}))} + @defproc[(sum [xs (t:List t:Integer)]) t:Integer]{ Adds the elements of @racket[xs] together and returns the sum. Equivalent to @racket[(foldl + 0)]. @@ -739,6 +936,188 @@ Adds the elements of @racket[xs] together and returns the sum. Equivalent to @ra (eval:check (sum {1 :: 2 :: 3 :: Nil}) 6) (eval:check (sum Nil) 0))} +@defproc[(product [xs (t:List t:Integer)]) t:Integer]{ + +Multiplies the elements of @racket[xs] together and returns the product. Equivalent to +@racket[(foldl * 1)]. + +@(hackett-examples + (eval:check (product {1 :: 2 :: 3 :: 4 :: Nil}) 24) + (eval:check (product Nil) 1))} + +@defproc[(iterate [step {a t:-> a}] [seed a]) (List a)]{ + +Returns the infinite list @racket[{seed :: (step seed) :: (step (step seed)) :: ...}]. + +@(hackett-examples + (take 5 (iterate (+ 1) 0)) + (take 5 (iterate (λ [x] {x ++ "a"}) "")))} + +@defproc[(reverse (xs (t:List a))) (t:List a)]{ + +Returns @racket[xs] in reversed order. + +@(hackett-examples + (reverse {1 :: 2 :: 3 :: Nil}) + (reverse (: Nil (t:List t:Integer))))} + +@defproc[(zip-with [f {a t:-> b t:-> c}] [as (t:List a)] [bs (t:List b)]) (t:List c)]{ + +This function will apply @racket[f] to each element in @racket[as] and @racket[bs] until it +has reached the end of either, then it returns a list like +@racket[{(f _a0 _b0) :: (f _a1 _b1) :: (f _a2 _b2) :: ... :: Nil}] (where @racket[as] contains +elements named @racket[_a0], @racket[_a1], @racket[_a2] etc., and @racket[bs] contains elements +named @racket[_b0], @racket[_b1], @racket[_b2] etc.). + +@(hackett-examples + (zip-with + {1 :: 2 :: 3 :: Nil} {18 :: 42 :: 50 :: Nil}) + (zip-with + {1 :: 2 :: 3 :: Nil} {18 :: 42 :: 50 :: 100 :: Nil}) + (zip-with + {1 :: 2 :: 3 :: 4 :: Nil} {18 :: 42 :: 50 :: Nil}) + (zip-with * {1 :: 2 :: 3 :: Nil} {18 :: 42 :: 50 :: Nil}) + (zip-with + (: Nil (t:List t:Integer)) (: Nil (t:List t:Integer))))} + +@defproc[(zip [as (t:List a)] [bs (t:List b)]) (t:List (t:Tuple a b))]{ + +Returns a list of componenetwise pairs from @racket[as] and @racket[bs]. The length of this list is +the length of the shortest input list. Equivalent to @racket[(zip-with Tuple as bs)]. + +@(hackett-examples + (zip {1 :: 2 :: 3 :: Nil} {18 :: 42 :: 50 :: Nil}) + (zip {1 :: 2 :: 3 :: Nil} {18 :: 42 :: 50 :: 100 :: Nil}) + (zip {1 :: 2 :: 3 :: 4 :: Nil} {18 :: 42 :: 50 :: Nil}) + (zip (: Nil (t:List t:Integer)) (: Nil (t:List t:Integer))))} + +@defproc[(repeat [x a]) (t:List a)]{ + +Returns an infinite list containing only @racket[x]. + +@(hackett-examples + (take 5 (repeat 1)))} + +@defproc[(replicate [n Integer] [x a]) (t:List a)]{ + +Returns a list of @racket[n] copies of @racket[x]. + +@(hackett-examples + (replicate 3 1))} + +@defproc[(cycle! [xs (t:List a)]) (t:List a)]{ + +Returns the infinite list @racket[{xs ++ xs ++ xs ++ ...}]. If @racket[xs] is infinite, +@racket[{(cycle! xs)or == xs}]. This function is @tech[#:key "partial function"]{partial}, because it +errors when given @racket[Nil]. + +@(hackett-examples + (take 10 (cycle! {1 :: 2 :: 3 :: Nil})) + (eval:error (cycle! (: Nil (t:List t:Integer)))))} + +@defproc[(or [xs (t:List t:Bool)]) t:Bool]{ + +Logically ors the elements of @racket[xs] together and returns the result. Equivalent to @racket[(foldr || False)]. +Because it uses a right fold, the only elements which will be evaluated are those before the first expression which +evaluates to @racket[True]. Additionally, @racket[(or infinite-list)] can never return @racket[False], and +@racket[(or (repeat False))] will never terminate. + +@(hackett-examples + (or {True :: False :: Nil}) + (or {False :: True :: Nil}) + (or {True :: (error! "never happens") :: Nil}) + (or Nil))} + +@defproc[(and [xs (t:List t:Bool)]) t:Bool]{ + +Logically ands the elements of @racket[xs] together and returns the result. Equivalent to @racket[(foldr && True)]. +Because it uses a right fold, the only elements which will be evaluated are those before the first expression which +evaluates to @racket[False]. Additionally, @racket[(and infinite-list)] can never return @racket[True], and +@racket[(and (repeat True))] will never terminate. + +@(hackett-examples + (and {True :: False :: Nil}) + (and {False :: True :: Nil}) + (and {False :: (error! "never happens") :: Nil}) + (and Nil))} + +@defproc[(any? [p {a t:-> t:Bool}] [xs (t:List t:Bool)]) t:Bool]{ + +Returns @racket[True] if @racket[xs] contains an element @racket[x] such that @racket[(p x)] is +@racket[True]. Equivalent to @racket[(or (map p xs))]. + +@(hackett-examples + (any? (<= 2) {1 :: 2 :: 3 :: Nil}) + (any? (<= 4) {1 :: 2 :: 3 :: Nil}) + (any? (<= 0) {1 :: (error! "never happens") :: Nil}) + (any? (<= 0) Nil))} + +@defproc[(all? [p {a t:-> t:Bool}] [xs (t:List t:Bool)]) t:Bool]{ + +Returns @racket[True] if for every element @racket[x] of @racket[xs] @racket[(p x)] is +@racket[True]. Equivalent to @racket[(and (map p xs))]. + +@(hackett-examples + (all? (<= 1) {1 :: 2 :: 3 :: Nil}) + (all? (<= 2) {1 :: 2 :: 3 :: Nil}) + (all? (<= 2) {1 :: (error! "never happens") :: Nil}) + (all? (<= 1) Nil))} + +@defproc[(elem? [_ (t:Eq a)] [x a] [xs (t:List a)]) t:Bool]{ + +Returns @racket[True] if @racket[xs] contains @racket[x]. Equivalent to @racket[(any? (== x) xs)]. +Only elements to the left of the first expression equal to @racket[x] in @racket[xs] will be checked +for equality. + +@(hackett-examples + (elem? 2 {1 :: 2 :: 3 :: Nil}) + (elem? 0 {1 :: 2 :: 3 :: Nil}) + (elem? 1 {1 :: (error! "never happens") :: Nil}) + (elem? 1 Nil))} + +@defproc[(not-elem? [_ (t:Eq a)] [x a] [xs (t:List a)]) t:Bool]{ + +Returns @racket[False] if @racket[xs] contains @racket[x]. Equivalent to @racket[(not (elem? x xs))]. +Only elements to the left of the first expression equal to @racket[x] in @racket[xs] will be checked +for equality. + +@(hackett-examples + (elem? 2 {1 :: 2 :: 3 :: Nil}) + (elem? 0 {1 :: 2 :: 3 :: Nil}) + (elem? 1 {1 :: (error! "never happens") :: Nil}) + (elem? 1 Nil))} + +@defproc[(delete [_ (t:Eq a)] [x a] [xs (t:List a)]) (t:List a)]{ + +Returns @racket[xs] with the first occurrence of @racket[x] removed. Equivalent to +@racket[(delete-by == x xs)]. Only elements to the left of the first expression equal to @racket[x] +in @racket[xs] will be checked for equality. + +@(hackett-examples + (delete 2 {1 :: 2 :: 3 :: Nil}) + (delete 2 {1 :: 2 :: 3 :: 2 :: Nil}) + (delete 0 {1 :: 2 :: 3 :: Nil}) + (head (delete 1 {1 :: 2 :: (error! "never happens") :: Nil})) + (delete 1 Nil))} + +@defproc[(delete-by [rel {a t:-> a t:-> t:Bool}] [x a] [xs (t:List a)]) (t:List a)]{ + +Finds the first element @racket[y] such that @racket[{y rel x}] and returns @racket[xs] with +@racket[y] removed. Generalizes @racket[delete]. Only elements to the left of the first expression +such @racket[y] will be checked for equality. + +@(hackett-examples + (delete-by > 2 {1 :: 2 :: 3 :: Nil}) + (delete-by > 0 {1 :: 2 :: 3 :: Nil}) + (head (delete-by /= 1 {1 :: 2 :: (error! "never happens") :: Nil})) + (delete-by (λ [y x] {(remainder! y x) == 0}) 2 Nil) + (delete-by (error! "never happens") (error! "never happens") (: Nil (t:List t:Integer))))} + +@defproc[(intersperse [x a] [xs (t:List a)]) (t:List a)]{ + +Given a separator and a list, intersperse returns a new list with the separator placed between each +element of the list. + +@(hackett-examples + (intersperse 42 {1 :: 2 :: 3 :: Nil}) + (intersperse 42 Nil))} + @section[#:tag "reference-typeclasses"]{Typeclasses} @subsection[#:tag "reference-defining-typeclasses"]{Defining typeclasses and typeclass instances} @@ -802,9 +1181,14 @@ evaluated, produces the value. @subsection[#:tag "reference-equality"]{Equality} @defclass[(t:Eq a) - [== {a t:-> a t:-> t:Bool}]]{ + [== {a t:-> a t:-> t:Bool}] + [/= {a t:-> a t:-> t:Bool}]]{ The class of types with a notion of equality. The @racket[==] method should produce @racket[True] if -both of its arguments are equal, otherwise it should produce @racket[False]. +both of its arguments are equal, otherwise it should produce @racket[False]. The @racket[/=] +method should produce @racket[True] if its arguments are unequal, otherwise it should produce +@racket[False]. Default implementations of @racket[==] and @racket[/=] are given in terms of the +negation of the other, in case inequality is easier to define than equality, or if it is more +efficient to implement independent definitions for each. @defmethod[== {a t:-> a t:-> t:Bool}]{ @@ -813,7 +1197,16 @@ both of its arguments are equal, otherwise it should produce @racket[False]. (eval:check {10 == 11} False) (eval:check {{1 :: 2 :: Nil} == {1 :: 2 :: Nil}} True) (eval:check {{1 :: 2 :: Nil} == {1 :: Nil}} False) - (eval:check {{1 :: 2 :: Nil} == {1 :: 3 :: Nil}} False))}} + (eval:check {{1 :: 2 :: Nil} == {1 :: 3 :: Nil}} False))} + +@defmethod[/= {a t:-> a t:-> t:Bool}]{ + +@(hackett-examples + (eval:check {10 /= 10} False) + (eval:check {10 /= 11} True) + (eval:check {{1 :: 2 :: Nil} /= {1 :: 2 :: Nil}} False) + (eval:check {{1 :: 2 :: Nil} /= {1 :: Nil}} True) + (eval:check {{1 :: 2 :: Nil} /= {1 :: 3 :: Nil}} True))}} @subsection[#:tag "reference-semigroup-monoid"]{Semigroups and monoids} diff --git a/hackett-lib/hackett/data/list.rkt b/hackett-lib/hackett/data/list.rkt index 47e56a4..5fe7fce 100644 --- a/hackett-lib/hackett/data/list.rkt +++ b/hackett-lib/hackett/data/list.rkt @@ -3,23 +3,77 @@ (require hackett/data/maybe hackett/private/prim) -(provide (data List) head tail head! tail! take drop filter foldr foldl reverse zip-with sum - repeat cycle! or and any? all? elem? not-elem? delete delete-by) +(provide (data List) head last tail init head! last! tail! init! uncons uncons! unfoldr nil? length + nth nth! find-index index-of take take-while drop drop-while tails inits filter find + foldr foldl reverse zip-with zip sum product iterate repeat replicate cycle! concat + fold-map or and any? all? elem? not-elem? delete delete-by intersperse) (defn head : (∀ [a] {(List a) -> (Maybe a)}) [[{x :: _}] (Just x)] [[Nil ] Nothing]) +(defn last : (forall [a] {(List a) -> (Maybe a)}) + [[{x :: Nil}] (Just x)] + [[{_ :: xs} ] (last xs)] + [[_ ] Nothing]) + (defn tail : (∀ [a] {(List a) -> (Maybe (List a))}) [[{_ :: xs}] (Just xs)] [[Nil ] Nothing]) +(defn init : (forall [a] {(List a) -> (Maybe (List a))}) + [[Nil] Nothing] + [[xs ] (Just (init! xs))]) + (defn head! : (∀ [a] {(List a) -> a}) [[xs] (from-maybe (error! "head!: empty list") (head xs))]) +(defn last! : (forall [a] {(List a) -> a}) + [[xs] (from-maybe (error! "last!: empty list") (last xs))]) + (defn tail! : (∀ [a] {(List a) -> (List a)}) [[xs] (from-maybe (error! "tail!: empty list") (tail xs))]) +(defn init! : (forall [a] {(List a) -> (List a)}) + [[{_ :: Nil}] Nil] + [[{x :: xs} ] {x :: (init! xs)}] + [[Nil ] (error! "tail!: empty list")]) + +(defn uncons : (forall [a] {(List a) -> (Maybe (Tuple a (List a)))}) + [[{x :: xs}] (Just (Tuple x xs))] + [[Nil ] Nothing]) + +(defn uncons! : (forall [a] {(List a) -> (Tuple a (List a))}) + [[xs] (from-maybe (error! "uncons!: empty list") (uncons xs))]) + +(defn unfoldr : (forall [a b] {{b -> (Maybe (Tuple a b))} -> b -> (List a)}) + [[step seed] (case (step seed) + [Nothing Nil] + [(Just (Tuple a b)) {a :: (unfoldr step b)}])]) + +(defn nil? : (forall [a] {(List a) -> Bool}) + [[Nil] True] + [[_ ] False]) + +(def length : (forall [a] {(List a) -> Integer}) + (foldr (λ [_ acc] {acc + 1}) 0)) + +(defn nth : (forall [a] {(List a) -> Integer -> (Maybe a)}) + [[{x :: xs} n] (if {n < 0} Nothing + (if {n == 0} (Just x) + (nth xs {n - 1})))] + [[Nil _] Nothing]) + +(defn nth! : (forall [a] {(List a) -> Integer -> a}) + [[xs n] (from-maybe (error! "nth!: empty list") (nth xs n))]) + +(defn find-index : (forall [a] {{a -> Bool} -> (List a) -> (Maybe Integer)}) + [[p {x :: xs}] (if (p x) (Just 0) (map (+ 1) (find-index p xs)))] + [[_ Nil ] Nothing]) + +(def index-of : (forall [a] (Eq a) => {a -> (List a) -> (Maybe Integer)}) + {find-index . ==}) + (defn take : (∀ [a] {Integer -> (List a) -> (List a)}) [[n {x :: xs}] (if {n == 0} @@ -28,6 +82,14 @@ [[_ Nil] Nil]) +(defn take-while : (∀ [a] {{a -> Bool} -> (List a) -> (List a)}) + [[p {x :: xs}] + (if (p x) + {x :: (take-while p xs)} + Nil)] + [[_ Nil] + Nil]) + (defn drop : (∀ [a] {Integer -> (List a) -> (List a)}) [[n {x :: xs}] (if {n == 0} @@ -36,10 +98,32 @@ [[_ Nil] Nil]) +(defn drop-while : (∀ [a] {{a -> Bool} -> (List a) -> (List a)}) + [[p {x :: xs}] + (if (p x) + (drop-while p xs) + {x :: xs})] + [[_ Nil] + Nil]) + +(def tails : (forall [a] {(List a) -> (List (List a))}) + (λ [l] {l :: (case l + [{x :: xs} (tails xs)] + [Nil Nil])})) + +(def inits : (forall [a] {(List a) -> (List (List a))}) + (λ [l] {Nil :: (case l + [Nil Nil] + [{x :: xs} (map (:: x) (inits xs))])})) + (defn filter : (∀ [a] {{a -> Bool} -> (List a) -> (List a)}) [[f {x :: xs}] (let ([ys (filter f xs)]) (if (f x) {x :: ys} ys))] [[_ Nil ] Nil]) +(defn find : (forall [a] {{a -> Bool} -> (List a) -> (Maybe a)}) + [[p {x :: xs}] (if (p x) (Just x) (find p xs))] + [[p Nil ] Nothing]) + (defn foldl : (∀ [a b] {{b -> a -> b} -> b -> (List a) -> b}) [[f a {x :: xs}] (let ([b (f a x)]) {b seq (foldl f b xs)})] [[_ a Nil ] a]) @@ -51,16 +135,33 @@ [[f {x :: xs} {y :: ys}] {(f x y) :: (zip-with f xs ys)}] [[_ _ _ ] Nil]) +(def zip : (∀ [a b] {(List a) -> (List b) -> (List (Tuple a b))}) + (zip-with Tuple)) + (def sum : {(List Integer) -> Integer} (foldl + 0)) +(def product : {(List Integer) -> Integer} + (foldl * 1)) + +(defn iterate : (forall [a] {{a -> a} -> a -> (List a)}) + [[f x] {x :: (iterate f (f x))}]) + (defn repeat : (∀ [a] {a -> (List a)}) [[x] (letrec ([xs {x :: xs}]) xs)]) +(defn replicate : (∀ [a] {Integer -> a -> (List a)}) + [[n x] (if {n <= 0} + Nil + {x :: (replicate {n - 1} x)})]) + (defn cycle! : (∀ [a] {(List a) -> (List a)}) [[Nil] (error! "cycle!: empty list")] [[xs ] (letrec ([ys {xs ++ ys}]) ys)]) +(def fold-map : (forall [a m] (Monoid m) => {{a -> m} -> (List a) -> m}) + (λ [f] (foldr {++ . f} mempty))) + (def or : {(List Bool) -> Bool} (foldr || False)) @@ -77,7 +178,7 @@ [[x] (any? (== x))]) (defn not-elem? : (∀ [a] (Eq a) => {a -> (List a) -> Bool}) - [[x] (all? {not . (== x)})]) + [[x] {not . (elem? x)}]) (def delete : (∀ [a] (Eq a) => {a -> (List a) -> (List a)}) (delete-by ==)) @@ -89,3 +190,10 @@ {y :: (delete-by =? x ys)})] [[_ _ Nil] Nil]) + +(defn intersperse : (forall [a] {a -> (List a) -> (List a)}) + [[_ Nil ] Nil] + [[in {x :: xs}] (letrec ([helper + (λ* [[{y :: ys}] {in :: y :: (helper ys)}] + [[Nil ] Nil])]) + {x :: (helper xs)})]) diff --git a/hackett-lib/hackett/private/prim/base.rkt b/hackett-lib/hackett/private/prim/base.rkt index 5cdafba..30454b0 100644 --- a/hackett-lib/hackett/private/prim/base.rkt +++ b/hackett-lib/hackett/private/prim/base.rkt @@ -118,7 +118,10 @@ ;; Eq (class (Eq a) - [== : {a -> a -> Bool}]) + [== : {a -> a -> Bool} + (λ [a b] (not {a /= b}))] + [/= : {a -> a -> Bool} + (λ [a b] (not {a == b}))]) (instance (Eq Unit) [== (λ [Unit Unit] True)])