From 0c6043f479674b2e2da237b6a9faa8a8b0f9117b Mon Sep 17 00:00:00 2001 From: Rebecca Mark Date: Thu, 7 Jul 2022 00:57:16 -0700 Subject: [PATCH 1/5] WIP adding list concept --- concepts/lists/.meta/config.json | 6 ++ concepts/lists/about.md | 62 +++++++++++++ concepts/lists/introduction.md | 35 ++++++++ concepts/lists/links.json | 14 +++ config.json | 5 ++ .../concept/language-list/.docs/hints.md | 43 +++++++++ .../language-list/.docs/instructions.md | 87 +++++++++++++++++++ .../language-list/.docs/introduction.md | 35 ++++++++ .../concept/language-list/.meta/config.json | 22 +++++ .../concept/language-list/.meta/design.md | 31 +++++++ .../.meta/examples/languageList.examples.u | 0 .../language-list/.meta/testAnnotation.json | 0 .../concept/language-list/.meta/testLoader.u | 0 .../concept/language-list/languageList.test.u | 0 .../concept/language-list/languageList.u | 0 15 files changed, 340 insertions(+) create mode 100644 concepts/lists/.meta/config.json create mode 100644 concepts/lists/about.md create mode 100644 concepts/lists/introduction.md create mode 100644 concepts/lists/links.json create mode 100644 exercises/concept/language-list/.docs/hints.md create mode 100644 exercises/concept/language-list/.docs/instructions.md create mode 100644 exercises/concept/language-list/.docs/introduction.md create mode 100644 exercises/concept/language-list/.meta/config.json create mode 100644 exercises/concept/language-list/.meta/design.md create mode 100644 exercises/concept/language-list/.meta/examples/languageList.examples.u create mode 100644 exercises/concept/language-list/.meta/testAnnotation.json create mode 100644 exercises/concept/language-list/.meta/testLoader.u create mode 100644 exercises/concept/language-list/languageList.test.u create mode 100644 exercises/concept/language-list/languageList.u diff --git a/concepts/lists/.meta/config.json b/concepts/lists/.meta/config.json new file mode 100644 index 0000000..67ca30a --- /dev/null +++ b/concepts/lists/.meta/config.json @@ -0,0 +1,6 @@ +{ + "authors": [ + "rlmark" + ], + "blurb": "Using the List collection type in Unison" +} diff --git a/concepts/lists/about.md b/concepts/lists/about.md new file mode 100644 index 0000000..eb9b8a4 --- /dev/null +++ b/concepts/lists/about.md @@ -0,0 +1,62 @@ +# Unison Lists + +Lists are used in the Unison programming language to represent a finite, ordered collection of elements. They're written with comma-separated elements in square braces: + +``` +emptyList = [] + +listNats : [Nat] +listNats = [1,2,3,4] + +listText : [Text] +listText = ["hello", "world"] +``` + +Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+`: + +``` +myList = [1,2,3,4] + +> 0 +: myList :+ 5 + ⧩ + [0, 1, 2, 3, 4, 5] +``` + +Concatenating lists is supported with the `++` operator: + +``` +> [1,2] ++ [3,4,5] + ⧩ + [1, 2, 3, 4, 5] +``` + +The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. + +[list-docs]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List + + +## List pattern matching + +It's common to pattern match on the head and tail elements of a list with the `+:` syntax: + +``` +match ["a", " b", "c"] with + head +: tail -> head + otherwise -> "otherwise" +``` + +But in Unison you can also pattern match on the last element of a list, just reverse the operator: + +``` +match ["a", " b", "c"] with + prefix :+ last -> last + otherwise -> "otherwise" +``` + +Multi list element matching is supported by surrounding the desired elements in square brackets, followed by the concatenation operator, `++`. This expression will match any list with a length of two or more elements: + +``` +match ["a", " b", "c"] with + [first, second] ++ remainder -> first + otherwise -> "otherwise" +``` diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md new file mode 100644 index 0000000..223a41c --- /dev/null +++ b/concepts/lists/introduction.md @@ -0,0 +1,35 @@ +# Unison Lists + +Lists are used in the Unison programming language to represent a finite, ordered collection of elements. They're written with comma-separated elements in square braces: + +``` +emptyList = [] + +listNats : [Nat] +listNats = [1,2,3,4] + +listText : [Text] +listText = ["hello", "world"] +``` + +Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+`: + +``` +myList = [1,2,3,4] + +> 0 +: myList :+ 5 + ⧩ + [0, 1, 2, 3, 4, 5] +``` + +Concatenating lists is supported with the `++` operator: + +``` +> [1,2] ++ [3,4,5] + ⧩ + [1, 2, 3, 4, 5] +``` + +The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. + +[list-docs]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List diff --git a/concepts/lists/links.json b/concepts/lists/links.json new file mode 100644 index 0000000..71e1631 --- /dev/null +++ b/concepts/lists/links.json @@ -0,0 +1,14 @@ +[ + { + "url": "https://www.unison-lang.org/learn/fundamentals/values-and-functions/common-collection-types/#lists", + "description": "Lists and other common collection types in Unison" + }, + { + "url": "https://www.unison-lang.org/learn/fundamentals/control-flow/pattern-matching2/#pattern-matching-on", + "description": "List pattern matching" + }, + { + "url": "https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List", + "description": "List documentation from the standard library" + } +] diff --git a/config.json b/config.json index c78a771..0b753f7 100644 --- a/config.json +++ b/config.json @@ -250,6 +250,11 @@ "uuid": "24332ec2-07b2-49e5-aa58-4829d31dc44a", "slug": "basics", "name": "Basics" + }, + { + "uuid": "44f2d0c1-73db-487a-a2d2-aea4fa7be73f", + "slug": "lists", + "name": "Lists" } ], "key_features": [ diff --git a/exercises/concept/language-list/.docs/hints.md b/exercises/concept/language-list/.docs/hints.md new file mode 100644 index 0000000..fc2cb4b --- /dev/null +++ b/exercises/concept/language-list/.docs/hints.md @@ -0,0 +1,43 @@ +# Hints + +## General + +- Use the built-in [list type][list]. + +## 1. Define a function to return an empty language list + +- You need to define a [named function][named-function] with 0 arguments. + +## 2. Define a function to add a language to the list + +- You need to define a function with 2 arguments. The first argument is a [list][list] of language [text literals][string]. The second argument is a [text literal value][string]. +- You can use list literal notation forms. + +## 3. Define a function to remove a language from the list + +- You need to define a function with 1 argument. The first argument is a [list][list] of language [text-literals][string]. +- Check out Unison's syntax for [pattern matching on list elements][list-patterns] + +## 4. Define a function to return the first item in the list + +- You need to define a function with 1 argument. The first argument is a [list][list] of language [string-literals][string]. +- You can use the `Optional` data type to represent if there is no value to return. + +## 5. Define a function to return how many languages are in the list + +- You need to define a function with 1 argument. The first argument is a [list][list] of language [string-literals][string]. +- Unison [provides a function][size] to count the length of a list. + +## 6. Define a function to determine if the list includes a functional language + +- You need to define a function with 1 argument. The first argument is a [list][list] of language [string-literals][string]. +- Your function should return a boolean value indicating whether `"Unison"` is a member of the list. + +## 7. Define a function to create a string from the list + +- You need to define a function with two arguments. The first argument is a [list][list] of language [string-literals][string] and the second is a `Text` value to be used as a separator. + +[list]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List +[string]: https://www.unison-lang.org/learn/language-reference/literals/ +[list-patterns]: https://www.unison-lang.org/learn/fundamentals/control-flow/pattern-matching2/#pattern-matching-on +[size]: https://share.unison-lang.org/latest/namespaces/unison/base/;/terms/List/size diff --git a/exercises/concept/language-list/.docs/instructions.md b/exercises/concept/language-list/.docs/instructions.md new file mode 100644 index 0000000..1762882 --- /dev/null +++ b/exercises/concept/language-list/.docs/instructions.md @@ -0,0 +1,87 @@ +# Instructions + +In this exercise you need to implement some functions to manipulate a list of programming languages. Some of the functions may exist for `List`, but for this exercise try not to use them. + +## 1. Define a function to return an empty language list + +Define the `new` function that takes no arguments and returns an empty list. + +``` +languageList.new : [Text] +languageList.new = todo "return empty list" +``` + +## 2. Define a function to add a language to the list + +Define the `add` function that takes 2 arguments (a list of languages and a string literal of a language). It should return the resulting list with the new language prepended to the given list. + +``` +> languageList.new + |> languageList.add "Clojure" + |> languageList.add "Unison" + ⧩ + ["Unison", "Clojure"] +``` + +## 3. Define a function to remove a language from the list + +Define the `remove` function that takes 1 argument (a list of languages). It should return the list without the first item. Calling `remove` on an empty list should return an empty list. + +``` +> languageList.new + |> languageList.add "Clojure" + |> languageList.add "Unison" + |> languageList.remove + ⧩ + ["Clojure"] +``` + +## 4. Define a function to return the first item in the list + +Define the `first` function that takes 1 argument (a list of languages). It should return the first language in the list. + +``` +> languageList.new + |> languageList.add "Elm" + |> languageList.add "Prolog" + |> languageList.first + ⧩ + Some "Prolog" +``` + +## 5. Define a function to return how many languages are in the list + +Define the `count` function that takes 1 argument (a list of languages). It should return the number of languages in the list. + +``` +> languageList.new + |> languageList.add "Elm" + |> languageList.add "Prolog" + |> languageList.count + ⧩ + 2 +``` + +## 6. Define a function to determine if the list includes Unison + +Define the `containsUnison` function which takes 1 argument (a list of languages). It should return a boolean value. It should return true if _"Unison"_ is one of the languages in the list. + +```elixir +> languageList.new + |> languageList.add "Unison" + |> languageList.includesUnison + ⧩ + true +``` + +## 7. Define a function to create a string from the list + + +``` +> languageList.new + |> languageList.add "Clojure" + |> languageList.add "Unison" + |> languageList.join ", " + ⧩ + "Unison, Clojure" +``` diff --git a/exercises/concept/language-list/.docs/introduction.md b/exercises/concept/language-list/.docs/introduction.md new file mode 100644 index 0000000..223a41c --- /dev/null +++ b/exercises/concept/language-list/.docs/introduction.md @@ -0,0 +1,35 @@ +# Unison Lists + +Lists are used in the Unison programming language to represent a finite, ordered collection of elements. They're written with comma-separated elements in square braces: + +``` +emptyList = [] + +listNats : [Nat] +listNats = [1,2,3,4] + +listText : [Text] +listText = ["hello", "world"] +``` + +Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+`: + +``` +myList = [1,2,3,4] + +> 0 +: myList :+ 5 + ⧩ + [0, 1, 2, 3, 4, 5] +``` + +Concatenating lists is supported with the `++` operator: + +``` +> [1,2] ++ [3,4,5] + ⧩ + [1, 2, 3, 4, 5] +``` + +The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. + +[list-docs]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List diff --git a/exercises/concept/language-list/.meta/config.json b/exercises/concept/language-list/.meta/config.json new file mode 100644 index 0000000..4dd409b --- /dev/null +++ b/exercises/concept/language-list/.meta/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "rlmark" + ], + "contributors": [ + ], + "files": { + "solution": [ + "language-list.u" + ], + "test": [ + "language-list.test.u" + ], + "exemplar": [ + ".meta/examples/language-list.example.u" + ] + }, + "forked_from": [ + "elixir/language-list" + ], + "blurb": "Learn about lists by keeping track of the programing languages you're currently learning on Exercism." +} diff --git a/exercises/concept/language-list/.meta/design.md b/exercises/concept/language-list/.meta/design.md new file mode 100644 index 0000000..53dc1cf --- /dev/null +++ b/exercises/concept/language-list/.meta/design.md @@ -0,0 +1,31 @@ +# Design + +## Learning objectives + +- Know of the existence of the `List` type. +- Know how list can be constructed with `[]` and `head +: tail` syntax +- Use basic functions and macros related to Lists. + - `head` + - `tail` + - `size` + +## Out of scope + +- `String` functions and string manipulation +- Folding over lists +- Memory and performance characteristics. + +## Concepts + +- `lists` + - know of the existence of the `List` type + - know of the idea of `List` design + - know some basic patterns / functions + +## Resources + +- Standard library List documentation: [Lists][base-list] +- List pattern matching: [Lists][pattern-matching-lists] + +[base-list]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List +[pattern-matching-lists]: https://www.unison-lang.org/learn/fundamentals/control-flow/pattern-matching2/#pattern-matching-on diff --git a/exercises/concept/language-list/.meta/examples/languageList.examples.u b/exercises/concept/language-list/.meta/examples/languageList.examples.u new file mode 100644 index 0000000..e69de29 diff --git a/exercises/concept/language-list/.meta/testAnnotation.json b/exercises/concept/language-list/.meta/testAnnotation.json new file mode 100644 index 0000000..e69de29 diff --git a/exercises/concept/language-list/.meta/testLoader.u b/exercises/concept/language-list/.meta/testLoader.u new file mode 100644 index 0000000..e69de29 diff --git a/exercises/concept/language-list/languageList.test.u b/exercises/concept/language-list/languageList.test.u new file mode 100644 index 0000000..e69de29 diff --git a/exercises/concept/language-list/languageList.u b/exercises/concept/language-list/languageList.u new file mode 100644 index 0000000..e69de29 From f38e7c2cb7963d9376a5755aad1e0936d31d59c3 Mon Sep 17 00:00:00 2001 From: Rebecca Mark Date: Tue, 16 Aug 2022 10:11:39 -0700 Subject: [PATCH 2/5] wip list instructions and docs --- concepts/lists/introduction.md | 29 ++++++++++++++++++- .../concept/language-list/.docs/hints.md | 21 +++++++------- .../language-list/.docs/instructions.md | 3 +- .../language-list/.docs/introduction.md | 28 +++++++++++++++++- .../concept/language-list/.meta/design.md | 2 +- 5 files changed, 68 insertions(+), 15 deletions(-) diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md index 223a41c..e8ec378 100644 --- a/concepts/lists/introduction.md +++ b/concepts/lists/introduction.md @@ -32,4 +32,31 @@ Concatenating lists is supported with the `++` operator: The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. -[list-docs]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List +## List pattern matching + +It's common to pattern match on the head and tail elements of a list with the `+:` syntax: + +``` +match ["a", " b", "c"] with + head +: tail -> head + otherwise -> "otherwise" +``` + +But in Unison you can also pattern match on the last element of a list, just reverse the operator: + +``` +match ["a", " b", "c"] with + prefix :+ last -> last + otherwise -> "otherwise" +``` + +Multi list element matching is supported by surrounding the desired elements in square brackets, followed by the concatenation operator, `++`. This expression will match any list with a length of two or more elements: + +``` +match ["a", " b", "c"] with + [first, second] ++ remainder -> first + otherwise -> "otherwise" +``` + + +[list-docs]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List diff --git a/exercises/concept/language-list/.docs/hints.md b/exercises/concept/language-list/.docs/hints.md index fc2cb4b..e61a87c 100644 --- a/exercises/concept/language-list/.docs/hints.md +++ b/exercises/concept/language-list/.docs/hints.md @@ -6,38 +6,39 @@ ## 1. Define a function to return an empty language list -- You need to define a [named function][named-function] with 0 arguments. +- You need to define a [Unison function function][named-function] with 0 arguments. ## 2. Define a function to add a language to the list - You need to define a function with 2 arguments. The first argument is a [list][list] of language [text literals][string]. The second argument is a [text literal value][string]. -- You can use list literal notation forms. +- You can use list literal notation form. ## 3. Define a function to remove a language from the list -- You need to define a function with 1 argument. The first argument is a [list][list] of language [text-literals][string]. +- You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. - Check out Unison's syntax for [pattern matching on list elements][list-patterns] ## 4. Define a function to return the first item in the list -- You need to define a function with 1 argument. The first argument is a [list][list] of language [string-literals][string]. -- You can use the `Optional` data type to represent if there is no value to return. +- You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. +- You can use the [`Optional` data type][optional] to represent if there is no value to return. ## 5. Define a function to return how many languages are in the list -- You need to define a function with 1 argument. The first argument is a [list][list] of language [string-literals][string]. +- You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. - Unison [provides a function][size] to count the length of a list. ## 6. Define a function to determine if the list includes a functional language -- You need to define a function with 1 argument. The first argument is a [list][list] of language [string-literals][string]. +- You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. - Your function should return a boolean value indicating whether `"Unison"` is a member of the list. ## 7. Define a function to create a string from the list -- You need to define a function with two arguments. The first argument is a [list][list] of language [string-literals][string] and the second is a `Text` value to be used as a separator. +- You need to define a function with two arguments. The first argument is a [list][list] of language [text literals][string] and the second is a `Text` value to be used as a separator. -[list]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List +[list]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List [string]: https://www.unison-lang.org/learn/language-reference/literals/ [list-patterns]: https://www.unison-lang.org/learn/fundamentals/control-flow/pattern-matching2/#pattern-matching-on -[size]: https://share.unison-lang.org/latest/namespaces/unison/base/;/terms/List/size +[size]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/terms/data/List/size +[optional]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/Optional \ No newline at end of file diff --git a/exercises/concept/language-list/.docs/instructions.md b/exercises/concept/language-list/.docs/instructions.md index 1762882..93654b3 100644 --- a/exercises/concept/language-list/.docs/instructions.md +++ b/exercises/concept/language-list/.docs/instructions.md @@ -74,8 +74,7 @@ Define the `containsUnison` function which takes 1 argument (a list of languages true ``` -## 7. Define a function to create a string from the list - +## 7. Define a function to determine if a given list is a sub-list ``` > languageList.new diff --git a/exercises/concept/language-list/.docs/introduction.md b/exercises/concept/language-list/.docs/introduction.md index 223a41c..252cefe 100644 --- a/exercises/concept/language-list/.docs/introduction.md +++ b/exercises/concept/language-list/.docs/introduction.md @@ -32,4 +32,30 @@ Concatenating lists is supported with the `++` operator: The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. -[list-docs]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List +## List pattern matching + +It's common to pattern match on the head and tail elements of a list with the `+:` syntax: + +``` +match ["a", " b", "c"] with + head +: tail -> head + otherwise -> "otherwise" +``` + +But in Unison you can also pattern match on the last element of a list, just reverse the operator: + +``` +match ["a", " b", "c"] with + prefix :+ last -> last + otherwise -> "otherwise" +``` + +Multi list element matching is supported by surrounding the desired elements in square brackets, followed by the concatenation operator, `++`. This expression will match any list with a length of two or more elements: + +``` +match ["a", " b", "c"] with + [first, second] ++ remainder -> first + otherwise -> "otherwise" +``` + +[list-docs]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List diff --git a/exercises/concept/language-list/.meta/design.md b/exercises/concept/language-list/.meta/design.md index 53dc1cf..c6d7764 100644 --- a/exercises/concept/language-list/.meta/design.md +++ b/exercises/concept/language-list/.meta/design.md @@ -27,5 +27,5 @@ - Standard library List documentation: [Lists][base-list] - List pattern matching: [Lists][pattern-matching-lists] -[base-list]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List +[base-list]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List [pattern-matching-lists]: https://www.unison-lang.org/learn/fundamentals/control-flow/pattern-matching2/#pattern-matching-on From b0a25a70a07efee23af7ca716d3b5907757bd67a Mon Sep 17 00:00:00 2001 From: Rebecca Mark Date: Thu, 25 Aug 2022 23:43:46 -0700 Subject: [PATCH 3/5] adding list concept exercise --- concepts/lists/about.md | 9 ++- concepts/lists/introduction.md | 5 +- config.json | 10 ++++ .../concept/language-list/.docs/hints.md | 33 +++++----- .../language-list/.docs/instructions.md | 60 +++++++++---------- .../language-list/.docs/introduction.md | 4 +- .../concept/language-list/.meta/config.json | 8 +-- .../concept/language-list/.meta/design.md | 13 ++-- .../.meta/examples/languageList.example.u | 26 ++++++++ .../.meta/examples/languageList.examples.u | 0 .../language-list/.meta/testAnnotation.json | 50 ++++++++++++++++ .../concept/language-list/.meta/testLoader.md | 9 +++ .../concept/language-list/.meta/testLoader.u | 0 .../concept/language-list/languageList.test.u | 50 ++++++++++++++++ .../concept/language-list/languageList.u | 17 ++++++ 15 files changed, 224 insertions(+), 70 deletions(-) create mode 100644 exercises/concept/language-list/.meta/examples/languageList.example.u delete mode 100644 exercises/concept/language-list/.meta/examples/languageList.examples.u create mode 100644 exercises/concept/language-list/.meta/testLoader.md delete mode 100644 exercises/concept/language-list/.meta/testLoader.u diff --git a/concepts/lists/about.md b/concepts/lists/about.md index eb9b8a4..ecc9dc1 100644 --- a/concepts/lists/about.md +++ b/concepts/lists/about.md @@ -12,7 +12,7 @@ listText : [Text] listText = ["hello", "world"] ``` -Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+`: +Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+` operators: ``` myList = [1,2,3,4] @@ -30,10 +30,7 @@ Concatenating lists is supported with the `++` operator: [1, 2, 3, 4, 5] ``` -The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. - -[list-docs]: https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List - +The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find.all` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. ## List pattern matching @@ -60,3 +57,5 @@ match ["a", " b", "c"] with [first, second] ++ remainder -> first otherwise -> "otherwise" ``` + +[list-docs]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md index e8ec378..ecc9dc1 100644 --- a/concepts/lists/introduction.md +++ b/concepts/lists/introduction.md @@ -12,7 +12,7 @@ listText : [Text] listText = ["hello", "world"] ``` -Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+`: +Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+` operators: ``` myList = [1,2,3,4] @@ -30,7 +30,7 @@ Concatenating lists is supported with the `++` operator: [1, 2, 3, 4, 5] ``` -The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. +The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find.all` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. ## List pattern matching @@ -58,5 +58,4 @@ match ["a", " b", "c"] with otherwise -> "otherwise" ``` - [list-docs]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List diff --git a/config.json b/config.json index 5759f31..adef4ac 100644 --- a/config.json +++ b/config.json @@ -40,6 +40,16 @@ "concepts": ["basics"], "difficulty": 1, "status": "wip" + }, + { + "slug": "language-list", + "name": "Language List", + "uuid": "5ebdb25b-39a0-4cd8-9f73-04ec565ef15f", + "practices": [], + "prerequisites": [], + "concepts": ["lists"], + "difficulty": 2, + "status": "wip" } ], "practice": [ diff --git a/exercises/concept/language-list/.docs/hints.md b/exercises/concept/language-list/.docs/hints.md index e61a87c..3cf4356 100644 --- a/exercises/concept/language-list/.docs/hints.md +++ b/exercises/concept/language-list/.docs/hints.md @@ -3,6 +3,7 @@ ## General - Use the built-in [list type][list]. +- In functional programming it's common to iterate through, inspect, or manipulate lists by [recursively pattern matching][functional-looping] on their elements until reaching the end of the list. In fact, many of the common functions defined for the list data type are based on these principles. ## 1. Define a function to return an empty language list @@ -10,35 +11,31 @@ ## 2. Define a function to add a language to the list -- You need to define a function with 2 arguments. The first argument is a [list][list] of language [text literals][string]. The second argument is a [text literal value][string]. -- You can use list literal notation form. +- You need to define a function with 2 arguments. The first argument is a [text literal value][string]. The second argument is a [list][list] of language [text literals][string]. +- The list data type has a number of operators for manipulating lists, the "cons" (aka prepend) operator looks like `+:`. -## 3. Define a function to remove a language from the list +## 3. Define a function to remove the left-most language from the list - You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. -- Check out Unison's syntax for [pattern matching on list elements][list-patterns] +- Check out Unison's syntax for [pattern matching on list elements][list-patterns]. Pattern matching allows you to decompose the list into its constituent parts. -## 4. Define a function to return the first item in the list +## 4. Define a function to return how many elements are in the list -- You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. -- You can use the [`Optional` data type][optional] to represent if there is no value to return. - -## 5. Define a function to return how many languages are in the list +- You need to define a function which takes in a [list][list] of language [text literals][string] and returns the size as a `Nat`. +- It's common to keep a running count of the number of elements seen using [recursion][functional-looping]. -- You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. -- Unison [provides a function][size] to count the length of a list. +## 5. Define a function to determine if the list includes a given language -## 6. Define a function to determine if the list includes a functional language - -- You need to define a function with 1 argument. The first argument is a [list][list] of language [text literals][string]. -- Your function should return a boolean value indicating whether `"Unison"` is a member of the list. +- You need to define a function with 2 arguments. The first is a [text][string] value and the second argument is a [list][list] of language [text literals][string]. -## 7. Define a function to create a string from the list +## 6. Define a function to reverse a given list -- You need to define a function with two arguments. The first argument is a [list][list] of language [text literals][string] and the second is a `Text` value to be used as a separator. +- You need to define a function with 1 argument: the `List` of `Text` values. +- What happens if you call `List.foldLeft` on your list, passing in the `+:` operator as the first argument? What happens if you call `List.foldRight` with the `+:` argument? [list]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List [string]: https://www.unison-lang.org/learn/language-reference/literals/ [list-patterns]: https://www.unison-lang.org/learn/fundamentals/control-flow/pattern-matching2/#pattern-matching-on [size]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/terms/data/List/size -[optional]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/Optional \ No newline at end of file +[optional]: https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/Optional +[functional-looping]: https://www.unison-lang.org/learn/fundamentals/control-flow/looping/#functional-looping \ No newline at end of file diff --git a/exercises/concept/language-list/.docs/instructions.md b/exercises/concept/language-list/.docs/instructions.md index 93654b3..809f5da 100644 --- a/exercises/concept/language-list/.docs/instructions.md +++ b/exercises/concept/language-list/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -In this exercise you need to implement some functions to manipulate a list of programming languages. Some of the functions may exist for `List`, but for this exercise try not to use them. +In this exercise you need to implement some functions to manipulate a list of programming languages. Some of the functions you'll be asked to define may exist for `List`, which is good to know for future reference, but for this exercise try not to use them! ## 1. Define a function to return an empty language list @@ -13,7 +13,7 @@ languageList.new = todo "return empty list" ## 2. Define a function to add a language to the list -Define the `add` function that takes 2 arguments (a list of languages and a string literal of a language). It should return the resulting list with the new language prepended to the given list. +Define the `add` function that takes 2 arguments (a list of languages and a string literal of a language). It should return the resulting list with the new language added to the front of the given list. ``` > languageList.new @@ -23,64 +23,62 @@ Define the `add` function that takes 2 arguments (a list of languages and a stri ["Unison", "Clojure"] ``` -## 3. Define a function to remove a language from the list +## 3. Define a function to remove the left-most language from the list -Define the `remove` function that takes 1 argument (a list of languages). It should return the list without the first item. Calling `remove` on an empty list should return an empty list. +Define the `drop1` function that takes 1 argument (a list of languages). It should return the list without the first item. Calling `drop1` on an empty list should return an empty list. ``` > languageList.new |> languageList.add "Clojure" |> languageList.add "Unison" - |> languageList.remove + |> languageList.drop1 ⧩ ["Clojure"] ``` -## 4. Define a function to return the first item in the list +## 4. Define a function to return how many elements are in the list -Define the `first` function that takes 1 argument (a list of languages). It should return the first language in the list. +Define the `size` function that takes 1 argument (a list of languages). It should return the number of languages in the list. ``` > languageList.new |> languageList.add "Elm" |> languageList.add "Prolog" - |> languageList.first - ⧩ - Some "Prolog" -``` - -## 5. Define a function to return how many languages are in the list - -Define the `count` function that takes 1 argument (a list of languages). It should return the number of languages in the list. - -``` -> languageList.new - |> languageList.add "Elm" - |> languageList.add "Prolog" - |> languageList.count + |> languageList.size ⧩ 2 ``` -## 6. Define a function to determine if the list includes Unison +## 5. Define a function to determine if the list includes a given language -Define the `containsUnison` function which takes 1 argument (a list of languages). It should return a boolean value. It should return true if _"Unison"_ is one of the languages in the list. +Define the `contains` function which takes 1 argument (a list of languages). It should return a boolean value. It should return true if the desired language is one of the languages in the list. -```elixir +``` > languageList.new |> languageList.add "Unison" - |> languageList.includesUnison + |> languageList.add "Clojure" + |> languageList.contains "Unison" ⧩ true ``` -## 7. Define a function to determine if a given list is a sub-list +## 6. Define a function to reverse a given list + +Define the `reverse` which takes in a list and returns the list with the elements in reverse order. ``` -> languageList.new - |> languageList.add "Clojure" - |> languageList.add "Unison" - |> languageList.join ", " +list1 = + languageList.new + |> languageList.add "Clojure" + |> languageList.add "Scala" + |> languageList.add "Unison" + |> languageList.add "Elm" + +> list1 + ⧩ + ["Elm", "Unison", "Scala", "Clojure"] + +> languageList.reverse list1 ⧩ - "Unison, Clojure" + ["Clojure", "Scala", "Unison", "Elm"] ``` diff --git a/exercises/concept/language-list/.docs/introduction.md b/exercises/concept/language-list/.docs/introduction.md index 252cefe..ecc9dc1 100644 --- a/exercises/concept/language-list/.docs/introduction.md +++ b/exercises/concept/language-list/.docs/introduction.md @@ -12,7 +12,7 @@ listText : [Text] listText = ["hello", "world"] ``` -Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+`: +Unison implements lists as a finger tree, allowing for fast access of the first and last element. You can read more about the underlying implementation in the [standard library List documentation][list-docs]. Appending single elements to either side of the list can be done with the `+:` and `:+` operators: ``` myList = [1,2,3,4] @@ -30,7 +30,7 @@ Concatenating lists is supported with the `++` operator: [1, 2, 3, 4, 5] ``` -The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. +The standard library, `base` contains a variety of functions available for `List` transformations. Check them out by using the `find.all` command in the UCM or by exploring the `List` namespace in [Unison share][list-docs]. ## List pattern matching diff --git a/exercises/concept/language-list/.meta/config.json b/exercises/concept/language-list/.meta/config.json index 4dd409b..006ac47 100644 --- a/exercises/concept/language-list/.meta/config.json +++ b/exercises/concept/language-list/.meta/config.json @@ -2,17 +2,15 @@ "authors": [ "rlmark" ], - "contributors": [ - ], "files": { "solution": [ - "language-list.u" + "languageList.u" ], "test": [ - "language-list.test.u" + "languageList.test.u" ], "exemplar": [ - ".meta/examples/language-list.example.u" + ".meta/examples/languageList.example.u" ] }, "forked_from": [ diff --git a/exercises/concept/language-list/.meta/design.md b/exercises/concept/language-list/.meta/design.md index c6d7764..59bb165 100644 --- a/exercises/concept/language-list/.meta/design.md +++ b/exercises/concept/language-list/.meta/design.md @@ -4,16 +4,17 @@ - Know of the existence of the `List` type. - Know how list can be constructed with `[]` and `head +: tail` syntax -- Use basic functions and macros related to Lists. - - `head` - - `tail` - - `size` +- Use basic functions related to Lists. +- Parts 1,2,3 (empty, add, drop1) teach basic list primitives like, `[]`, `+:`, and `drop`, or associated pattern matching conventions. +- Part 4 (size) teaches folding over the list, or tracking state via recursion and pattern matching +- Part 5 (contains) teaches the contains function or folding over the list +- Part 6 (reverse) teaches foldRight or `+:` in the context of pattern matching ## Out of scope -- `String` functions and string manipulation -- Folding over lists +- `Text` functions and string manipulation - Memory and performance characteristics. +- Polymorphism ## Concepts diff --git a/exercises/concept/language-list/.meta/examples/languageList.example.u b/exercises/concept/language-list/.meta/examples/languageList.example.u new file mode 100644 index 0000000..98dc1d7 --- /dev/null +++ b/exercises/concept/language-list/.meta/examples/languageList.example.u @@ -0,0 +1,26 @@ +languageList.new : [Text] +languageList.new = [] + +languageList.add : Text -> [Text] -> [Text] +languageList.add input list = input +: list + +languageList.drop1 : [Text] -> [Text] +languageList.drop1 = cases + head +: tail -> tail + [] -> [] + +languageList.size : [Text] -> Nat +languageList.size list = + go acc = cases + [] -> acc + h :+ t -> go (Nat.increment acc) t + go 0 list + +languageList.contains : Text -> [Text] -> Boolean +languageList.contains input = cases + [] -> false + h +: t | h === input -> true + h +: t -> contains input t + +languageList.reverse : [Text] -> [Text] +languageList.reverse list = List.foldLeft (b a -> a List.+: b ) [] list \ No newline at end of file diff --git a/exercises/concept/language-list/.meta/examples/languageList.examples.u b/exercises/concept/language-list/.meta/examples/languageList.examples.u deleted file mode 100644 index e69de29..0000000 diff --git a/exercises/concept/language-list/.meta/testAnnotation.json b/exercises/concept/language-list/.meta/testAnnotation.json index e69de29..0d9d2fc 100644 --- a/exercises/concept/language-list/.meta/testAnnotation.json +++ b/exercises/concept/language-list/.meta/testAnnotation.json @@ -0,0 +1,50 @@ +[ + { + "name": "languageList.test.ex1", + "test_code": "languageList.test.ex1 =\n\tTest.label \"languageList.new should return empty list\" <| Test.expect (languageList.new === [])" + }, + { + "name": "languageList.test.ex2", + "test_code": "languageList.test.ex2 =\n\tTest.label \"languageList.add should prepend an element\" <| Test.expect (languageList.add [\"Elm\"] === [\"Unison\", \"Elm\"])" + }, + { + "name": "languageList.test.ex3", + "test_code": "languageList.test.ex3 =\n\tTest.label \"languageList.drop1 should drop first element\" <| Test.expect (languageList.drop1 [\"Elm\", \"Cobol\", \"Haskell\"] === [ \"Cobol\", \"Haskell\"])" + }, + { + "name": "languageList.test.ex4", + "test_code": "languageList.test.ex4 =\n\tTest.label \"languageList.drop1 should return empty list\" <| Test.expect (languageList.drop1 [] === [])" + }, + { + "name": "languageList.test.ex5", + "test_code": "languageList.test.ex5 =\n\tTest.label \"languageList.size should return size of list\" <| Test.expect (languageList.size [\"Elm\", \"Cobol\", \"Haskell\"] === 3)" + }, + { + "name": "languageList.test.ex6", + "test_code": "languageList.test.ex6 =\n\tTest.label \"languageList.size should handle empty list\" <| Test.expect (languageList.size [] === 0)" + }, + { + "name": "languageList.test.ex7", + "test_code": "languageList.test.ex7 =\n\tTest.label \"languageList.contains should return true if list contains element\" <| Test.expect (languageList.contains \"Unison\" [\"Scala\", \"Python\", \"Unison\"] === true)" + }, + { + "name": "languageList.test.ex8", + "test_code": "languageList.test.ex8 =\n\tTest.label \"languageList.contains should return false if list does not contain element\" <| Test.expect (languageList.contains \"Unison\" [\"Scala\", \"Python\", \"Ruby\"] === false)" + }, + { + "name": "languageList.test.ex9", + "test_code": "languageList.test.ex9 =\n\tTest.label \"languageList.contains should handle empty list\" <| Test.expect (languageList.contains \"Unison\" [] === false)" + }, + { + "name": "languageList.test.ex10", + "test_code": "languageList.test.ex10 =\n\tTest.label \"languageList.reverse should reverse list\" <| Test.expect (languageList.reverse [\"Elm\", \"Unison\", \"Scala\", \"Clojure\"] === [\"Clojure\", \"Scala\", \"Unison\", \"Elm\"])" + }, + { + "name": "languageList.test.ex11", + "test_code": "languageList.test.ex11 =\n\tTest.label \"languageList.reverse should handle list of one\" <| Test.expect (languageList.reverse [\"Unison\"] === [\"Unison\"])" + }, + { + "name": "languageList.test.ex12", + "test_code": "languageList.test.ex12 =\n\tTest.label \"languageList.reverse should handle list of one\" <| Test.expect (languageList.reverse [] === [])" + } +] \ No newline at end of file diff --git a/exercises/concept/language-list/.meta/testLoader.md b/exercises/concept/language-list/.meta/testLoader.md new file mode 100644 index 0000000..836e7fb --- /dev/null +++ b/exercises/concept/language-list/.meta/testLoader.md @@ -0,0 +1,9 @@ +# Testing transcript + +```ucm +.> load ./languageList.u +.> add +.> load ./languageList.test.u +.> add +.> move.term languageList.tests tests +``` diff --git a/exercises/concept/language-list/.meta/testLoader.u b/exercises/concept/language-list/.meta/testLoader.u deleted file mode 100644 index e69de29..0000000 diff --git a/exercises/concept/language-list/languageList.test.u b/exercises/concept/language-list/languageList.test.u index e69de29..1492c6d 100644 --- a/exercises/concept/language-list/languageList.test.u +++ b/exercises/concept/language-list/languageList.test.u @@ -0,0 +1,50 @@ +languageList.test.ex1 = + Test.label "languageList.new should return empty list" <| Test.expect (languageList.new === []) + +languageList.test.ex2 = + Test.label "languageList.add should prepend an element" <| Test.expect (languageList.add "Unison" ["Elm"] === ["Unison", "Elm"]) + +languageList.test.ex3 = + Test.label "languageList.drop1 should drop first element" <| Test.expect (languageList.drop1 ["Elm", "Cobol", "Haskell"] === [ "Cobol", "Haskell"]) + +languageList.test.ex4 = + Test.label "languageList.drop1 should return empty list" <| Test.expect (languageList.drop1 [] === []) + +languageList.test.ex5 = + Test.label "languageList.size should return size of list" <| Test.expect (languageList.size ["Elm", "Cobol", "Haskell"] === 3) + +languageList.test.ex6 = + Test.label "languageList.size should handle empty list" <| Test.expect (languageList.size [] === 0) + +languageList.test.ex7 = + Test.label "languageList.contains should return true if list contains element" <| Test.expect (languageList.contains "Unison" ["Scala", "Python", "Unison"] === true) + +languageList.test.ex8 = + Test.label "languageList.contains should return false if list does not contain element" <| Test.expect (languageList.contains "Unison" ["Scala", "Python", "Ruby"] === false) + +languageList.test.ex9 = + Test.label "languageList.contains should handle empty list" <| Test.expect (languageList.contains "Unison" [] === false) + +languageList.test.ex10 = + Test.label "languageList.reverse should reverse list" <| Test.expect (languageList.reverse ["Elm", "Unison", "Scala", "Clojure"] === ["Clojure", "Scala", "Unison", "Elm"]) + +languageList.test.ex11 = + Test.label "languageList.reverse should handle list of one" <| Test.expect (languageList.reverse ["Unison"] === ["Unison"]) + +languageList.test.ex12 = + Test.label "languageList.reverse should handle list of one" <| Test.expect (languageList.reverse [] === []) + +test> languageList.tests = runAll [ + languageList.test.ex1, + languageList.test.ex2, + languageList.test.ex3, + languageList.test.ex4, + languageList.test.ex5, + languageList.test.ex6, + languageList.test.ex7, + languageList.test.ex8, + languageList.test.ex9, + languageList.test.ex10, + languageList.test.ex11, + languageList.test.ex12 +] \ No newline at end of file diff --git a/exercises/concept/language-list/languageList.u b/exercises/concept/language-list/languageList.u index e69de29..24b115d 100644 --- a/exercises/concept/language-list/languageList.u +++ b/exercises/concept/language-list/languageList.u @@ -0,0 +1,17 @@ +languageList.new : [Text] +languageList.new = todo "return empty list" + +languageList.add : Text -> [Text] -> [Text] +languageList.add input list = todo "return a list with the input preprended" + +languageList.drop1 : [Text] -> [Text] +languageList.drop1 list = todo "return a list with the first element dropped" + +languageList.size : [Text] -> Nat +languageList.size list = todo "return the size of the list" + +languageList.contains : Text -> [Text] -> Boolean +languageList.contains input list = todo "return if the element is in the list" + +languageList.reverse : [Text] -> [Text] +languageList.reverse list = todo "return the reversed list" \ No newline at end of file From 8ca83125a250927f5e964715d9233c4ac6c36baf Mon Sep 17 00:00:00 2001 From: Rebecca Mark Date: Thu, 25 Aug 2022 23:47:44 -0700 Subject: [PATCH 4/5] updated links resource for list --- concepts/lists/links.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/concepts/lists/links.json b/concepts/lists/links.json index 71e1631..f85af3c 100644 --- a/concepts/lists/links.json +++ b/concepts/lists/links.json @@ -8,7 +8,11 @@ "description": "List pattern matching" }, { - "url": "https://share.unison-lang.org/latest/namespaces/unison/base/;/types/List", + "url": "https://share.unison-lang.org/@unison/code/latest/namespaces/public/base/latest/;/types/data/List", "description": "List documentation from the standard library" + }, + { + "url": "https://www.unison-lang.org/learn/fundamentals/control-flow/looping/", + "description": "Tips for using recursion using a List example" } ] From 52e218feb1deed12bf5ac524e3f717379ea68fe5 Mon Sep 17 00:00:00 2001 From: Rebecca Mark Date: Thu, 25 Aug 2022 23:56:13 -0700 Subject: [PATCH 5/5] added stubbed values instead of todos to make TDD easier --- exercises/concept/language-list/languageList.u | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/exercises/concept/language-list/languageList.u b/exercises/concept/language-list/languageList.u index 24b115d..f614ac5 100644 --- a/exercises/concept/language-list/languageList.u +++ b/exercises/concept/language-list/languageList.u @@ -1,17 +1,17 @@ languageList.new : [Text] -languageList.new = todo "return empty list" +languageList.new = ["return empty list"] languageList.add : Text -> [Text] -> [Text] -languageList.add input list = todo "return a list with the input preprended" +languageList.add input list = ["return a list with the input preprended"] languageList.drop1 : [Text] -> [Text] -languageList.drop1 list = todo "return a list with the first element dropped" +languageList.drop1 list = ["return a list with the first element dropped"] languageList.size : [Text] -> Nat -languageList.size list = todo "return the size of the list" +languageList.size list = 100000 languageList.contains : Text -> [Text] -> Boolean -languageList.contains input list = todo "return if the element is in the list" +languageList.contains input list = false languageList.reverse : [Text] -> [Text] -languageList.reverse list = todo "return the reversed list" \ No newline at end of file +languageList.reverse list = ["return the reversed list"] \ No newline at end of file