1
0
Fork 0

Merge remote-tracking branch 'upstream/main'

main
Oliver Stolle 2026-04-27 21:05:10 +00:00
commit 6d96eb957d
19 changed files with 714 additions and 0 deletions

View File

@ -0,0 +1,10 @@
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y build-essential curl libffi-dev libffi8ubuntu1 libgmp-dev libgmp10 libncurses-dev
RUN curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
ENV PATH="$PATH:/root/.ghcup/bin"
RUN ghcup install hls
RUN apt-get update && apt-get install -y git zlib1g-dev
RUN cabal update && cabal install ghci-dap haskell-debug-adapter
RUN cabal update && cabal install --lib HUnit

View File

@ -0,0 +1,12 @@
{
"name": "Haskell Dev Container",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": { "extensions": [
"haskell.haskell",
"phoityne.phoityne-vscode"
]}
}
}

3
haskell/.vscode/settings.json vendored 100644
View File

@ -0,0 +1,3 @@
{
"editor.formatOnSave": true
}

61
haskell/.vscode/tasks.json vendored 100644
View File

@ -0,0 +1,61 @@
{
// Automatically created by phoityne-vscode extension.
"version": "2.0.0",
"presentation": {
"reveal": "always",
"panel": "new"
},
"tasks": [
{
// F7
"group": {
"kind": "build",
"isDefault": false
},
"label": "haskell build",
"type": "shell",
"command": "cabal configure && cabal build"
},
{
// F6
"group": "build",
"type": "shell",
"label": "haskell clean & build",
"command": "cabal clean && cabal configure && cabal build"
},
{
// F8
"group": {
"kind": "test",
"isDefault": true
},
"type": "shell",
"label": "haskell test",
"command": "cabal test"
},
{
// F6
"isBackground": true,
"type": "shell",
"label": "haskell watch",
"command": "stack build --test --no-run-tests --file-watch"
}
,
{
// Build a single Haskell file
"type": "shell",
"label": "haskell build single file",
"command": "ghc",
"args": [ "${file}" ],
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@ -0,0 +1,14 @@
# Build
`ghc hello-world.hs`
# Run
`runghc hello-world.hs`
# Run interactively
```
ghci
ghci> :load hello-world.hs
ghci> main
```

View File

@ -0,0 +1,2 @@
main :: IO ()
main = putStrLn "Hello, World!"

View File

@ -0,0 +1,131 @@
# Haskell - Expressions
The following illustrates some haskell basics. It can be reproduced using `ghci`.
## Types, Literals, and Constants along with Arithmetic and Boolean Operations
Expression | Type (:t) | Value | Comment
--- | --- | --- | --------
`2` | `Num a => a` | `2` |
`2.03` | `Fractional a => a` | `2.03` |
`'c'` | `Char` | `'c'`
`"hallo"` | `String` | `"hallo"` |
`True` | `Bool` | `True` |
`x=5` | `Num a => a` | `5` | Constant named `x`
`2 + 3` | `Num a => a` | `5` | Similar `-,*,^`
`2 / 3` | `Fractional a => a` | `0.6666666666666666` |
`1 > 2` | `Bool` | `False` | Similar `<, <=, >=, ==, /=`
`True && False` | `Bool` | `False` | Similar `\|\|,not`
`((2+3)*5 > 1) \|\| not (1 > 2)` | `Bool` | `True` | Right part is not evaluated due to lazy evaluation
## Unary Functions
Expression | Type (:t) | Value | Comment
--- | --- | --- | --------
`sqrt(4)` | `Floating a => a` | `2.0` |
`sqrt 4` | `Floating a => a` | `2.0` | Similar `abs,negate,signum,recip`
`sqrt` | `Floating a => a -> a` | |
`sqrt 3^2 + 4^2` | `Floating a => a` | `19.0` |
`sqrt (3^2 + 4^2)` | `Floating a => a` | `5.0` |
`negate(sqrt (3^2 + 4^2))` | `Floating a => a` | `-5.0` |
`negate $ sqrt (3^2 + 4^2)` | `Floating a => a`| `-5.0` | Function **application** operator `$`
`(negate . sqrt) (3^2 + 4^2)`| `Floating a => a`| `-5.0` | Function **composition** operator `.` Reads `negate` **after** `negate . sqrt` |
`(negate . length) "hallo"` | `Int` | `-5` |
`negatedRoot = negate . sqrt` | `Floating c => c -> c` | | Constant named `negatedRoot`
## Binary Functions
Expression | Type (:t) | Value | Comment
--- | --- | --- | --------
`div 8 4` | `Integral a => a` | `2` | Similar `mod,gcd,lcm,not`
``8 `div` 4`` | `Integral a => a` | `2` | **Infix** notation using backticks
`8 + 4` | `Num a => a` | `12` | `-,*,^,<, <=, >=, ==, /=`
`(+) 8 4` | `Num a => a` | `12` | **Prefix** notation using parenthesis
`div` | `Integral a => a -> a -> a` | | **Currying** represents multi-argument functions as a chain of single-argument functions |
`div 8` | `Integral a => a -> a` | | binds the **first** argument; Similar `(8/),(8*),(8+),(8-)` |
`div8bySomething = div 8` | `Integral a => a -> a` | |
`div8bySomething 4` | `Integral a => a` | `2` |
`uncurry div` | `Integral c => (c, c) -> c` | | accepts a single tuple argument
`uncurry div (8,4)` | `Integral c => c` | `2` |
`uncurry` | `(a -> b -> c) -> (a, b) -> c`| |
`` (`div` 4) `` | `Integral a => a -> a` | | **Sectioning** binds the **second** argument of infix functions; Similar `(/8),(*8),(+8),(-8)` |
``divSomethingBy4 = (`div` 4)`` | `Integral a => a -> a` | |
`divSomethingBy4 8` | `Integral a => a` | `2` |
`const` | `a -> b -> a` | |
`const 8` | `Num a => b -> a` | | function that ignores the input and always returns 8
`const 8 4` | `Num a => a` | `8` |
## Tuples
Expression | Type (:t) | Value | Comment
--- | --- | --- | --------
`(1, 2)` | `(Num a, Num b) => (a, b)` | `(1, 2)` |
`(1, "hello", True)` | `(Num a => (a, String, Bool)` | `(1, "hello", True)` |
`fst (1, 2)` | `Num a => a` | `1` |
`snd (1, 2)` | `Num b => b` | `2` |
`(,) 1 2` | `Num a => a -> a -> (a, a)` | `(1, 2)` |
## Strings
Expression | Type (:t) | Value | Comment
--- | --- | --- | --------
`"hello" ++ " world"` | `String` | `"hello world"` | String concatenation
`length "hello"` | `Int` | `5` | Length of the string
`null ""` | `Bool` | `True` | Checks if the string is empty
## Control Structures
Expression | Type (:t) | Value | Comment
--- | --- | --- | --------
`if 10/2==5 then "five" else "something else"` | `String` | `"five"` |
`case 1 of { 1 -> "small"; 2 -> "medium"; _ -> "large"}` | `String` | `"small"` | patterns are overlapping
`(let x = 5*2 in (x * 2,x /2))` | `(Fractional b, Num a) => (a, b)` | `(20,5.0)` |
## Lists
Expression | Type (:t) | Value | Comment
--- | --- | --- | --------
`[]` | `[a]` | `[]` |
`1:7:4:[]` | `Num a => [a]` | `[1,7,4]` | actual construction of a list
`[1,7,4]` | `Num a => [a]` | `[1,7,4]` |
`8 : [1,7,4]` | `Num a => [a]` | `[8,1,7,4]` | **cons** operator, short for construct
`[1,7,4]` | `[Num a] => [a]` | `[1,7,4]` |
`(++)` | `[a] -> [a] -> [a]` | |
`[1,7,4] ++ [8]` | `Num a => [a]` | `[1,7,4,8]` |
`[1,7,4] !! 2` | `Num a => [a]` | `4` |
`(!!)` | `[a] -> Int -> a` | |
`head [1,7,4]` | `Num a => a` | `1` | Similar `last`
`tail [1,7,4]` | `[Num a] => [a]` | `[7,4]` | Similar `init`
`length [1,7,4]` | `Int` | `3` |
`null []` | `Bool` | `True` |
`reverse [1,7,4]` | `[Num a] => [a]` | `[4,7,1]` | Similar `Data.List.sort`
`take 2 [1,7,4]` | `[Num a]=>[a]` | `[1,7]` | Similar `drop`
`take` | `Int -> [a] -> [a]` | |
`sum [1,7,4]` | `Num a=>a` | `12` | Similar `product,maximum,minimum,length`
`foldl (-) 0 [1,7,4]` | `Num a => a` | `-12` | `(((0-1)-7)-4)`
`foldl` | `Foldable t => (b -> a -> b) -> b -> t a -> b` | |
`foldr (-) 0 [1,7,4]` | `Num a => a` | `-2` | `(1-(7-(4-0)))`
`elem 7 [1,7,4]` | `Bool` | `True` |
`all even [1,7,4]` | `Bool` | `False` | Similar `any`
`filter even [1,7,4]` | `[Integral a] => [a]` | `[1,7,4]` | Similar `odd,(>1),(/=3)`
`(length . filter (>1) ) [1,7,4]` | `Int` | `2` |
`Data.List.partition (>1) [1,7,4]` | `(Ord a, Num a) => ([a], [a])` | `([7,4],[1])`
`zip [1,7,4] ["one","seven","four","eight"]` | `Num a => [(a, String)]` | `[(1,"one"),(7,"seven"),(4,"four")]` | truncating to the shorter list
`Data.List.sortOn fst $ zip [1,7,4] ["one", "seven", "four"]` | `(Ord b, Num b) => [(b, String)]` | `[(1,"one"),(4,"four"),(7,"seven")]`
`Data.List.sort ["one","seven","four","eight"]` | `[String]` | `["eight","four","one","seven"]`
`reverse $ Data.List.sort ["one","seven","four","eight"]` | `[String]` | `["seven","one","four","eight"]`
`Data.List.sortBy compare ["one","seven","four","eight"]` | `[String]` | `["eight","four","one","seven"]`
`Data.List.sortBy (flip compare) ["one","seven","four","eight"]` | `[String]` | `["seven","one","four","eight"]`
`Data.List.sortBy (curry( (uncurry compare) . (uncurry(Control.Arrow.***) (length,length)))) ["one","seven","four","eight","ten"]` | `[String]` | `["one","ten","four","seven","eight"]` |
`Data.List.sortBy (Data.Ord.comparing length) ["one","seven","four","eight","ten"]` | `[String]` | `["one","ten","four","seven","eight"]`
`map (+1) [1,7,4]` | `Num a => [a]` | `[2,8,5]` |
`map length ["one", "seven", "four"]` | `[Int]` | `[3,5,4]` |
`map (negate . abs) [1,-7,4]` | `Num a => [a]` | `[-1,-7,-4]` |
`map even [1,7,4]` | `[Bool]` | `[False,False,True]` |
`[1..5]` | `(Num a, Enum a) => [a]` | `[1,2,3,4,5]` |
`[1,3..9]` | `(Num a, Enum a) => [a]` | `[1,3,5,7,9]` |
`[1..]` | `(Num a, Enum a) => [a]` | `[1,2,3,4,5,...]` | infinite sequence
`take 4 [10..]` | `(Num a, Enum a) => [a]` | `[1,2,3,4]` | laziness in action
`[x*2 \| x <- [1..5]]` | `[Num a] => [a]` | `[2, 4, 6, 8, 10]` | List comprehension
``[x*2 \| x <- [1..5], x `mod` 3 == 0]`` | `[Num a] => [a]` | `[6]` |
`[ (a,b,c) \| c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]` | `(Num c, Eq c, Enum c) => [(c, c, c)]` | `[(3,4,5),(6,8,10)]`

View File

@ -0,0 +1,10 @@
# Assignment
You are provided with:
1. A vector of names
2. A vector of ages
Your task is to compute a list containing the UPPERCASE names of the two oldest persons whose names ends with an "a". The result shall be sorted by alphabet.
Complete the corresponding unit test in the file `02-list-operations/list-operations.hs`.

View File

@ -0,0 +1,23 @@
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Avoid reverse" #-}
{-# HLINT ignore "Use void" #-}
import Data.Char (toUpper)
import Data.List (sort, sortOn)
import Test.HUnit
names = ["Oliver", "Emma", "Liam", "Ava", "Noah", "Sophia", "James", "Mia", "Elijah", "Isabella"]
ages = [25, 30, 22, 29, 35, 28, 40, 26, 33, 31]
-- we are looking for the UPPERCASE names of the two oldest persons whose names ends with an a sorted alphabetically"
extractedNames = []
test1 = Test.HUnit.TestCase (assertEqual "ExtractedNames" ["EMMA", "ISABELLA"] extractedNames)
tests = TestList [test1]
main :: IO ()
main = runTestTT test1 >> return ()

View File

@ -0,0 +1,33 @@
-- single parameter
-- two parameters
-- ============= pattern matching =================
-- ============= guards =================
-- ============= recursive algorithms =================
-- ============= recursive list algorithms =================
-- ============= merge sort =================
-- =========== Filter all numbers that can be divided by 10 ===========
-- ========================== standard deviation using lambdas =====================
-- The standard deviation is a measure of the amount of variation or dispersion of a set of values.
-- It is defined as the square root of the average of the squared differences from the mean.
--
-- Formula:
-- σ = sqrt( (1/N) * Σ (xi - μ)^2 )
-- where:
-- - σ is the standard deviation,
-- - N is the number of values,
-- - xi represents each value,
-- - μ is the mean of the values.
stddev seq = 0
-- ======================= order list of strings by length =================

View File

@ -0,0 +1,13 @@
# Assignment - Tower of Hanoi {.alert}
The Tower of Hanoi is a classic mathematical puzzle that involves three rods and a number of disks of different sizes.
The puzzle starts with all the disks stacked in ascending order of size on one rod (the source rod), with the smallest disk on top.
The objective is to move the entire stack to another rod (the destination rod), following these rules:
1. Only one disk can be moved at a time.
2. Each move consists of taking the top disk from one rod and placing it on another rod.
3. No disk may be placed on top of a smaller disk.
**Your task:**
Implement a function that solves the Tower of Hanoi problem for `n` disks. The rods are represented as Chars (e.g. 'a','b','c'). The result shall be a list of moving instructions. Add your implementation to the file `04-hanoi/hanoi.hs` that already contains a test and a helper function that creates the move instruction for a single move.

View File

@ -0,0 +1,70 @@
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use void" #-}
import Test.HUnit
-- some helper function that describes a single move
move :: Int -> Char -> Char -> String
move n src dst = "move disk " ++ show n ++ " from " ++ [src] ++ " to " ++ [dst]
-- transfers a number of disks (the Int) from a source (the first Char) rod to a destination (the second Char) rod via a temp (the third char) rod
-- returns a list of required operations
hanoi :: (Int,Char,Char,Char) -> [String]
--TODO: implement here
-- Source, Destination, Temp
hanoiTests :: [((Int, Char, Char, Char), [String])]
hanoiTests =
[ ( (1, 'a', 'c', 'b'),
[ "move disk 1 from a to c"
]
),
( (1, 'b', 'a', 'c'),
[ "move disk 1 from b to a"
]
),
( (2, 'a', 'c', 'b'),
[ "move disk 1 from a to b",
"move disk 2 from a to c",
"move disk 1 from b to c"
]
),
( (3, 'a', 'c', 'b'),
[ "move disk 1 from a to c",
"move disk 2 from a to b",
"move disk 1 from c to b",
"move disk 3 from a to c",
"move disk 1 from b to a",
"move disk 2 from b to c",
"move disk 1 from a to c"
]
),
( (4, 'a', 'c', 'b'),
[ "move disk 1 from a to b",
"move disk 2 from a to c",
"move disk 1 from b to c",
"move disk 3 from a to b",
"move disk 1 from c to a",
"move disk 2 from c to b",
"move disk 1 from a to b",
"move disk 4 from a to c",
"move disk 1 from b to c",
"move disk 2 from b to a",
"move disk 1 from c to a",
"move disk 3 from b to c",
"move disk 1 from a to b",
"move disk 2 from a to c",
"move disk 1 from b to c"
]
)
]
hanoiTestCases :: [Test]
hanoiTestCases = map (\(input, expected) -> TestCase (assertEqual ("hanoi " ++ show input) expected (hanoi input))) hanoiTests
tests :: Test
tests = TestList hanoiTestCases
main :: IO ()
main = runTestTT tests >> return ()

View File

@ -0,0 +1,5 @@
-- data Entity =
-- data Shape =
-- area :: Shape a -> a

View File

@ -0,0 +1,72 @@
# Complex Numbers
## Assignment
Define a new type `Complex` that allows arithmetic calculations in an intuitive fashion. See below for the rules that shall be implemented. Incrementally make sure that all unit tests in `06-complex/complex.hs` are passed.
## Complex Numbers
Complex numbers are numbers of the form: $z = a + bi$
- **`a`**: The real part of the complex number.
- **`b`**: The imaginary part of the complex number.
- **`i`**: The imaginary unit, where $i^2 = -1$.
Complex numbers are used in mathematics, physics, and engineering to extend the real number system and solve equations that have no real solutions, such as $x^2 + 1 = 0$.
Complex numbers are often represented in both rectangular form $a + bi$ and polar/exponential form $r e^{i\theta}$.
## Rules for Computing with Complex Numbers
### 1. **Addition and Subtraction**
- Add or subtract the real and imaginary parts separately.
- Rule:
$(a + bi) + (c + di) = (a + c) + (b + d)i$
$(a + bi) - (c + di) = (a - c) + (b - d)i$
**Examples**:
1. $(2 + 3i) + (4 + 5i) = 6 + 8i$
2. $(0 + 3i) + (2 + 0i) = 2 + 3i$
3. $(7 + 2i) - (3 + 6i) = 4 - 4i$
4. $(5 + 4i) - (1 + 2i) = 4 + 2i$
### 2. **Multiplication**
- Use the distributive property and the rule $i^2 = -1$.
- Rule:
$(a + bi)(c + di) = (ac - bd) + (ad + bc)i$
**Examples**:
1. $(1 + 2i)(3 + 4i) = -5 + 10i$
2. $(2 + 3i)(1 - i) = 5 + i$
3. $(4 + i)(2 - 3i) = 11 - 10i$
4. $(3 + 2i)(3 + 2i) = 5 + 12i$
### 3. **Division**
- Multiply numerator and denominator by the conjugate of the denominator.
- Rule:
$\frac{a + bi}{c + di} = \frac{(a + bi)(c - di)}{(c + di)(c - di)}$
Simplifies to:
$\frac{(ac + bd) + (bc - ad)i}{c^2 + d^2}$
**Examples**:
1. $\frac{1 + i}{1 - i} = 0 + 1i$
2. $\frac{3 + 2i}{4 + 3i} = \frac{18 + i}{25} = 0.72 - 0.04i$
3. $\frac{2 + i}{1 + i} = \frac{3 - i}{2} = 1.5 - 0.5i$
### 4. **Complex Conjugate**
- The conjugate of $a + bi$ is $a - bi$, used for simplifications and magnitude calculation.
**Examples**:
1. Conjugate of $3 + 4i$ is $3 - 4i$.
2. Conjugate of $5 - i$ is $5 + i$.
3. Conjugate of $-2 + 3i$ is $-2 - 3i$.
### 5. **Magnitude (Modulus)**
- The magnitude is the distance from the origin in the complex plane.
- Rule: $|a + bi| = \sqrt{a^2 + b^2}$
**Examples**:
1. $|3 + 4i| = \sqrt{3^2 + 4^2} = 5$
2. $|1 - i| = \sqrt{1^2 + (-1)^2} = \sqrt{2}$
3. $|0 + 5i| = \sqrt{0^2 + 5^2} = 5$

View File

@ -0,0 +1,123 @@
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use void" #-}
import Test.HUnit
data Complex a = TODO
instance (Show a, Num a, Eq a) => Show (Complex a) where
-- show :: (Show a, Num a, Eq a) => Complex a -> String
-- TODO
instance (Num a, Floating a) => Num (Complex a) where
-- (+) :: (Num a, Floating a) => Complex a -> Complex a -> Complex a
-- (*) :: (Num a, Floating a) => Complex a -> Complex a -> Complex a
-- TODO
-- abs (Complex re im) = TODO
-- signum (Complex re im) = TODO
-- fromInteger n = TODO
-- negate :: (Num a, Floating a) => Complex a -> Complex a
-- negate (Complex re im) = Complex (negate re) (negate im)
instance (Fractional a, Floating a) => Fractional (Complex a) where
-- fromRational r = TODO
-- recip (Complex re im) = TODO
-- (Complex re1 im1) / (Complex re2 im2) = TODO
-- conj :: Num a => Complex a -> Complex a
-- TODO
tests :: Test
tests =
TestList
[ Test.HUnit.TestCase (assertEqual "Show 1+2i" "1+2i" (show $ Complex 1 2)),
Test.HUnit.TestCase (assertEqual "Show 1" "1" (show $ Complex 1 0)),
Test.HUnit.TestCase (assertEqual "Show i" "i" (show i)),
Test.HUnit.TestCase (assertEqual "Show 5i" "5i" (show $ Complex 0 5)),
Test.HUnit.TestCase (assertEqual "Show 0" "0" (show $ Complex 0 0)),
Test.HUnit.TestCase (assertEqual "Compare Equal" True (Complex 2 3 == Complex 2 3)),
Test.HUnit.TestCase (assertEqual "Compare Real Not Equal" False (Complex 1 3 == Complex 2 3)),
Test.HUnit.TestCase
(assertEqual "Compare Imag Not Equal" False (Complex 2 4 == Complex 2 3)),
Test.HUnit.TestCase
(assertEqual "Compare Not Equal" False (Complex 2 3 /= Complex 2 3)),
Test.HUnit.TestCase
( assertEqual
"Addition 1"
(Complex 6.0 8.0)
(Complex 2.0 3.0 + Complex 4.0 5.0)
),
Test.HUnit.TestCase
( assertEqual
"Addition 2"
(Complex 2.0 3.0)
(Complex 0.0 3.0 + Complex 2.0 0.0)
),
Test.HUnit.TestCase
( assertEqual
"Subtraction 1"
(Complex 4.0 (-4.0))
(Complex 7.0 2.0 - Complex 3.0 6.0)
),
Test.HUnit.TestCase
( assertEqual
"Subtraction 2"
(Complex 4.0 2.0)
(Complex 5.0 4.0 - Complex 1.0 2.0)
),
Test.HUnit.TestCase
( assertEqual
"Negation"
(Complex (-7.0) (-2.0))
(negate (Complex 7.0 2.0))
),
Test.HUnit.TestCase
( assertEqual
"Multiplication 1"
(Complex (-5.0) 10.0)
(Complex 1.0 2.0 * Complex 3.0 4.0)
),
Test.HUnit.TestCase
( assertEqual
"Multiplication 2"
(Complex 5.0 1.0)
(Complex 2.0 3.0 * Complex 1.0 (-1.0))
),
Test.HUnit.TestCase
( assertEqual
"Multiplication 3"
(Complex 11.0 (-10.0))
(Complex 4.0 1.0 * Complex 2.0 (-3.0))
),
Test.HUnit.TestCase
( assertEqual
"Multiplication 4"
(Complex 5.0 12.0)
(Complex 3.0 2.0 * Complex 3.0 2.0)
),
Test.HUnit.TestCase
( assertEqual
"Magnitude 1"
(Complex 5.0 0.0)
(abs (Complex 3.0 4.0))
),
Test.HUnit.TestCase
( assertEqual
"Magnitude 2"
(Complex (sqrt 2.0) 0.0)
(abs (Complex 1.0 (-1.0)))
),
Test.HUnit.TestCase
( assertEqual
"Magnitude 3"
(Complex 5.0 0.0)
(abs (Complex 0.0 5.0))
),
TestCase (assertEqual "Conjugate of 3+4i" (Complex 3 (-4)) (conj (Complex 3 4))),
TestCase (assertEqual "Conjugate of 5-i" (Complex 5 1) (conj (Complex 5 (-1)))),
TestCase (assertEqual "Conjugate of -2+3i" (Complex (-2) (-3)) (conj (Complex (-2) 3)))
]
main :: IO ()
main = runTestTT tests >> return ()

View File

@ -0,0 +1,2 @@
import System.IO
import Text.Read (readMaybe)

View File

@ -0,0 +1,16 @@
# Assignment - Statistics
The file `08-statistics/data.csv` contains random data of students. It consists of the following columns:
- first name
- last name
- study subject
The rest of the columns -- and that number may vary -- contain points for different tasks. The first row is a header.
Your task is to Write a program that reads a filename from standard input. The corresponding csv-file shall be parsed and then the following statistics shall be computed and printed to standard output:
- the best student, i.e. the student with the most accumulated points (name and points shall be printed)
- the average points of all rows for each subject (subject and average points shall be printed in ascending order)
Implement your solution in the file `08-statistics/statistics.hs` and upload the file to moodle.

View File

@ -0,0 +1,97 @@
First Name,Last Name,Subject,Task1,Task2,Task3,Task4,Task5
Alice,Johnson,IB,87,45,68,92,33
Bob,Smith,CSB,56,79,42,88,12
Charlie,Williams,IMB,73,94,35,64,89
David,Brown,UIB,41,59,77,29,83
Emma,Jones,IB,99,21,48,75,56
Frank,Garcia,CSB,32,81,94,55,23
Grace,Miller,IMB,74,53,61,95,39
Henry,Davis,UIB,90,40,28,76,65
Isabella,Rodriguez,IB,57,86,72,49,100
Jack,Martinez,CSB,64,31,59,97,14
Liam,Hernandez,IMB,85,67,50,78,41
Mia,Lopez,UIB,44,92,33,56,81
Noah,Gonzalez,IB,68,39,74,82,47
Olivia,Wilson,CSB,95,20,62,53,34
Paul,Anderson,IMB,29,88,49,31,77
Sophia,Thomas,UIB,81,56,93,42,69
Ethan,Moore,IB,47,77,65,59,92
Zoe,Taylor,CSB,38,95,40,70,58
Lucas,Harris,IMB,99,45,83,62,37
Ava,Clark,UIB,53,66,91,85,29
Benjamin,Walker,IB,71,58,80,34,61
Chloe,Hall,CSB,76,23,67,47,94
Daniel,Allen,IMB,39,82,55,90,73
Ella,Young,UIB,86,32,99,60,25
James,King,IB,42,75,48,93,57
Madison,Wright,CSB,63,54,72,51,88
Nathan,Scott,IMB,91,37,79,68,45
Emma,Green,UIB,50,89,31,77,61
Jacob,Baker,IB,74,69,58,46,97
Emily,Adams,CSB,88,41,66,79,30
Samuel,Nelson,IMB,33,85,92,40,50
Sophia,Carter,UIB,69,47,71,58,94
Alexander,Mitchell,IB,57,98,36,61,82
Victoria,Perez,CSB,92,28,64,73,49
William,Roberts,IMB,45,76,89,55,31
Ella,Turner,UIB,78,59,41,96,68
Daniel,Phillips,IB,60,32,85,71,43
Natalie,Campbell,CSB,55,74,99,28,79
Mason,Parker,IMB,93,50,39,82,66
Hannah,Evans,UIB,48,69,57,95,22
Christopher,Edwards,IB,90,88,34,53,72
Lucy,Collins,CSB,31,46,81,77,56
Gabriel,Stewart,IMB,65,79,62,90,44
Avery,Morris,UIB,80,23,47,36,97
Ryan,Ross,IB,58,71,83,45,74
Sophie,Reed,CSB,99,33,60,81,51
Isaac,Adams,IMB,42,92,30,57,85
Leah,Bennett,UIB,76,64,55,89,39
Tyler,Barnes,IB,67,40,78,95,20
Scarlett,Morgan,CSB,34,84,91,47,53
John,White,IMB,89,25,72,69,98
Eleanor,James,UIB,54,58,49,87,62
Caleb,Wood,IB,31,100,37,46,81
Amelia,Hill,CSB,73,45,79,66,50
Julian,Scott,IMB,97,34,89,22,76
Charlotte,Bryant,UIB,63,92,41,88,32
Isaiah,Mitchell,IB,81,68,52,39,74
Lily,Foster,CSB,56,97,44,85,29
Elijah,Howard,IMB,70,61,36,90,99
Peyton,Washington,UIB,49,82,67,31,75
Xavier,Cook,IB,88,55,93,42,64
Nora,Bailey,CSB,37,72,57,96,47
Owen,Rivera,IMB,59,30,80,77,91
Harper,Cooper,UIB,50,99,33,28,65
Eli,Fisher,IB,78,40,85,92,53
Mila,Harrison,CSB,62,47,71,89,31
Adam,Romero,IMB,34,66,98,42,75
Stella,Patel,UIB,96,39,54,87,68
Carson,Cox,IB,42,55,79,100,27
Luna,Sanders,CSB,88,74,46,29,83
Connor,Henderson,IMB,97,32,53,60,98
Brooklyn,Bishop,UIB,45,90,61,72,31
Andrew,Griffin,IB,58,42,87,65,49
Natalia,Russell,CSB,70,23,74,56,92
Jason,Myers,IMB,81,67,35,48,79
Alexa,Hayes,UIB,37,98,55,93,42
Christian,Long,IB,64,71,82,45,57
Zoey,Gibson,CSB,90,54,38,100,73
Brayden,Graham,IMB,39,89,66,53,31
Maya,Sullivan,UIB,85,77,62,94,25
Jaxon,Ford,IB,48,35,100,71,83
Claire,Wallace,CSB,59,46,88,38,76
Dominic,Cole,IMB,78,92,44,67,50
Eva,Jenkins,UIB,100,29,53,79,61
Riley,Perkins,IB,55,97,31,84,30
Leo,Brooks,CSB,72,40,91,45,99
Hailey,Reynolds,IMB,31,58,77,90,28
Aaron,Fox,UIB,83,72,61,35,48
Kennedy,Stevens,IB,41,66,85,92,53
Sebastian,Webb,CSB,99,33,60,81,51
Melanie,Ward,IMB,76,64,55,89,39
Adrian,Bishop,UIB,67,40,78,95,20
Jasmine,Cook,IB,34,84,91,47,53
Miles,Barnes,CSB,89,25,72,69,98
Savannah,Wood,IMB,54,58,49,87,62
Hudson,Hill,UIB,31,100,37,46,81
1 First Name Last Name Subject Task1 Task2 Task3 Task4 Task5
2 Alice Johnson IB 87 45 68 92 33
3 Bob Smith CSB 56 79 42 88 12
4 Charlie Williams IMB 73 94 35 64 89
5 David Brown UIB 41 59 77 29 83
6 Emma Jones IB 99 21 48 75 56
7 Frank Garcia CSB 32 81 94 55 23
8 Grace Miller IMB 74 53 61 95 39
9 Henry Davis UIB 90 40 28 76 65
10 Isabella Rodriguez IB 57 86 72 49 100
11 Jack Martinez CSB 64 31 59 97 14
12 Liam Hernandez IMB 85 67 50 78 41
13 Mia Lopez UIB 44 92 33 56 81
14 Noah Gonzalez IB 68 39 74 82 47
15 Olivia Wilson CSB 95 20 62 53 34
16 Paul Anderson IMB 29 88 49 31 77
17 Sophia Thomas UIB 81 56 93 42 69
18 Ethan Moore IB 47 77 65 59 92
19 Zoe Taylor CSB 38 95 40 70 58
20 Lucas Harris IMB 99 45 83 62 37
21 Ava Clark UIB 53 66 91 85 29
22 Benjamin Walker IB 71 58 80 34 61
23 Chloe Hall CSB 76 23 67 47 94
24 Daniel Allen IMB 39 82 55 90 73
25 Ella Young UIB 86 32 99 60 25
26 James King IB 42 75 48 93 57
27 Madison Wright CSB 63 54 72 51 88
28 Nathan Scott IMB 91 37 79 68 45
29 Emma Green UIB 50 89 31 77 61
30 Jacob Baker IB 74 69 58 46 97
31 Emily Adams CSB 88 41 66 79 30
32 Samuel Nelson IMB 33 85 92 40 50
33 Sophia Carter UIB 69 47 71 58 94
34 Alexander Mitchell IB 57 98 36 61 82
35 Victoria Perez CSB 92 28 64 73 49
36 William Roberts IMB 45 76 89 55 31
37 Ella Turner UIB 78 59 41 96 68
38 Daniel Phillips IB 60 32 85 71 43
39 Natalie Campbell CSB 55 74 99 28 79
40 Mason Parker IMB 93 50 39 82 66
41 Hannah Evans UIB 48 69 57 95 22
42 Christopher Edwards IB 90 88 34 53 72
43 Lucy Collins CSB 31 46 81 77 56
44 Gabriel Stewart IMB 65 79 62 90 44
45 Avery Morris UIB 80 23 47 36 97
46 Ryan Ross IB 58 71 83 45 74
47 Sophie Reed CSB 99 33 60 81 51
48 Isaac Adams IMB 42 92 30 57 85
49 Leah Bennett UIB 76 64 55 89 39
50 Tyler Barnes IB 67 40 78 95 20
51 Scarlett Morgan CSB 34 84 91 47 53
52 John White IMB 89 25 72 69 98
53 Eleanor James UIB 54 58 49 87 62
54 Caleb Wood IB 31 100 37 46 81
55 Amelia Hill CSB 73 45 79 66 50
56 Julian Scott IMB 97 34 89 22 76
57 Charlotte Bryant UIB 63 92 41 88 32
58 Isaiah Mitchell IB 81 68 52 39 74
59 Lily Foster CSB 56 97 44 85 29
60 Elijah Howard IMB 70 61 36 90 99
61 Peyton Washington UIB 49 82 67 31 75
62 Xavier Cook IB 88 55 93 42 64
63 Nora Bailey CSB 37 72 57 96 47
64 Owen Rivera IMB 59 30 80 77 91
65 Harper Cooper UIB 50 99 33 28 65
66 Eli Fisher IB 78 40 85 92 53
67 Mila Harrison CSB 62 47 71 89 31
68 Adam Romero IMB 34 66 98 42 75
69 Stella Patel UIB 96 39 54 87 68
70 Carson Cox IB 42 55 79 100 27
71 Luna Sanders CSB 88 74 46 29 83
72 Connor Henderson IMB 97 32 53 60 98
73 Brooklyn Bishop UIB 45 90 61 72 31
74 Andrew Griffin IB 58 42 87 65 49
75 Natalia Russell CSB 70 23 74 56 92
76 Jason Myers IMB 81 67 35 48 79
77 Alexa Hayes UIB 37 98 55 93 42
78 Christian Long IB 64 71 82 45 57
79 Zoey Gibson CSB 90 54 38 100 73
80 Brayden Graham IMB 39 89 66 53 31
81 Maya Sullivan UIB 85 77 62 94 25
82 Jaxon Ford IB 48 35 100 71 83
83 Claire Wallace CSB 59 46 88 38 76
84 Dominic Cole IMB 78 92 44 67 50
85 Eva Jenkins UIB 100 29 53 79 61
86 Riley Perkins IB 55 97 31 84 30
87 Leo Brooks CSB 72 40 91 45 99
88 Hailey Reynolds IMB 31 58 77 90 28
89 Aaron Fox UIB 83 72 61 35 48
90 Kennedy Stevens IB 41 66 85 92 53
91 Sebastian Webb CSB 99 33 60 81 51
92 Melanie Ward IMB 76 64 55 89 39
93 Adrian Bishop UIB 67 40 78 95 20
94 Jasmine Cook IB 34 84 91 47 53
95 Miles Barnes CSB 89 25 72 69 98
96 Savannah Wood IMB 54 58 49 87 62
97 Hudson Hill UIB 31 100 37 46 81

View File

@ -0,0 +1,17 @@
import Data.List (nub, sortOn)
import System.IO
-- separator -> Input -> Separated Input
-- split :: Char -> String -> [String]
-- data Entry =
-- averages :: [Entry] -> [(String, Float)]
-- content -> Entries
-- parse :: String -> [Entry]
main :: IO ()
main = do
putStrLn "Enter a filename: "
putStrLn "..."