From 8f8817fa79eedef25866bbda9adec7f194552323 Mon Sep 17 00:00:00 2001 From: meatball Date: Mon, 30 Sep 2024 20:04:14 +0200 Subject: [PATCH 1/4] Add list concept --- concepts/lists/.meta/config.json | 6 ++ concepts/lists/about.md | 87 +++++++++++++++++++ concepts/lists/introduction.md | 87 +++++++++++++++++++ concepts/lists/links.json | 1 + .../concept/language-list/.docs/hints.md | 8 ++ .../language-list/.docs/instructions.md | 66 ++++++++++++++ .../language-list/.docs/introduction.md | 87 +++++++++++++++++++ .../.meta/STUB-ALLOWED-TO-NOT-COMPILE | 3 + .../concept/language-list/.meta/config.json | 25 ++++++ .../concept/language-list/.meta/design.md | 36 ++++++++ .../language-list/.meta/exemplar/package.yaml | 18 ++++ .../.meta/exemplar/src/LanguageList.hs | 19 ++++ exercises/concept/language-list/package.yaml | 18 ++++ .../concept/language-list/src/LanguageList.hs | 25 ++++++ exercises/concept/language-list/stack.yaml | 1 + exercises/concept/language-list/test/Tests.hs | 63 ++++++++++++++ 16 files changed, 550 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/STUB-ALLOWED-TO-NOT-COMPILE 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/exemplar/package.yaml create mode 100644 exercises/concept/language-list/.meta/exemplar/src/LanguageList.hs create mode 100644 exercises/concept/language-list/package.yaml create mode 100644 exercises/concept/language-list/src/LanguageList.hs create mode 100644 exercises/concept/language-list/stack.yaml create mode 100644 exercises/concept/language-list/test/Tests.hs diff --git a/concepts/lists/.meta/config.json b/concepts/lists/.meta/config.json new file mode 100644 index 000000000..e342fd8d7 --- /dev/null +++ b/concepts/lists/.meta/config.json @@ -0,0 +1,6 @@ +{ + "blurb": "Lists are a basic data type in Haskell for holding a collection of values. A list can hold values of different types. Lists are immutable, meaning they cannot be modified. Lists in Haskell are implemented as linked lists. Therefore, accessing an element in a list takes linear time depending on the length of the list.", + "authors": [ + "meatball133" + ] +} \ No newline at end of file diff --git a/concepts/lists/about.md b/concepts/lists/about.md new file mode 100644 index 000000000..bf76c86b8 --- /dev/null +++ b/concepts/lists/about.md @@ -0,0 +1,87 @@ +# About + +[Lists][list] are a basic data type in Haskell for holding a collection of values. +Lists are _immutable_, meaning they cannot be modified. +Any operation that changes a list returns a new list. +There are several methods in the prelude which allows you to work with Lists. + +Lists in Haskell are implemented as [linked lists][linked-list-wiki], and not as arrays of contiguous memory location. +Therefore, accessing an element in a list takes linear time depending on the length of the list. + +Lists can be written in literal form, head-tail notation, (which uses the `cons` operator `:`), or a combination of both: + +```haskell +-- Literal Form +[] +[1] +[1, 2, 3] + +-- Head-tail Notation +[] +-- same as [1] +1 : [] +-- same as [1, 2, 3] +1 : (2 : (3 : [])) + +-- Mixed +-- same as [1, 2, 3] +1 : [2, 3] +``` + +Head-tail notation can be used to append items to a list. + +```haskell +list = [2, 1] + +[3, 2, 1] == 3 : list +-- -> True +``` + +Appending elements to a list during iteration is considered an anti-pattern. +Appending an element requires walking through the entire list and adding the element at the end, therefore, appending a new element in each iteration would require walking through the entire list in each iteration. + +We can achieve the same result by prepending an element to the reversed list, and then reversing the result. Prepending is a fast operation and requires constant time. + +```haskell +-- Appending to the end of a list (potentially slow) +[1, 2, 3] ++ [4] ++ [5] ++ [6] + +-- Prepend to the start of a list (faster, due to the nature of linked lists) +6 : (5 : (4 : [3, 2, 1])) +-- then reverse! +``` + +There are several common Prelude functions for lists: + +- [`head`][head] returns the _head_ of a list -- the _first_ item in a list. +- [`tail`][tail] returns the _tail_ of the list -- the list _minus_ the _first_ item. +- [`length`][length] returns the number items in the list. +- [`elem`][in] returns a boolean value indicating whether the item is an element in the list. + +There is also the [`List` module][list]. + +Lists can only contain one data type. + +```haskell +list = [1, "string"] +-- Error: No instance for (Num String) arising from the literal ‘1’ +``` + +## Type annotation + +The type annotation of a list is `[a]` where a is the type which the lists holds, for example `String` or `Int`. + +``` haskell +a :: [Int] +a = [1, 2, 3] +``` + +[enum]: https://hexdocs.pm/elixir/Enum.html +[enum-protocol]: https://hexdocs.pm/elixir/Enumerable.html +[hd]: https://hexdocs.pm/elixir/Kernel.html#hd/1 +[in]: https://hexdocs.pm/elixir/Kernel.html#in/2 +[length]: https://hexdocs.pm/elixir/Kernel.html#length/1 +[list]: https://hexdocs.pm/elixir/List.html +[stream]: https://hexdocs.pm/elixir/Stream.html +[tl]: https://hexdocs.pm/elixir/Kernel.html#tl/1 +[linked-list-wiki]: https://en.wikipedia.org/wiki/Linked_list diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md new file mode 100644 index 000000000..d5193935d --- /dev/null +++ b/concepts/lists/introduction.md @@ -0,0 +1,87 @@ +# About + +[Lists][list] are a basic data type in Haskell for holding a collection of values. +Lists are _immutable_, meaning they cannot be modified. +Any operation that changes a list returns a new list. +There are several methods in the prelude which allows you to work with Lists. + +Lists in Haskell are implemented as [linked lists][linked-list-wiki], and not as arrays of contiguous memory location. +Therefore, accessing an element in a list takes linear time depending on the length of the list. + +Lists can be written in literal form, head-tail notation, (which uses the `cons` operator `:`), or a combination of both: + +```haskell +-- Literal Form +[] +[1] +[1, 2, 3] + +-- Head-tail Notation +[] +-- same as [1] +1 : [] +-- same as [1, 2, 3] +1 : (2 : (3 : [])) + +-- Mixed +-- same as [1, 2, 3] +1 : [2, 3] +``` + +Head-tail notation can be used to append items to a list. + +```haskell +list = [2, 1] + +[3, 2, 1] == 3 : list +-- true +``` + +Appending elements to a list during iteration is considered an anti-pattern. +Appending an element requires walking through the entire list and adding the element at the end, therefore, appending a new element in each iteration would require walking through the entire list in each iteration. + +We can achieve the same result by prepending an element to the reversed list, and then reversing the result. Prepending is a fast operation and requires constant time. + +```haskell +-- Appending to the end of a list (potentially slow) +[1, 2, 3] ++ [4] ++ [5] ++ [6] + +-- Prepend to the start of a list (faster, due to the nature of linked lists) +6 : (5 : (4 : [3, 2, 1])) +-- then reverse! +``` + +There are several common Prelude functions for lists: + +- [`head`][head] returns the _head_ of a list -- the _first_ item in a list. +- [`tail`][tail] returns the _tail_ of the list -- the list _minus_ the _first_ item. +- [`length`][length] returns the number items in the list. +- [`elem`][in] returns a boolean value indicating whether the item is an element in the list. + +There is also the [`List` module][list]. + +Lists can only contain one data type. + +```haskell +list = [1, "string"] +-- Error: No instance for (Num String) arising from the literal ‘1’ +``` + +## Type annotation + +The type annotation of a list is `[a]` where a is the type which the lists holds, for example `String` or `Int`. + +``` haskell +a :: [Int] +a = [1, 2, 3] +``` + +[enum]: https://hexdocs.pm/elixir/Enum.html +[enum-protocol]: https://hexdocs.pm/elixir/Enumerable.html +[hd]: https://hexdocs.pm/elixir/Kernel.html#hd/1 +[in]: https://hexdocs.pm/elixir/Kernel.html#in/2 +[length]: https://hexdocs.pm/elixir/Kernel.html#length/1 +[list]: https://hexdocs.pm/elixir/List.html +[stream]: https://hexdocs.pm/elixir/Stream.html +[tl]: https://hexdocs.pm/elixir/Kernel.html#tl/1 +[linked-list-wiki]: https://en.wikipedia.org/wiki/Linked_list diff --git a/concepts/lists/links.json b/concepts/lists/links.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/concepts/lists/links.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/exercises/concept/language-list/.docs/hints.md b/exercises/concept/language-list/.docs/hints.md new file mode 100644 index 000000000..3e2c107b8 --- /dev/null +++ b/exercises/concept/language-list/.docs/hints.md @@ -0,0 +1,8 @@ +# General + +- Basic numbers operators are described in the Haskell [GHC.Num module documentation](https://hackage.haskell.org/package/base-4.16.0.0/docs/GHC-Num.html). But you might prefer a more easily digestable [basic introduction.](https://www.tutorialspoint.com/haskell/haskell_basic_operators.htm) + +# Modules and Indentation + +- [Declaring modules](https://learnyouahaskell.github.io/modules#making-our-own-modules) +- [Indentation rules](https://en.wikibooks.org/wiki/Haskell/Indentation) diff --git a/exercises/concept/language-list/.docs/instructions.md b/exercises/concept/language-list/.docs/instructions.md new file mode 100644 index 000000000..ddcdec7cd --- /dev/null +++ b/exercises/concept/language-list/.docs/instructions.md @@ -0,0 +1,66 @@ +# Instructions + +In this exercise you need to implement some functions to manipulate a list of programming languages. + +## 1. Define a function to return an empty language list + +Define the `new` function that takes no arguments and returns an empty list. + +```haskell +new +-- -> [] +``` + +## 2. Define a function to add a language to the list + +Define the `add/2` function that takes 2 arguments (a _language list_ and a string literal of a _language_). +It should return the resulting list with the new language prepended to the given list. + +```haskell +add new "Clojure" +-- -> ["Clojure"] +add ["Clojure"] "Haskell" +-- -> ["Haskell", "Clojure"] +``` + +## 3. Define a function to remove a language from the list + +Define the `remove` function that takes 1 argument (a _language list_). +It should return the list without the first item. Assume the list will always have at least one item. + +```haskell +remove ["Haskell", "Clojure", "Erlang"] +-- -> ["Clojure", "Erlang"] +``` + +## 4. Define a function to return the first item in the list + +Define the `first` function that takes 1 argument (a _language list_). +It should return the first language in the list. +Assume the list will always have at least one item. + +```haskell +first ["Elixir", "Haskell", "Clojure", "Prolog"] +-- -> "Elixir" +``` + +## 5. Define a function to return how many languages are in the list + +Define the `count` function that takes 1 argument (a _language list_). +It should return the number of languages in the list. + +```haskell +count ["Prolog", "Elm"] +-- -> 2 +``` + +## 6. Define a function to determine if the list includes a functional language + +Define the `isFunctionalList` function which takes 1 argument (a _language list_). +It should return a boolean value. +It should return `True` if _"Haskell"_ is one of the languages in the list. + +```haskell +isFunctionalList ["Haskell"] +-- -> True +``` diff --git a/exercises/concept/language-list/.docs/introduction.md b/exercises/concept/language-list/.docs/introduction.md new file mode 100644 index 000000000..bf76c86b8 --- /dev/null +++ b/exercises/concept/language-list/.docs/introduction.md @@ -0,0 +1,87 @@ +# About + +[Lists][list] are a basic data type in Haskell for holding a collection of values. +Lists are _immutable_, meaning they cannot be modified. +Any operation that changes a list returns a new list. +There are several methods in the prelude which allows you to work with Lists. + +Lists in Haskell are implemented as [linked lists][linked-list-wiki], and not as arrays of contiguous memory location. +Therefore, accessing an element in a list takes linear time depending on the length of the list. + +Lists can be written in literal form, head-tail notation, (which uses the `cons` operator `:`), or a combination of both: + +```haskell +-- Literal Form +[] +[1] +[1, 2, 3] + +-- Head-tail Notation +[] +-- same as [1] +1 : [] +-- same as [1, 2, 3] +1 : (2 : (3 : [])) + +-- Mixed +-- same as [1, 2, 3] +1 : [2, 3] +``` + +Head-tail notation can be used to append items to a list. + +```haskell +list = [2, 1] + +[3, 2, 1] == 3 : list +-- -> True +``` + +Appending elements to a list during iteration is considered an anti-pattern. +Appending an element requires walking through the entire list and adding the element at the end, therefore, appending a new element in each iteration would require walking through the entire list in each iteration. + +We can achieve the same result by prepending an element to the reversed list, and then reversing the result. Prepending is a fast operation and requires constant time. + +```haskell +-- Appending to the end of a list (potentially slow) +[1, 2, 3] ++ [4] ++ [5] ++ [6] + +-- Prepend to the start of a list (faster, due to the nature of linked lists) +6 : (5 : (4 : [3, 2, 1])) +-- then reverse! +``` + +There are several common Prelude functions for lists: + +- [`head`][head] returns the _head_ of a list -- the _first_ item in a list. +- [`tail`][tail] returns the _tail_ of the list -- the list _minus_ the _first_ item. +- [`length`][length] returns the number items in the list. +- [`elem`][in] returns a boolean value indicating whether the item is an element in the list. + +There is also the [`List` module][list]. + +Lists can only contain one data type. + +```haskell +list = [1, "string"] +-- Error: No instance for (Num String) arising from the literal ‘1’ +``` + +## Type annotation + +The type annotation of a list is `[a]` where a is the type which the lists holds, for example `String` or `Int`. + +``` haskell +a :: [Int] +a = [1, 2, 3] +``` + +[enum]: https://hexdocs.pm/elixir/Enum.html +[enum-protocol]: https://hexdocs.pm/elixir/Enumerable.html +[hd]: https://hexdocs.pm/elixir/Kernel.html#hd/1 +[in]: https://hexdocs.pm/elixir/Kernel.html#in/2 +[length]: https://hexdocs.pm/elixir/Kernel.html#length/1 +[list]: https://hexdocs.pm/elixir/List.html +[stream]: https://hexdocs.pm/elixir/Stream.html +[tl]: https://hexdocs.pm/elixir/Kernel.html#tl/1 +[linked-list-wiki]: https://en.wikipedia.org/wiki/Linked_list diff --git a/exercises/concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE b/exercises/concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE new file mode 100644 index 000000000..6d7c414d8 --- /dev/null +++ b/exercises/concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE @@ -0,0 +1,3 @@ +Teaches the basics concept, wherein we want the students to learn how to define functions, +and we found that people usually learn best when they have to write things from scratch. +https://github.com/exercism/haskell/pull/1026#issuecomment-988556486 diff --git a/exercises/concept/language-list/.meta/config.json b/exercises/concept/language-list/.meta/config.json new file mode 100644 index 000000000..496ada26c --- /dev/null +++ b/exercises/concept/language-list/.meta/config.json @@ -0,0 +1,25 @@ +{ + "authors": [ + "meatball133" + ], + "files": { + "solution": [ + "src/LanguageList.hs", + "package.yaml" + ], + "test": [ + "test/Tests.hs" + ], + "exemplar": [ + ".meta/exemplar/src/LanguageListLanguageList.hs" + ], + "invalidator": [ + "stack.yaml" + ] + }, + "forked_from": [ + "elixir/language-list" + ], + "icon": "language-list", + "blurb": "Learn about lists by keeping track of the programming 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 000000000..5bbe978d3 --- /dev/null +++ b/exercises/concept/language-list/.meta/design.md @@ -0,0 +1,36 @@ +# Design + +## Learning objectives + +- Know of the existence of the `list` type. +- Know how list can be constructed with `[]` and `[ x : xs ]` syntax +- Use basic functions and macros related to Lists. + - `head` + - `tail` + - `length` + - `elem` +- Learn about string literals + +## Out of scope + +- Pattern matching +- `Enum` module functions / behaviors +- `String` functions and string manipulation +- Iterate over a list +- 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 + - like `[]`, `[_:_]`, `head`, `tail`, `length/1`, `elem` +- `string-literals` + - not a standalone concept, captured in `basics` + - know how to write out a string with double quotes + +## Prerequisites + +- `booleans` + - know how to return booleans values from a function diff --git a/exercises/concept/language-list/.meta/exemplar/package.yaml b/exercises/concept/language-list/.meta/exemplar/package.yaml new file mode 100644 index 000000000..b725f6a1d --- /dev/null +++ b/exercises/concept/language-list/.meta/exemplar/package.yaml @@ -0,0 +1,18 @@ +name: language-list +version: 1.0.0.0 + +dependencies: + - base + +library: + exposed-modules: LanguageList + source-dirs: src + ghc-options: -Wall + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - language-list + - hspec diff --git a/exercises/concept/language-list/.meta/exemplar/src/LanguageList.hs b/exercises/concept/language-list/.meta/exemplar/src/LanguageList.hs new file mode 100644 index 000000000..dc5826f71 --- /dev/null +++ b/exercises/concept/language-list/.meta/exemplar/src/LanguageList.hs @@ -0,0 +1,19 @@ +module LanguageList (new, add, remove, first, count, isFunctionalList) where + +new :: [String] +new = [] + +add :: String -> [String] -> [String] +add language list = language : list + +remove :: [String] -> [String] +remove list = tail list + +first :: [String] -> String +first list = head list + +count :: [String] -> Int +count list = length list + +isFunctionalList :: [String] -> Bool +isFunctionalList list = "Haskell" `elem` list diff --git a/exercises/concept/language-list/package.yaml b/exercises/concept/language-list/package.yaml new file mode 100644 index 000000000..b725f6a1d --- /dev/null +++ b/exercises/concept/language-list/package.yaml @@ -0,0 +1,18 @@ +name: language-list +version: 1.0.0.0 + +dependencies: + - base + +library: + exposed-modules: LanguageList + source-dirs: src + ghc-options: -Wall + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - language-list + - hspec diff --git a/exercises/concept/language-list/src/LanguageList.hs b/exercises/concept/language-list/src/LanguageList.hs new file mode 100644 index 000000000..b720af213 --- /dev/null +++ b/exercises/concept/language-list/src/LanguageList.hs @@ -0,0 +1,25 @@ +module LanguageList (new, add, remove, first, count, isFunctionalList) where + +new :: [String] +new = + error "Implement this function." + +add :: String -> [String] -> [String] +add = + error "Implement this function." + +remove :: [String] -> [String] +remove = + error "Implement this function." + +first :: [String] -> String +first = + error "Implement this function." + +count :: [String] -> Int +count = + error "Implement this function." + +isFunctionalList :: [String] -> Bool +isFunctionalList = + error "Implement this function." diff --git a/exercises/concept/language-list/stack.yaml b/exercises/concept/language-list/stack.yaml new file mode 100644 index 000000000..115878212 --- /dev/null +++ b/exercises/concept/language-list/stack.yaml @@ -0,0 +1 @@ +resolver: lts-20.18 diff --git a/exercises/concept/language-list/test/Tests.hs b/exercises/concept/language-list/test/Tests.hs new file mode 100644 index 000000000..da0db80ab --- /dev/null +++ b/exercises/concept/language-list/test/Tests.hs @@ -0,0 +1,63 @@ +import Test.Hspec (it, shouldBe, hspec) +import LanguageList (new, add, remove, first, count, isFunctionalList) + +main :: IO () +main = hspec $ do + it "new list" $ do + new `shouldBe` [] + + it "add a language to a list" $ do + add "Haskell" new `shouldBe` ["Haskell"] + + it "add several languages to a list" $ do + let updatedList = add "Elixir" + $ add "F#" + $ add "Erlang" + $ add "Haskell" + $ add "Clojure" new + updatedList `shouldBe` ["Elixir", "F#", "Erlang", "Haskell", "Clojure"] + + it "add then remove results in empty list" $ do + let updatedList = remove + $ add "Haskell" new + updatedList `shouldBe` [] + + it "adding two languages, when removed, removes first item" $ do + let updatedList = remove + $ add "Elixir" + $ add "Haskell" new + updatedList `shouldBe` ["Haskell"] + + it "add one language, then get the first" $ do + let firstElement = first + $ add "Haskell" new + firstElement `shouldBe` "Haskell" + + it "add one language, then get the first" $ do + let firstElement = first + $ add "F#" + $ add "Erlang" + $ add "Elixir" + $ add "Haskell" new + firstElement `shouldBe` "F#" + + it "the count of a new list is 0" $ do + count new `shouldBe` 0 + + it "the count of a one-language list is 1" $ do + let countElements = count + $ add "Haskell" new + countElements `shouldBe` 1 + + it "the count of a multiple-item list is equal to its length" $ do + let countElements = count + $ add "Erlang" + $ add "Elixir" + $ add "Haskell" new + countElements `shouldBe` 3 + + it "a functional language list" $ do + isFunctionalList ["Clojure", "Haskell", "Erlang", "Elixir", "F#"] `shouldBe` True + + it "not a functional language list" $ do + isFunctionalList ["Java", "C", "JavaScript"] `shouldBe` False From be6635e577172613e042ff1936ea366dcf6e343c Mon Sep 17 00:00:00 2001 From: meatball Date: Mon, 30 Sep 2024 20:27:54 +0200 Subject: [PATCH 2/4] Add lists concept --- concepts/lists/about.md | 26 ++++++------- concepts/lists/introduction.md | 28 +++++++------- concepts/lists/links.json | 11 +++++- config.json | 17 +++++++++ .../concept/language-list/.docs/hints.md | 38 ++++++++++++++++--- .../language-list/.docs/introduction.md | 26 ++++++------- .../concept/language-list/.meta/design.md | 2 +- 7 files changed, 101 insertions(+), 47 deletions(-) diff --git a/concepts/lists/about.md b/concepts/lists/about.md index bf76c86b8..563bfce7a 100644 --- a/concepts/lists/about.md +++ b/concepts/lists/about.md @@ -56,19 +56,21 @@ There are several common Prelude functions for lists: - [`head`][head] returns the _head_ of a list -- the _first_ item in a list. - [`tail`][tail] returns the _tail_ of the list -- the list _minus_ the _first_ item. - [`length`][length] returns the number items in the list. -- [`elem`][in] returns a boolean value indicating whether the item is an element in the list. +- [`elem`][elem] returns a boolean value indicating whether the item is an element in the list. -There is also the [`List` module][list]. +There is also the [`Data.List` module][list]. -Lists can only contain one data type. +## List types + +In Haskell, lists are **homogenous**. +This means that all elements of a list have the same type. +When you try to put elements of different types into the same list, you will get a type error. ```haskell list = [1, "string"] -- Error: No instance for (Num String) arising from the literal ‘1’ ``` -## Type annotation - The type annotation of a list is `[a]` where a is the type which the lists holds, for example `String` or `Int`. ``` haskell @@ -76,12 +78,10 @@ a :: [Int] a = [1, 2, 3] ``` -[enum]: https://hexdocs.pm/elixir/Enum.html -[enum-protocol]: https://hexdocs.pm/elixir/Enumerable.html -[hd]: https://hexdocs.pm/elixir/Kernel.html#hd/1 -[in]: https://hexdocs.pm/elixir/Kernel.html#in/2 -[length]: https://hexdocs.pm/elixir/Kernel.html#length/1 -[list]: https://hexdocs.pm/elixir/List.html -[stream]: https://hexdocs.pm/elixir/Stream.html -[tl]: https://hexdocs.pm/elixir/Kernel.html#tl/1 +[prelude]: https://hackage.haskell.org/package/base/docs/Prelude.html +[list]: https://hackage.haskell.org/package/base/docs/Data-List.html +[head]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:head +[tail]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:tail +[elem]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:elem +[length]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:length [linked-list-wiki]: https://en.wikipedia.org/wiki/Linked_list diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md index d5193935d..563bfce7a 100644 --- a/concepts/lists/introduction.md +++ b/concepts/lists/introduction.md @@ -34,7 +34,7 @@ Head-tail notation can be used to append items to a list. list = [2, 1] [3, 2, 1] == 3 : list --- true +-- -> True ``` Appending elements to a list during iteration is considered an anti-pattern. @@ -56,19 +56,21 @@ There are several common Prelude functions for lists: - [`head`][head] returns the _head_ of a list -- the _first_ item in a list. - [`tail`][tail] returns the _tail_ of the list -- the list _minus_ the _first_ item. - [`length`][length] returns the number items in the list. -- [`elem`][in] returns a boolean value indicating whether the item is an element in the list. +- [`elem`][elem] returns a boolean value indicating whether the item is an element in the list. -There is also the [`List` module][list]. +There is also the [`Data.List` module][list]. -Lists can only contain one data type. +## List types + +In Haskell, lists are **homogenous**. +This means that all elements of a list have the same type. +When you try to put elements of different types into the same list, you will get a type error. ```haskell list = [1, "string"] -- Error: No instance for (Num String) arising from the literal ‘1’ ``` -## Type annotation - The type annotation of a list is `[a]` where a is the type which the lists holds, for example `String` or `Int`. ``` haskell @@ -76,12 +78,10 @@ a :: [Int] a = [1, 2, 3] ``` -[enum]: https://hexdocs.pm/elixir/Enum.html -[enum-protocol]: https://hexdocs.pm/elixir/Enumerable.html -[hd]: https://hexdocs.pm/elixir/Kernel.html#hd/1 -[in]: https://hexdocs.pm/elixir/Kernel.html#in/2 -[length]: https://hexdocs.pm/elixir/Kernel.html#length/1 -[list]: https://hexdocs.pm/elixir/List.html -[stream]: https://hexdocs.pm/elixir/Stream.html -[tl]: https://hexdocs.pm/elixir/Kernel.html#tl/1 +[prelude]: https://hackage.haskell.org/package/base/docs/Prelude.html +[list]: https://hackage.haskell.org/package/base/docs/Data-List.html +[head]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:head +[tail]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:tail +[elem]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:elem +[length]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:length [linked-list-wiki]: https://en.wikipedia.org/wiki/Linked_list diff --git a/concepts/lists/links.json b/concepts/lists/links.json index 0637a088a..b01d42115 100644 --- a/concepts/lists/links.json +++ b/concepts/lists/links.json @@ -1 +1,10 @@ -[] \ No newline at end of file +[ + { + "url": "https://hackage.haskell.org/package/base/docs/Data-List.html", + "description": "Haskell Prelude: Data.List" + }, + { + "url": "https://www.haskelltutorials.com/guides/haskell-lists-ultimate-guide.html", + "description": "Haskell Lists: The Ultimate Guide" + } +] \ No newline at end of file diff --git a/config.json b/config.json index 145ade90f..6605b37d2 100644 --- a/config.json +++ b/config.json @@ -48,6 +48,18 @@ "basics" ] }, + { + "slug": "language-list", + "name": "Language List", + "uuid": "2770e2c0-883d-4336-be94-3b4ae7529ac3", + "prerequisites": [ + "basics" + ], + "status": "beta", + "concepts": [ + "lists" + ] + }, { "slug": "temperature", "name": "Temperature", @@ -1399,6 +1411,11 @@ "slug": "booleans", "name": "Booleans" }, + { + "uuid": "ef484ab5-d4d2-4d7c-b4b5-abb5920f916a", + "slug": "lists", + "name": "Lists" + }, { "uuid": "ca21a553-6fc1-49be-8f47-730f97330862", "slug": "pattern-matching-literals", diff --git a/exercises/concept/language-list/.docs/hints.md b/exercises/concept/language-list/.docs/hints.md index 3e2c107b8..de70d1ee0 100644 --- a/exercises/concept/language-list/.docs/hints.md +++ b/exercises/concept/language-list/.docs/hints.md @@ -1,8 +1,36 @@ -# General +# Hints -- Basic numbers operators are described in the Haskell [GHC.Num module documentation](https://hackage.haskell.org/package/base-4.16.0.0/docs/GHC-Num.html). But you might prefer a more easily digestable [basic introduction.](https://www.tutorialspoint.com/haskell/haskell_basic_operators.htm) +## General -# Modules and Indentation +- Use the built-in [(linked) list type][list]. -- [Declaring modules](https://learnyouahaskell.github.io/modules#making-our-own-modules) -- [Indentation rules](https://en.wikibooks.org/wiki/Haskell/Indentation) +## 1. Define a function to return an empty language list + +- The function needs to return `[]`. + +## 2. Define a function to add a language to the list + +- An element can be prepended to a list using `:`. + +## 3. Define a function to remove a language from the list + +- Haskell [provides a function][tail] to return a list with the first item removed. + +## 4. Define a function to return the first item in the list + +- HaskellHaskell [provides a function][head] to get the first item from a list. + +## 5. Define a function to return how many languages are in the list + +- Haskell [provides a function][length] to count the length of a list. + +## 6. Define a function to determine if the list includes a functional language + +- Your function should return a boolean value indicating whether `"Haskell"` is a member of the list. + Haskell [provides a function][elem] to test list membership. + +[list]: https://hackage.haskell.org/package/base/docs/Data-List.html +[head]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:head +[tail]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:tail +[elem]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:elem +[length]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:length diff --git a/exercises/concept/language-list/.docs/introduction.md b/exercises/concept/language-list/.docs/introduction.md index bf76c86b8..563bfce7a 100644 --- a/exercises/concept/language-list/.docs/introduction.md +++ b/exercises/concept/language-list/.docs/introduction.md @@ -56,19 +56,21 @@ There are several common Prelude functions for lists: - [`head`][head] returns the _head_ of a list -- the _first_ item in a list. - [`tail`][tail] returns the _tail_ of the list -- the list _minus_ the _first_ item. - [`length`][length] returns the number items in the list. -- [`elem`][in] returns a boolean value indicating whether the item is an element in the list. +- [`elem`][elem] returns a boolean value indicating whether the item is an element in the list. -There is also the [`List` module][list]. +There is also the [`Data.List` module][list]. -Lists can only contain one data type. +## List types + +In Haskell, lists are **homogenous**. +This means that all elements of a list have the same type. +When you try to put elements of different types into the same list, you will get a type error. ```haskell list = [1, "string"] -- Error: No instance for (Num String) arising from the literal ‘1’ ``` -## Type annotation - The type annotation of a list is `[a]` where a is the type which the lists holds, for example `String` or `Int`. ``` haskell @@ -76,12 +78,10 @@ a :: [Int] a = [1, 2, 3] ``` -[enum]: https://hexdocs.pm/elixir/Enum.html -[enum-protocol]: https://hexdocs.pm/elixir/Enumerable.html -[hd]: https://hexdocs.pm/elixir/Kernel.html#hd/1 -[in]: https://hexdocs.pm/elixir/Kernel.html#in/2 -[length]: https://hexdocs.pm/elixir/Kernel.html#length/1 -[list]: https://hexdocs.pm/elixir/List.html -[stream]: https://hexdocs.pm/elixir/Stream.html -[tl]: https://hexdocs.pm/elixir/Kernel.html#tl/1 +[prelude]: https://hackage.haskell.org/package/base/docs/Prelude.html +[list]: https://hackage.haskell.org/package/base/docs/Data-List.html +[head]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:head +[tail]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:tail +[elem]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:elem +[length]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:length [linked-list-wiki]: https://en.wikipedia.org/wiki/Linked_list diff --git a/exercises/concept/language-list/.meta/design.md b/exercises/concept/language-list/.meta/design.md index 5bbe978d3..b9fe14c8e 100644 --- a/exercises/concept/language-list/.meta/design.md +++ b/exercises/concept/language-list/.meta/design.md @@ -25,7 +25,7 @@ - know of the existence of the `list` type; - know of the idea of `list` design; - know some basic patterns / functions - - like `[]`, `[_:_]`, `head`, `tail`, `length/1`, `elem` + - like `[]`, `[_:_]`, `head`, `tail`, `length`, `elem` - `string-literals` - not a standalone concept, captured in `basics` - know how to write out a string with double quotes From 16dae496bf833aca4da40f35dbb23ece0845a869 Mon Sep 17 00:00:00 2001 From: meatball Date: Mon, 30 Sep 2024 20:29:30 +0200 Subject: [PATCH 3/4] Fix config file --- exercises/concept/language-list/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/language-list/.meta/config.json b/exercises/concept/language-list/.meta/config.json index 496ada26c..141e68c99 100644 --- a/exercises/concept/language-list/.meta/config.json +++ b/exercises/concept/language-list/.meta/config.json @@ -11,7 +11,7 @@ "test/Tests.hs" ], "exemplar": [ - ".meta/exemplar/src/LanguageListLanguageList.hs" + ".meta/exemplar/src/LanguageList.hs" ], "invalidator": [ "stack.yaml" From 79f5c93ecade6034e389ae3f94995441b64004b5 Mon Sep 17 00:00:00 2001 From: meatball Date: Mon, 30 Sep 2024 20:32:36 +0200 Subject: [PATCH 4/4] Remove stub allowed not to compile --- .../concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 exercises/concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE diff --git a/exercises/concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE b/exercises/concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE deleted file mode 100644 index 6d7c414d8..000000000 --- a/exercises/concept/language-list/.meta/STUB-ALLOWED-TO-NOT-COMPILE +++ /dev/null @@ -1,3 +0,0 @@ -Teaches the basics concept, wherein we want the students to learn how to define functions, -and we found that people usually learn best when they have to write things from scratch. -https://github.com/exercism/haskell/pull/1026#issuecomment-988556486