diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml
index d5275448..f45deaa3 100644
--- a/.github/workflows/haskell.yml
+++ b/.github/workflows/haskell.yml
@@ -1,10 +1,11 @@
+---
#
# .github/workflows/haskell.yml
#
----
name: Haskell Workflow
on: # yamllint disable-line rule:truthy
pull_request:
+
jobs:
stage1:
name: Change Check
@@ -31,7 +32,7 @@ jobs:
# Check if the files are present in the changed file list (added, modified, deleted) then output to stdout.
HAS_DIFF=false
printf "=== Which Haskell files changed? ===\n"
- if printf "%s\n" "${GIT_DIFF}" | grep -E '^(.*[.](hs|cabal)|.*/stack[.]yaml[.].*|.github/workflows/haskell.yml)$'; then
+ if printf "%s\n" "${GIT_DIFF}" | grep -E '^(haskell/.*[.](hs|cabal)|haskell/.*/stack[.]yaml[.].*|.github/workflows/haskell.yml)$'; then
HAS_DIFF=true
fi
printf "\n"
@@ -94,6 +95,6 @@ jobs:
./for_each hlint src --report
- name: Testing with coverage
id: haskell-test-coverage
- run: |
+ run: |-
cd ./haskell
./for_each stack test --coverage
diff --git a/haskell/README.md b/haskell/README.md
index f6c8b979..5aac6918 100644
--- a/haskell/README.md
+++ b/haskell/README.md
@@ -19,3 +19,8 @@
- [space-age](./space-age/README.md)
- [bob](./bob/README.md)
- [triangle](./triangle/README.md)
+- [collatz-conjecture](./collatz-conjecture/README.md)
+- [hamming](./hamming/README.md)
+- [protein-translation](./protein-translation/README.md)
+- [robot-simulator](./robot-simulator/README.md)
+- [yacht](./yacht/README.md)
diff --git a/haskell/collatz-conjecture/.exercism/config.json b/haskell/collatz-conjecture/.exercism/config.json
new file mode 100644
index 00000000..5627086e
--- /dev/null
+++ b/haskell/collatz-conjecture/.exercism/config.json
@@ -0,0 +1,30 @@
+{
+ "authors": [],
+ "contributors": [
+ "guygastineau",
+ "iHiD",
+ "navossoc",
+ "petertseng",
+ "ppartarr",
+ "sshine",
+ "tejasbubane"
+ ],
+ "files": {
+ "solution": [
+ "src/CollatzConjecture.hs",
+ "package.yaml"
+ ],
+ "test": [
+ "test/Tests.hs"
+ ],
+ "example": [
+ ".meta/examples/success-standard/src/CollatzConjecture.hs"
+ ],
+ "invalidator": [
+ "stack.yaml"
+ ]
+ },
+ "blurb": "Calculate the number of steps to reach 1 using the Collatz conjecture.",
+ "source": "An unsolved problem in mathematics named after mathematician Lothar Collatz",
+ "source_url": "https://en.wikipedia.org/wiki/3x_%2B_1_problem"
+}
diff --git a/haskell/collatz-conjecture/.exercism/metadata.json b/haskell/collatz-conjecture/.exercism/metadata.json
new file mode 100644
index 00000000..4a505c95
--- /dev/null
+++ b/haskell/collatz-conjecture/.exercism/metadata.json
@@ -0,0 +1 @@
+{"track":"haskell","exercise":"collatz-conjecture","id":"17d391e3c4b6400cba19f838366e68b9","url":"https://exercism.org/tracks/haskell/exercises/collatz-conjecture","handle":"vpayno","is_requester":true,"auto_approve":false}
\ No newline at end of file
diff --git a/haskell/collatz-conjecture/HELP.md b/haskell/collatz-conjecture/HELP.md
new file mode 100644
index 00000000..ede7a64c
--- /dev/null
+++ b/haskell/collatz-conjecture/HELP.md
@@ -0,0 +1,86 @@
+# Help
+
+## Running the tests
+
+To run the test suite, execute the following command:
+
+```bash
+stack test
+```
+
+#### If you get an error message like this...
+
+```
+No .cabal file found in directory
+```
+
+or
+
+```
+RedownloadInvalidResponse Request {
+...
+}
+ "/home/username/.stack/build-plan/lts-xx.yy.yaml" (Response {responseStatus = Status {statusCode = 404, statusMessage = "Not Found"},
+```
+
+You are probably running an old stack version and need
+to upgrade it. Try running:
+
+```bash
+stack upgrade
+```
+
+Or see other options for upgrading at [Stack documentation](https://docs.haskellstack.org/en/stable/install_and_upgrade/#upgrade).
+
+#### Otherwise, if you get an error message like this...
+
+```
+No compiler found, expected minor version match with...
+Try running "stack setup" to install the correct GHC...
+```
+
+Just do as it says and it will download and install
+the correct compiler version:
+
+```bash
+stack setup
+```
+
+If you want to play with your solution in GHCi, just run the command:
+
+```bash
+stack ghci
+```
+
+## Submitting your solution
+
+You can submit your solution using the `exercism submit src/CollatzConjecture.hs package.yaml` command.
+This command will upload your solution to the Exercism website and print the solution page's URL.
+
+It's possible to submit an incomplete solution which allows you to:
+
+- See how others have completed the exercise
+- Request help from a mentor
+
+## Need to get help?
+
+If you'd like help solving the exercise, check the following pages:
+
+- The [Haskell track's documentation](https://exercism.org/docs/tracks/haskell)
+- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
+- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
+
+Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
+
+## Getting Started
+
+Please refer to the [installation](https://exercism.io/tracks/haskell/installation)
+and [learning](https://exercism.io/tracks/haskell/learning) help pages.
+
+## Feedback, Issues, Pull Requests
+
+The [exercism/haskell](https://github.com/exercism/haskell) repository on
+GitHub is the home for all of the Haskell exercises.
+
+If you have feedback about an exercise, or want to help implementing a new
+one, head over there and create an issue. We'll do our best to help you!
\ No newline at end of file
diff --git a/haskell/collatz-conjecture/README.md b/haskell/collatz-conjecture/README.md
new file mode 100644
index 00000000..1a0f18bc
--- /dev/null
+++ b/haskell/collatz-conjecture/README.md
@@ -0,0 +1,53 @@
+# Collatz Conjecture
+
+Welcome to Collatz Conjecture on Exercism's Haskell Track.
+If you need help running the tests or submitting your code, check out `HELP.md`.
+
+## Instructions
+
+The Collatz Conjecture or 3x+1 problem can be summarized as follows:
+
+Take any positive integer n. If n is even, divide n by 2 to get n / 2. If n is
+odd, multiply n by 3 and add 1 to get 3n + 1. Repeat the process indefinitely.
+The conjecture states that no matter which number you start with, you will
+always reach 1 eventually.
+
+Given a number n, return the number of steps required to reach 1.
+
+## Examples
+
+Starting with n = 12, the steps would be as follows:
+
+0. 12
+1. 6
+2. 3
+3. 10
+4. 5
+5. 16
+6. 8
+7. 4
+8. 2
+9. 1
+
+Resulting in 9 steps. So for input n = 12, the return value would be 9.
+
+## Source
+
+### Contributed to by
+
+- @guygastineau
+- @iHiD
+- @navossoc
+- @petertseng
+- @ppartarr
+- @sshine
+- @tejasbubane
+
+### Based on
+
+An unsolved problem in mathematics named after mathematician Lothar Collatz - https://en.wikipedia.org/wiki/3x_%2B_1_problem
+
+### My Solution
+
+- [my solution](./src/CollatzConjecture.hs)
+- [run-tests](./run-tests-haskell.txt)
diff --git a/haskell/collatz-conjecture/collatz-conjecture.cabal b/haskell/collatz-conjecture/collatz-conjecture.cabal
new file mode 100644
index 00000000..c1f936ea
--- /dev/null
+++ b/haskell/collatz-conjecture/collatz-conjecture.cabal
@@ -0,0 +1,34 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.35.1.
+--
+-- see: https://github.com/sol/hpack
+
+name: collatz-conjecture
+version: 1.2.1.4
+build-type: Simple
+
+library
+ exposed-modules:
+ CollatzConjecture
+ other-modules:
+ Paths_collatz_conjecture
+ hs-source-dirs:
+ src
+ ghc-options: -Wall
+ build-depends:
+ base
+ default-language: Haskell2010
+
+test-suite test
+ type: exitcode-stdio-1.0
+ main-is: Tests.hs
+ other-modules:
+ Paths_collatz_conjecture
+ hs-source-dirs:
+ test
+ build-depends:
+ base
+ , collatz-conjecture
+ , hspec
+ default-language: Haskell2010
diff --git a/haskell/collatz-conjecture/package.yaml b/haskell/collatz-conjecture/package.yaml
new file mode 100644
index 00000000..b1e699e5
--- /dev/null
+++ b/haskell/collatz-conjecture/package.yaml
@@ -0,0 +1,21 @@
+name: collatz-conjecture
+version: 1.2.1.4
+
+dependencies:
+ - base
+
+library:
+ exposed-modules: CollatzConjecture
+ source-dirs: src
+ ghc-options: -Wall
+ # dependencies:
+ # - foo # List here the packages you
+ # - bar # want to use in your solution.
+
+tests:
+ test:
+ main: Tests.hs
+ source-dirs: test
+ dependencies:
+ - collatz-conjecture
+ - hspec
diff --git a/haskell/collatz-conjecture/report.html b/haskell/collatz-conjecture/report.html
new file mode 100644
index 00000000..8cd3f07d
--- /dev/null
+++ b/haskell/collatz-conjecture/report.html
@@ -0,0 +1,186 @@
+
+
+
+
+HLint Report
+
+
+
+
+
+
+
+
+
+
+
+ Report generated by HLint
+v3.3.6
+ - a tool to suggest improvements to your Haskell code.
+
+
+No hints
+
+
+
+
diff --git a/haskell/collatz-conjecture/run-tests-haskell.txt b/haskell/collatz-conjecture/run-tests-haskell.txt
new file mode 100644
index 00000000..d93bc43f
--- /dev/null
+++ b/haskell/collatz-conjecture/run-tests-haskell.txt
@@ -0,0 +1,91 @@
+Running automated test file(s):
+
+
+===============================================================================
+
+Running: hlint src --report
+Writing report to report.html ...
+No hints
+
+real 0m0.168s
+user 0m0.124s
+sys 0m0.035s
+
+===============================================================================
+
+Running: brittany --verbose --write-mode=inplace ./src/CollatzConjecture.hs ./test/Tests.hs
+
+real 0m0.044s
+user 0m0.029s
+sys 0m0.006s
+
+===============================================================================
+
+Running: stack test --coverage
+collatz-conjecture-1.2.1.4: unregistering (local file changes: package.yaml)
+collatz-conjecture> build (lib + test)
+Preprocessing library for collatz-conjecture-1.2.1.4..
+Building library for collatz-conjecture-1.2.1.4..
+Preprocessing test suite 'test' for collatz-conjecture-1.2.1.4..
+Building test suite 'test' for collatz-conjecture-1.2.1.4..
+collatz-conjecture> copy/register
+Installing library in /home/vpayno/git_vpayno/exercism-workspace/haskell/collatz-conjecture/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/lib/x86_64-linux-ghc-9.0.2/collatz-conjecture-1.2.1.4-4M8Uje2PQEMJqOuL7IEZZR
+Registering library for collatz-conjecture-1.2.1.4..
+collatz-conjecture> test (suite: test)
+
+
+collatz
+ zero steps for one
+ divide if even
+ even and odd steps
+ large number of even and odd steps
+ zero is an error
+ negative value is an error
+
+Finished in 0.0001 seconds
+6 examples, 0 failures
+
+
+
+collatz-conjecture> Test suite test passed
+Generating coverage report for collatz-conjecture's test-suite "test".
+100% expressions used (31/31)
+ 75% boolean coverage (3/4)
+ 75% guards (3/4), 1 always True
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (0/0)
+100% alternatives used (4/4)
+100% local declarations used (0/0)
+100% top-level declarations used (2/2)
+The coverage report for collatz-conjecture's test-suite "test" is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/collatz-conjecture/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/collatz-conjecture/test/hpc_index.html.
+Completed 2 action(s).
+Generating unified report.
+100% expressions used (31/31)
+ 75% boolean coverage (3/4)
+ 75% guards (3/4), 1 always True
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (0/0)
+100% alternatives used (4/4)
+100% local declarations used (0/0)
+100% top-level declarations used (2/2)
+The unified report is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/collatz-conjecture/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/combined/all/hpc_index.html.
+
+An index of the generated HTML coverage reports is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/collatz-conjecture/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/index.html.
+
+real 0m1.156s
+user 0m0.782s
+sys 0m0.321s
+
+===============================================================================
+
+Running: misspell .
+
+real 0m0.031s
+user 0m0.054s
+sys 0m0.023s
+
+===============================================================================
+
diff --git a/haskell/collatz-conjecture/src/CollatzConjecture.hs b/haskell/collatz-conjecture/src/CollatzConjecture.hs
new file mode 100644
index 00000000..6214b679
--- /dev/null
+++ b/haskell/collatz-conjecture/src/CollatzConjecture.hs
@@ -0,0 +1,12 @@
+module CollatzConjecture
+ ( collatz
+ ) where
+
+collatz :: Integer -> Maybe Integer
+collatz n = collatz' n 0
+
+collatz' :: Integer -> Integer -> Maybe Integer
+collatz' n steps | n == 1 = Just steps
+ | n <= 0 = Nothing
+ | even n = collatz' (n `div` 2) (steps + 1)
+ | otherwise = collatz' (3 * n + 1) (steps + 1)
diff --git a/haskell/collatz-conjecture/stack.yaml b/haskell/collatz-conjecture/stack.yaml
new file mode 100644
index 00000000..97a3d909
--- /dev/null
+++ b/haskell/collatz-conjecture/stack.yaml
@@ -0,0 +1,2 @@
+---
+resolver: lts-19.27
diff --git a/haskell/collatz-conjecture/stack.yaml.lock b/haskell/collatz-conjecture/stack.yaml.lock
new file mode 100644
index 00000000..d035878d
--- /dev/null
+++ b/haskell/collatz-conjecture/stack.yaml.lock
@@ -0,0 +1,12 @@
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+# https://docs.haskellstack.org/en/stable/lock_files
+
+packages: []
+snapshots:
+- completed:
+ sha256: 1ecad1f0bd2c27de88dbff6572446cfdf647c615d58a7e2e2085c6b7dfc04176
+ size: 619403
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/27.yaml
+ original: lts-19.27
diff --git a/haskell/collatz-conjecture/test/Tests.hs b/haskell/collatz-conjecture/test/Tests.hs
new file mode 100644
index 00000000..a924d179
--- /dev/null
+++ b/haskell/collatz-conjecture/test/Tests.hs
@@ -0,0 +1,48 @@
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+{-# LANGUAGE RecordWildCards #-}
+
+import Data.Foldable ( for_ )
+import Test.Hspec ( Spec
+ , describe
+ , it
+ , shouldBe
+ )
+import Test.Hspec.Runner ( configFastFail
+ , defaultConfig
+ , hspecWith
+ )
+
+import CollatzConjecture ( collatz )
+
+main :: IO ()
+main = hspecWith defaultConfig { configFastFail = True } specs
+
+specs :: Spec
+specs = describe "collatz" $ for_ cases test
+ where
+
+ test Case {..} = it description assertion
+ where assertion = collatz number `shouldBe` expected
+
+
+data Case = Case
+ { description :: String
+ , number :: Integer
+ , expected :: Maybe Integer
+ }
+
+cases :: [Case]
+cases =
+ [ Case { description = "zero steps for one", number = 1, expected = Just 0 }
+ , Case { description = "divide if even", number = 16, expected = Just 4 }
+ , Case { description = "even and odd steps", number = 12, expected = Just 9 }
+ , Case { description = "large number of even and odd steps"
+ , number = 1000000
+ , expected = Just 152
+ }
+ , Case { description = "zero is an error", number = 0, expected = Nothing }
+ , Case { description = "negative value is an error"
+ , number = -15
+ , expected = Nothing
+ }
+ ]
diff --git a/haskell/hamming/.exercism/config.json b/haskell/hamming/.exercism/config.json
new file mode 100644
index 00000000..2521d679
--- /dev/null
+++ b/haskell/hamming/.exercism/config.json
@@ -0,0 +1,34 @@
+{
+ "authors": [
+ "petertseng"
+ ],
+ "contributors": [
+ "chastell",
+ "iHiD",
+ "kytrinyx",
+ "lpalma",
+ "ppartarr",
+ "rbasso",
+ "sshine",
+ "tejasbubane",
+ "tqa236"
+ ],
+ "files": {
+ "solution": [
+ "src/Hamming.hs",
+ "package.yaml"
+ ],
+ "test": [
+ "test/Tests.hs"
+ ],
+ "example": [
+ ".meta/examples/success-standard/src/Hamming.hs"
+ ],
+ "invalidator": [
+ "stack.yaml"
+ ]
+ },
+ "blurb": "Calculate the Hamming difference between two DNA strands.",
+ "source": "The Calculating Point Mutations problem at Rosalind",
+ "source_url": "https://rosalind.info/problems/hamm/"
+}
diff --git a/haskell/hamming/.exercism/metadata.json b/haskell/hamming/.exercism/metadata.json
new file mode 100644
index 00000000..fcd6b074
--- /dev/null
+++ b/haskell/hamming/.exercism/metadata.json
@@ -0,0 +1 @@
+{"track":"haskell","exercise":"hamming","id":"b700b38ddb564020a7e2ec1f437b446c","url":"https://exercism.org/tracks/haskell/exercises/hamming","handle":"vpayno","is_requester":true,"auto_approve":false}
\ No newline at end of file
diff --git a/haskell/hamming/HELP.md b/haskell/hamming/HELP.md
new file mode 100644
index 00000000..fced72bd
--- /dev/null
+++ b/haskell/hamming/HELP.md
@@ -0,0 +1,86 @@
+# Help
+
+## Running the tests
+
+To run the test suite, execute the following command:
+
+```bash
+stack test
+```
+
+#### If you get an error message like this...
+
+```
+No .cabal file found in directory
+```
+
+or
+
+```
+RedownloadInvalidResponse Request {
+...
+}
+ "/home/username/.stack/build-plan/lts-xx.yy.yaml" (Response {responseStatus = Status {statusCode = 404, statusMessage = "Not Found"},
+```
+
+You are probably running an old stack version and need
+to upgrade it. Try running:
+
+```bash
+stack upgrade
+```
+
+Or see other options for upgrading at [Stack documentation](https://docs.haskellstack.org/en/stable/install_and_upgrade/#upgrade).
+
+#### Otherwise, if you get an error message like this...
+
+```
+No compiler found, expected minor version match with...
+Try running "stack setup" to install the correct GHC...
+```
+
+Just do as it says and it will download and install
+the correct compiler version:
+
+```bash
+stack setup
+```
+
+If you want to play with your solution in GHCi, just run the command:
+
+```bash
+stack ghci
+```
+
+## Submitting your solution
+
+You can submit your solution using the `exercism submit src/Hamming.hs package.yaml` command.
+This command will upload your solution to the Exercism website and print the solution page's URL.
+
+It's possible to submit an incomplete solution which allows you to:
+
+- See how others have completed the exercise
+- Request help from a mentor
+
+## Need to get help?
+
+If you'd like help solving the exercise, check the following pages:
+
+- The [Haskell track's documentation](https://exercism.org/docs/tracks/haskell)
+- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
+- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
+
+Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
+
+## Getting Started
+
+Please refer to the [installation](https://exercism.io/tracks/haskell/installation)
+and [learning](https://exercism.io/tracks/haskell/learning) help pages.
+
+## Feedback, Issues, Pull Requests
+
+The [exercism/haskell](https://github.com/exercism/haskell) repository on
+GitHub is the home for all of the Haskell exercises.
+
+If you have feedback about an exercise, or want to help implementing a new
+one, head over there and create an issue. We'll do our best to help you!
\ No newline at end of file
diff --git a/haskell/hamming/README.md b/haskell/hamming/README.md
new file mode 100644
index 00000000..343dcb7e
--- /dev/null
+++ b/haskell/hamming/README.md
@@ -0,0 +1,54 @@
+# Hamming
+
+Welcome to Hamming on Exercism's Haskell Track.
+If you need help running the tests or submitting your code, check out `HELP.md`.
+
+## Instructions
+
+Calculate the Hamming Distance between two DNA strands.
+
+Your body is made up of cells that contain DNA. Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime!
+
+When cells divide, their DNA replicates too. Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. If we compare two strands of DNA and count the differences between them we can see how many mistakes occurred. This is known as the "Hamming Distance".
+
+We read DNA using the letters C,A,G and T. Two strands might look like this:
+
+ GAGCCTACTAACGGGAT
+ CATCGTAATGACGGCCT
+ ^ ^ ^ ^ ^ ^^
+
+They have 7 differences, and therefore the Hamming Distance is 7.
+
+The Hamming Distance is useful for lots of things in science, not just biology, so it's a nice phrase to be familiar with :)
+
+The Hamming distance is only defined for sequences of equal length, so
+an attempt to calculate it between sequences of different lengths should
+not work. The general handling of this situation (e.g., raising an
+exception vs returning a special value) may differ between languages.
+
+## Source
+
+### Created by
+
+- @petertseng
+
+### Contributed to by
+
+- @chastell
+- @iHiD
+- @kytrinyx
+- @lpalma
+- @ppartarr
+- @rbasso
+- @sshine
+- @tejasbubane
+- @tqa236
+
+### Based on
+
+The Calculating Point Mutations problem at Rosalind - https://rosalind.info/problems/hamm/
+
+### My Solution
+
+- [my solution](./src/Hamming.hs)
+- [run-tests](./run-tests-haskell.txt)
diff --git a/haskell/hamming/hamming.cabal b/haskell/hamming/hamming.cabal
new file mode 100644
index 00000000..975eb870
--- /dev/null
+++ b/haskell/hamming/hamming.cabal
@@ -0,0 +1,34 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.35.2.
+--
+-- see: https://github.com/sol/hpack
+
+name: hamming
+version: 2.3.0.10
+build-type: Simple
+
+library
+ exposed-modules:
+ Hamming
+ other-modules:
+ Paths_hamming
+ hs-source-dirs:
+ src
+ ghc-options: -Wall
+ build-depends:
+ base
+ default-language: Haskell2010
+
+test-suite test
+ type: exitcode-stdio-1.0
+ main-is: Tests.hs
+ other-modules:
+ Paths_hamming
+ hs-source-dirs:
+ test
+ build-depends:
+ base
+ , hamming
+ , hspec
+ default-language: Haskell2010
diff --git a/haskell/hamming/package.yaml b/haskell/hamming/package.yaml
new file mode 100644
index 00000000..2f43e527
--- /dev/null
+++ b/haskell/hamming/package.yaml
@@ -0,0 +1,21 @@
+name: hamming
+version: 2.3.0.10
+
+dependencies:
+ - base
+
+library:
+ exposed-modules: Hamming
+ source-dirs: src
+ ghc-options: -Wall
+ # dependencies:
+ # - foo # List here the packages you
+ # - bar # want to use in your solution.
+
+tests:
+ test:
+ main: Tests.hs
+ source-dirs: test
+ dependencies:
+ - hamming
+ - hspec
diff --git a/haskell/hamming/report.html b/haskell/hamming/report.html
new file mode 100644
index 00000000..8cd3f07d
--- /dev/null
+++ b/haskell/hamming/report.html
@@ -0,0 +1,186 @@
+
+
+
+
+HLint Report
+
+
+
+
+
+
+
+
+
+
+
+ Report generated by HLint
+v3.3.6
+ - a tool to suggest improvements to your Haskell code.
+
+
+No hints
+
+
+
+
diff --git a/haskell/hamming/run-tests-haskell.txt b/haskell/hamming/run-tests-haskell.txt
new file mode 100644
index 00000000..be725a5c
--- /dev/null
+++ b/haskell/hamming/run-tests-haskell.txt
@@ -0,0 +1,99 @@
+Running automated test file(s):
+
+
+===============================================================================
+
+Running: hlint src --report
+Writing report to report.html ...
+No hints
+
+real 0m0.127s
+user 0m0.093s
+sys 0m0.032s
+
+===============================================================================
+
+Running: brittany --verbose --write-mode=inplace ./src/Hamming.hs ./test/Tests.hs
+
+real 0m0.044s
+user 0m0.031s
+sys 0m0.010s
+
+===============================================================================
+
+Running: stack test --coverage
+hamming-2.3.0.10: unregistering (dependencies changed)
+hamming> configure (lib + test)
+Configuring hamming-2.3.0.10...
+hamming> build (lib + test)
+Preprocessing library for hamming-2.3.0.10..
+Building library for hamming-2.3.0.10..
+[1 of 2] Compiling Hamming
+[2 of 2] Compiling Paths_hamming
+Preprocessing test suite 'test' for hamming-2.3.0.10..
+Building test suite 'test' for hamming-2.3.0.10..
+Linking .stack-work/dist/x86_64-linux/Cabal-3.4.1.0/build/test/test ...
+hamming> copy/register
+Installing library in /home/vpayno/git_vpayno/exercism-workspace/haskell/hamming/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/lib/x86_64-linux-ghc-9.0.2/hamming-2.3.0.10-87nf3GdVZrPJRt7CGg5EoG
+Registering library for hamming-2.3.0.10..
+hamming> test (suite: test)
+
+
+distance
+ empty strands
+ single letter identical strands
+ single letter different strands
+ long identical strands
+ long different strands
+ disallow first strand longer
+ disallow second strand longer
+ disallow left empty strand
+ disallow right empty strand
+
+Finished in 0.0002 seconds
+9 examples, 0 failures
+
+
+
+hamming> Test suite test passed
+Generating coverage report for hamming's test-suite "test".
+ 94% expressions used (16/17)
+ 66% boolean coverage (2/3)
+ 50% guards (1/2), 1 always True
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (1/1)
+100% alternatives used (2/2)
+100% local declarations used (0/0)
+100% top-level declarations used (1/1)
+The coverage report for hamming's test-suite "test" is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/hamming/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/hamming/test/hpc_index.html.
+Completed 2 action(s).
+Generating unified report.
+ 94% expressions used (16/17)
+ 66% boolean coverage (2/3)
+ 50% guards (1/2), 1 always True
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (1/1)
+100% alternatives used (2/2)
+100% local declarations used (0/0)
+100% top-level declarations used (1/1)
+The unified report is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/hamming/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/combined/all/hpc_index.html.
+
+An index of the generated HTML coverage reports is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/hamming/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/index.html.
+
+real 0m2.445s
+user 0m1.620s
+sys 0m0.693s
+
+===============================================================================
+
+Running: misspell .
+
+real 0m0.024s
+user 0m0.040s
+sys 0m0.011s
+
+===============================================================================
+
diff --git a/haskell/hamming/src/Hamming.hs b/haskell/hamming/src/Hamming.hs
new file mode 100644
index 00000000..d765c2d0
--- /dev/null
+++ b/haskell/hamming/src/Hamming.hs
@@ -0,0 +1,9 @@
+module Hamming
+ ( distance
+ ) where
+
+distance :: String -> String -> Maybe Int
+distance lhs rhs
+ | length lhs /= length rhs = Nothing
+ | otherwise = Just
+ (length [ nucleotide | nucleotide <- zip lhs rhs, uncurry (/=) nucleotide ])
diff --git a/haskell/hamming/stack.yaml b/haskell/hamming/stack.yaml
new file mode 100644
index 00000000..97a3d909
--- /dev/null
+++ b/haskell/hamming/stack.yaml
@@ -0,0 +1,2 @@
+---
+resolver: lts-19.27
diff --git a/haskell/hamming/stack.yaml.lock b/haskell/hamming/stack.yaml.lock
new file mode 100644
index 00000000..d035878d
--- /dev/null
+++ b/haskell/hamming/stack.yaml.lock
@@ -0,0 +1,12 @@
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+# https://docs.haskellstack.org/en/stable/lock_files
+
+packages: []
+snapshots:
+- completed:
+ sha256: 1ecad1f0bd2c27de88dbff6572446cfdf647c615d58a7e2e2085c6b7dfc04176
+ size: 619403
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/27.yaml
+ original: lts-19.27
diff --git a/haskell/hamming/test/Tests.hs b/haskell/hamming/test/Tests.hs
new file mode 100644
index 00000000..49cafccc
--- /dev/null
+++ b/haskell/hamming/test/Tests.hs
@@ -0,0 +1,83 @@
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+{-# LANGUAGE RecordWildCards #-}
+
+import Data.Foldable ( for_ )
+import Test.Hspec ( Spec
+ , describe
+ , it
+ , shouldBe
+ )
+import Test.Hspec.Runner ( configFastFail
+ , defaultConfig
+ , hspecWith
+ )
+
+import Hamming ( distance )
+
+main :: IO ()
+main = hspecWith defaultConfig { configFastFail = True } specs
+
+specs :: Spec
+specs = describe "distance" $ for_ cases test
+ where
+
+ test Case {..} = it description assertion
+ where
+ assertion = expression `shouldBe` fromIntegral <$> expected
+ expression = distance strand1 strand2
+
+data Case = Case
+ { description :: String
+ , strand1 :: String
+ , strand2 :: String
+ , expected :: Maybe Integer
+ }
+
+cases :: [Case]
+cases =
+ [ Case { description = "empty strands"
+ , strand1 = ""
+ , strand2 = ""
+ , expected = Just 0
+ }
+ , Case { description = "single letter identical strands"
+ , strand1 = "A"
+ , strand2 = "A"
+ , expected = Just 0
+ }
+ , Case { description = "single letter different strands"
+ , strand1 = "G"
+ , strand2 = "T"
+ , expected = Just 1
+ }
+ , Case { description = "long identical strands"
+ , strand1 = "GGACTGAAATCTG"
+ , strand2 = "GGACTGAAATCTG"
+ , expected = Just 0
+ }
+ , Case { description = "long different strands"
+ , strand1 = "GGACGGATTCTG"
+ , strand2 = "AGGACGGATTCT"
+ , expected = Just 9
+ }
+ , Case { description = "disallow first strand longer"
+ , strand1 = "AATG"
+ , strand2 = "AAA"
+ , expected = Nothing
+ }
+ , Case { description = "disallow second strand longer"
+ , strand1 = "ATA"
+ , strand2 = "AGTG"
+ , expected = Nothing
+ }
+ , Case { description = "disallow left empty strand"
+ , strand1 = ""
+ , strand2 = "G"
+ , expected = Nothing
+ }
+ , Case { description = "disallow right empty strand"
+ , strand1 = "G"
+ , strand2 = ""
+ , expected = Nothing
+ }
+ ]
diff --git a/haskell/protein-translation/.exercism/config.json b/haskell/protein-translation/.exercism/config.json
new file mode 100644
index 00000000..a409bf85
--- /dev/null
+++ b/haskell/protein-translation/.exercism/config.json
@@ -0,0 +1,29 @@
+{
+ "authors": [
+ "Average-user"
+ ],
+ "contributors": [
+ "iHiD",
+ "petertseng",
+ "ppartarr",
+ "sshine",
+ "tejasbubane"
+ ],
+ "files": {
+ "solution": [
+ "src/ProteinTranslation.hs",
+ "package.yaml"
+ ],
+ "test": [
+ "test/Tests.hs"
+ ],
+ "example": [
+ ".meta/examples/success-standard/src/ProteinTranslation.hs"
+ ],
+ "invalidator": [
+ "stack.yaml"
+ ]
+ },
+ "blurb": "Translate RNA sequences into proteins.",
+ "source": "Tyler Long"
+}
diff --git a/haskell/protein-translation/.exercism/metadata.json b/haskell/protein-translation/.exercism/metadata.json
new file mode 100644
index 00000000..f0cc2c10
--- /dev/null
+++ b/haskell/protein-translation/.exercism/metadata.json
@@ -0,0 +1 @@
+{"track":"haskell","exercise":"protein-translation","id":"549646afc02849b8868a8b46b9d1f833","url":"https://exercism.org/tracks/haskell/exercises/protein-translation","handle":"vpayno","is_requester":true,"auto_approve":false}
\ No newline at end of file
diff --git a/haskell/protein-translation/HELP.md b/haskell/protein-translation/HELP.md
new file mode 100644
index 00000000..acfb2a65
--- /dev/null
+++ b/haskell/protein-translation/HELP.md
@@ -0,0 +1,86 @@
+# Help
+
+## Running the tests
+
+To run the test suite, execute the following command:
+
+```bash
+stack test
+```
+
+#### If you get an error message like this...
+
+```
+No .cabal file found in directory
+```
+
+or
+
+```
+RedownloadInvalidResponse Request {
+...
+}
+ "/home/username/.stack/build-plan/lts-xx.yy.yaml" (Response {responseStatus = Status {statusCode = 404, statusMessage = "Not Found"},
+```
+
+You are probably running an old stack version and need
+to upgrade it. Try running:
+
+```bash
+stack upgrade
+```
+
+Or see other options for upgrading at [Stack documentation](https://docs.haskellstack.org/en/stable/install_and_upgrade/#upgrade).
+
+#### Otherwise, if you get an error message like this...
+
+```
+No compiler found, expected minor version match with...
+Try running "stack setup" to install the correct GHC...
+```
+
+Just do as it says and it will download and install
+the correct compiler version:
+
+```bash
+stack setup
+```
+
+If you want to play with your solution in GHCi, just run the command:
+
+```bash
+stack ghci
+```
+
+## Submitting your solution
+
+You can submit your solution using the `exercism submit src/ProteinTranslation.hs package.yaml` command.
+This command will upload your solution to the Exercism website and print the solution page's URL.
+
+It's possible to submit an incomplete solution which allows you to:
+
+- See how others have completed the exercise
+- Request help from a mentor
+
+## Need to get help?
+
+If you'd like help solving the exercise, check the following pages:
+
+- The [Haskell track's documentation](https://exercism.org/docs/tracks/haskell)
+- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
+- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
+
+Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
+
+## Getting Started
+
+Please refer to the [installation](https://exercism.io/tracks/haskell/installation)
+and [learning](https://exercism.io/tracks/haskell/learning) help pages.
+
+## Feedback, Issues, Pull Requests
+
+The [exercism/haskell](https://github.com/exercism/haskell) repository on
+GitHub is the home for all of the Haskell exercises.
+
+If you have feedback about an exercise, or want to help implementing a new
+one, head over there and create an issue. We'll do our best to help you!
\ No newline at end of file
diff --git a/haskell/protein-translation/README.md b/haskell/protein-translation/README.md
new file mode 100644
index 00000000..d92e59ff
--- /dev/null
+++ b/haskell/protein-translation/README.md
@@ -0,0 +1,70 @@
+# Protein Translation
+
+Welcome to Protein Translation on Exercism's Haskell Track.
+If you need help running the tests or submitting your code, check out `HELP.md`.
+
+## Instructions
+
+Translate RNA sequences into proteins.
+
+RNA can be broken into three nucleotide sequences called codons, and then translated to a polypeptide like so:
+
+RNA: `"AUGUUUUCU"` => translates to
+
+Codons: `"AUG", "UUU", "UCU"`
+=> which become a polypeptide with the following sequence =>
+
+Protein: `"Methionine", "Phenylalanine", "Serine"`
+
+There are 64 codons which in turn correspond to 20 amino acids; however, all of the codon sequences and resulting amino acids are not important in this exercise. If it works for one codon, the program should work for all of them.
+However, feel free to expand the list in the test suite to include them all.
+
+There are also three terminating codons (also known as 'STOP' codons); if any of these codons are encountered (by the ribosome), all translation ends and the protein is terminated.
+
+All subsequent codons after are ignored, like this:
+
+RNA: `"AUGUUUUCUUAAAUG"` =>
+
+Codons: `"AUG", "UUU", "UCU", "UAA", "AUG"` =>
+
+Protein: `"Methionine", "Phenylalanine", "Serine"`
+
+Note the stop codon `"UAA"` terminates the translation and the final methionine is not translated into the protein sequence.
+
+Below are the codons and resulting Amino Acids needed for the exercise.
+
+Codon | Protein
+:--- | :---
+AUG | Methionine
+UUU, UUC | Phenylalanine
+UUA, UUG | Leucine
+UCU, UCC, UCA, UCG | Serine
+UAU, UAC | Tyrosine
+UGU, UGC | Cysteine
+UGG | Tryptophan
+UAA, UAG, UGA | STOP
+
+Learn more about [protein translation on Wikipedia](https://en.wikipedia.org/wiki/Translation_(biology))
+
+## Source
+
+### Created by
+
+- @Average-user
+
+### Contributed to by
+
+- @iHiD
+- @petertseng
+- @ppartarr
+- @sshine
+- @tejasbubane
+
+### Based on
+
+Tyler Long
+
+### My Solution
+
+- [my solution](./src/ProteinTranslation.hs)
+- [run-tests](./run-tests-haskell.txt)
diff --git a/haskell/protein-translation/package.yaml b/haskell/protein-translation/package.yaml
new file mode 100644
index 00000000..fa3ff3fe
--- /dev/null
+++ b/haskell/protein-translation/package.yaml
@@ -0,0 +1,21 @@
+name: protein-translation
+version: 1.1.1.3
+
+dependencies:
+ - base
+
+library:
+ exposed-modules: ProteinTranslation
+ source-dirs: src
+ ghc-options: -Wall
+ # dependencies:
+ # - foo # List here the packages you
+ # - bar # want to use in your solution.
+
+tests:
+ test:
+ main: Tests.hs
+ source-dirs: test
+ dependencies:
+ - protein-translation
+ - hspec
diff --git a/haskell/protein-translation/protein-translation.cabal b/haskell/protein-translation/protein-translation.cabal
new file mode 100644
index 00000000..038e37d3
--- /dev/null
+++ b/haskell/protein-translation/protein-translation.cabal
@@ -0,0 +1,34 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.35.2.
+--
+-- see: https://github.com/sol/hpack
+
+name: protein-translation
+version: 1.1.1.3
+build-type: Simple
+
+library
+ exposed-modules:
+ ProteinTranslation
+ other-modules:
+ Paths_protein_translation
+ hs-source-dirs:
+ src
+ ghc-options: -Wall
+ build-depends:
+ base
+ default-language: Haskell2010
+
+test-suite test
+ type: exitcode-stdio-1.0
+ main-is: Tests.hs
+ other-modules:
+ Paths_protein_translation
+ hs-source-dirs:
+ test
+ build-depends:
+ base
+ , hspec
+ , protein-translation
+ default-language: Haskell2010
diff --git a/haskell/protein-translation/report.html b/haskell/protein-translation/report.html
new file mode 100644
index 00000000..8cd3f07d
--- /dev/null
+++ b/haskell/protein-translation/report.html
@@ -0,0 +1,186 @@
+
+
+
+
+HLint Report
+
+
+
+
+
+
+
+
+
+
+
+ Report generated by HLint
+v3.3.6
+ - a tool to suggest improvements to your Haskell code.
+
+
+No hints
+
+
+
+
diff --git a/haskell/protein-translation/run-tests-haskell.txt b/haskell/protein-translation/run-tests-haskell.txt
new file mode 100644
index 00000000..e23ac223
--- /dev/null
+++ b/haskell/protein-translation/run-tests-haskell.txt
@@ -0,0 +1,113 @@
+Running automated test file(s):
+
+
+===============================================================================
+
+Running: hlint src --report
+Writing report to report.html ...
+No hints
+
+real 0m0.146s
+user 0m0.118s
+sys 0m0.020s
+
+===============================================================================
+
+Running: brittany --verbose --write-mode=inplace ./src/ProteinTranslation.hs ./test/Tests.hs
+
+real 0m0.083s
+user 0m0.060s
+sys 0m0.010s
+
+===============================================================================
+
+Running: stack test --coverage
+protein-translation-1.1.1.3: unregistering (dependencies changed)
+protein-translation> configure (lib + test)
+Configuring protein-translation-1.1.1.3...
+protein-translation> build (lib + test)
+Preprocessing library for protein-translation-1.1.1.3..
+Building library for protein-translation-1.1.1.3..
+[1 of 2] Compiling ProteinTranslation
+[2 of 2] Compiling Paths_protein_translation
+Preprocessing test suite 'test' for protein-translation-1.1.1.3..
+Building test suite 'test' for protein-translation-1.1.1.3..
+Linking .stack-work/dist/x86_64-linux/Cabal-3.4.1.0/build/test/test ...
+protein-translation> copy/register
+Installing library in /home/vpayno/git_vpayno/exercism-workspace/haskell/protein-translation/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/lib/x86_64-linux-ghc-9.0.2/protein-translation-1.1.1.3-8ZRJrugvz688FlGmFZTfVL
+Registering library for protein-translation-1.1.1.3..
+protein-translation> test (suite: test)
+
+
+proteins
+ Methionine RNA sequence
+ Phenylalanine RNA sequence 1
+ Phenylalanine RNA sequence 2
+ Leucine RNA sequence 1
+ Leucine RNA sequence 2
+ Serine RNA sequence 1
+ Serine RNA sequence 2
+ Serine RNA sequence 3
+ Serine RNA sequence 4
+ Tyrosine RNA sequence 1
+ Tyrosine RNA sequence 2
+ Cysteine RNA sequence 1
+ Cysteine RNA sequence 2
+ Tryptophan RNA sequence
+ STOP codon RNA sequence 1
+ STOP codon RNA sequence 2
+ STOP codon RNA sequence 3
+ Translate RNA strand into correct protein list
+ Translation stops if STOP codon at beginning of sequence
+ Translation stops if STOP codon at end of two-codon sequence
+ Translation stops if STOP codon at end of three-codon sequence
+ Translation stops if STOP codon in middle of three-codon sequence
+ Translation stops if STOP codon in middle of six-codon sequence
+
+Finished in 0.0003 seconds
+23 examples, 0 failures
+
+
+
+protein-translation> Test suite test passed
+Generating coverage report for protein-translation's test-suite "test".
+ 93% expressions used (81/87)
+ 50% boolean coverage (1/2)
+ 50% guards (1/2), 1 always True
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (0/0)
+ 60% alternatives used (6/10)
+100% local declarations used (0/0)
+100% top-level declarations used (3/3)
+The coverage report for protein-translation's test-suite "test" is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/protein-translation/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/protein-translation/test/hpc_index.html.
+Completed 2 action(s).
+Generating unified report.
+ 93% expressions used (81/87)
+ 50% boolean coverage (1/2)
+ 50% guards (1/2), 1 always True
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (0/0)
+ 60% alternatives used (6/10)
+100% local declarations used (0/0)
+100% top-level declarations used (3/3)
+The unified report is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/protein-translation/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/combined/all/hpc_index.html.
+
+An index of the generated HTML coverage reports is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/protein-translation/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/index.html.
+
+real 0m2.644s
+user 0m1.830s
+sys 0m0.723s
+
+===============================================================================
+
+Running: misspell .
+
+real 0m0.029s
+user 0m0.062s
+sys 0m0.013s
+
+===============================================================================
+
diff --git a/haskell/protein-translation/src/ProteinTranslation.hs b/haskell/protein-translation/src/ProteinTranslation.hs
new file mode 100644
index 00000000..43a7a5ea
--- /dev/null
+++ b/haskell/protein-translation/src/ProteinTranslation.hs
@@ -0,0 +1,38 @@
+module ProteinTranslation
+ ( proteins
+ ) where
+
+codonToProtein :: [(String, String)]
+codonToProtein =
+ [ ("AUG", "Methionine")
+ , ("UUU", "Phenylalanine")
+ , ("UUC", "Phenylalanine")
+ , ("UUA", "Leucine")
+ , ("UUG", "Leucine")
+ , ("UCU", "Serine")
+ , ("UCC", "Serine")
+ , ("UCA", "Serine")
+ , ("UCG", "Serine")
+ , ("UAU", "Tyrosine")
+ , ("UAC", "Tyrosine")
+ , ("UGU", "Cysteine")
+ , ("UGC", "Cysteine")
+ , ("UGG", "Tryptophan")
+ , ("UAA", "STOP")
+ , ("UAG", "STOP")
+ , ("UGA", "STOP")
+ ]
+
+getCodons :: String -> [(String, String)] -> Maybe String
+getCodons _ [] = Nothing
+getCodons codon ((c, a) : xs) | codon == c = Just a
+ | otherwise = getCodons codon xs
+
+proteins :: String -> Maybe [String]
+proteins [] = Just []
+proteins [_] = Just []
+proteins [_, _] = Just []
+proteins (x : y : z : xs) = case getCodons [x, y, z] codonToProtein of
+ Just "STOP" -> Just []
+ Just codon -> proteins xs >>= (\protein -> return $ codon : protein)
+ Nothing -> Nothing
diff --git a/haskell/protein-translation/stack.yaml b/haskell/protein-translation/stack.yaml
new file mode 100644
index 00000000..97a3d909
--- /dev/null
+++ b/haskell/protein-translation/stack.yaml
@@ -0,0 +1,2 @@
+---
+resolver: lts-19.27
diff --git a/haskell/protein-translation/stack.yaml.lock b/haskell/protein-translation/stack.yaml.lock
new file mode 100644
index 00000000..d035878d
--- /dev/null
+++ b/haskell/protein-translation/stack.yaml.lock
@@ -0,0 +1,12 @@
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+# https://docs.haskellstack.org/en/stable/lock_files
+
+packages: []
+snapshots:
+- completed:
+ sha256: 1ecad1f0bd2c27de88dbff6572446cfdf647c615d58a7e2e2085c6b7dfc04176
+ size: 619403
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/27.yaml
+ original: lts-19.27
diff --git a/haskell/protein-translation/test/Tests.hs b/haskell/protein-translation/test/Tests.hs
new file mode 100644
index 00000000..c250b9d1
--- /dev/null
+++ b/haskell/protein-translation/test/Tests.hs
@@ -0,0 +1,136 @@
+{-# LANGUAGE RecordWildCards #-}
+
+import Data.Foldable ( for_ )
+import Test.Hspec ( Spec
+ , describe
+ , it
+ , shouldBe
+ )
+import Test.Hspec.Runner ( configFastFail
+ , defaultConfig
+ , hspecWith
+ )
+
+import ProteinTranslation ( proteins )
+
+main :: IO ()
+main = hspecWith defaultConfig { configFastFail = True } specs
+
+specs :: Spec
+specs = describe "proteins" $ for_ cases test
+ where
+
+ test Case {..} = it description assertion
+ where assertion = proteins input `shouldBe` expected
+
+
+data Case = Case
+ { description :: String
+ , input :: String
+ , expected :: Maybe [String]
+ }
+
+cases :: [Case]
+cases =
+ [ Case { description = "Methionine RNA sequence"
+ , input = "AUG"
+ , expected = Just ["Methionine"]
+ }
+ , Case { description = "Phenylalanine RNA sequence 1"
+ , input = "UUU"
+ , expected = Just ["Phenylalanine"]
+ }
+ , Case { description = "Phenylalanine RNA sequence 2"
+ , input = "UUC"
+ , expected = Just ["Phenylalanine"]
+ }
+ , Case { description = "Leucine RNA sequence 1"
+ , input = "UUA"
+ , expected = Just ["Leucine"]
+ }
+ , Case { description = "Leucine RNA sequence 2"
+ , input = "UUG"
+ , expected = Just ["Leucine"]
+ }
+ , Case { description = "Serine RNA sequence 1"
+ , input = "UCU"
+ , expected = Just ["Serine"]
+ }
+ , Case { description = "Serine RNA sequence 2"
+ , input = "UCC"
+ , expected = Just ["Serine"]
+ }
+ , Case { description = "Serine RNA sequence 3"
+ , input = "UCA"
+ , expected = Just ["Serine"]
+ }
+ , Case { description = "Serine RNA sequence 4"
+ , input = "UCG"
+ , expected = Just ["Serine"]
+ }
+ , Case { description = "Tyrosine RNA sequence 1"
+ , input = "UAU"
+ , expected = Just ["Tyrosine"]
+ }
+ , Case { description = "Tyrosine RNA sequence 2"
+ , input = "UAC"
+ , expected = Just ["Tyrosine"]
+ }
+ , Case { description = "Cysteine RNA sequence 1"
+ , input = "UGU"
+ , expected = Just ["Cysteine"]
+ }
+ , Case { description = "Cysteine RNA sequence 2"
+ , input = "UGC"
+ , expected = Just ["Cysteine"]
+ }
+ , Case { description = "Tryptophan RNA sequence"
+ , input = "UGG"
+ , expected = Just ["Tryptophan"]
+ }
+ , Case { description = "STOP codon RNA sequence 1"
+ , input = "UAA"
+ , expected = Just []
+ }
+ , Case { description = "STOP codon RNA sequence 2"
+ , input = "UAG"
+ , expected = Just []
+ }
+ , Case { description = "STOP codon RNA sequence 3"
+ , input = "UGA"
+ , expected = Just []
+ }
+ , Case { description = "Translate RNA strand into correct protein list"
+ , input = "AUGUUUUGG"
+ , expected = Just ["Methionine", "Phenylalanine", "Tryptophan"]
+ }
+ , Case
+ { description = "Translation stops if STOP codon at beginning of sequence"
+ , input = "UAGUGG"
+ , expected = Just []
+ }
+ , Case
+ { description =
+ "Translation stops if STOP codon at end of two-codon sequence"
+ , input = "UGGUAG"
+ , expected = Just ["Tryptophan"]
+ }
+ , Case
+ { description =
+ "Translation stops if STOP codon at end of three-codon sequence"
+ , input = "AUGUUUUAA"
+ , expected = Just ["Methionine", "Phenylalanine"]
+ }
+ , Case
+ { description =
+ "Translation stops if STOP codon in middle of three-codon sequence"
+ , input = "UGGUAGUGG"
+ , expected = Just ["Tryptophan"]
+ }
+ , Case
+ { description =
+ "Translation stops if STOP codon in middle of six-codon sequence"
+ , input = "UGGUGUUAUUAAUGGUUU"
+ , expected = Just ["Tryptophan", "Cysteine", "Tyrosine"]
+ }
+ ]
diff --git a/haskell/robot-simulator/.exercism/config.json b/haskell/robot-simulator/.exercism/config.json
new file mode 100644
index 00000000..7b7587de
--- /dev/null
+++ b/haskell/robot-simulator/.exercism/config.json
@@ -0,0 +1,33 @@
+{
+ "authors": [
+ "etrepum"
+ ],
+ "contributors": [
+ "iHiD",
+ "kytrinyx",
+ "lpalma",
+ "petertseng",
+ "ppartarr",
+ "rbasso",
+ "sshine",
+ "tejasbubane",
+ "thalesmg"
+ ],
+ "files": {
+ "solution": [
+ "src/Robot.hs",
+ "package.yaml"
+ ],
+ "test": [
+ "test/Tests.hs"
+ ],
+ "example": [
+ ".meta/examples/success-standard/src/Robot.hs"
+ ],
+ "invalidator": [
+ "stack.yaml"
+ ]
+ },
+ "blurb": "Write a robot simulator.",
+ "source": "Inspired by an interview question at a famous company."
+}
diff --git a/haskell/robot-simulator/.exercism/metadata.json b/haskell/robot-simulator/.exercism/metadata.json
new file mode 100644
index 00000000..05dfe623
--- /dev/null
+++ b/haskell/robot-simulator/.exercism/metadata.json
@@ -0,0 +1 @@
+{"track":"haskell","exercise":"robot-simulator","id":"49571a0987ed4b73935526fc0448b3c8","url":"https://exercism.org/tracks/haskell/exercises/robot-simulator","handle":"vpayno","is_requester":true,"auto_approve":false}
\ No newline at end of file
diff --git a/haskell/robot-simulator/HELP.md b/haskell/robot-simulator/HELP.md
new file mode 100644
index 00000000..977dd824
--- /dev/null
+++ b/haskell/robot-simulator/HELP.md
@@ -0,0 +1,86 @@
+# Help
+
+## Running the tests
+
+To run the test suite, execute the following command:
+
+```bash
+stack test
+```
+
+#### If you get an error message like this...
+
+```
+No .cabal file found in directory
+```
+
+or
+
+```
+RedownloadInvalidResponse Request {
+...
+}
+ "/home/username/.stack/build-plan/lts-xx.yy.yaml" (Response {responseStatus = Status {statusCode = 404, statusMessage = "Not Found"},
+```
+
+You are probably running an old stack version and need
+to upgrade it. Try running:
+
+```bash
+stack upgrade
+```
+
+Or see other options for upgrading at [Stack documentation](https://docs.haskellstack.org/en/stable/install_and_upgrade/#upgrade).
+
+#### Otherwise, if you get an error message like this...
+
+```
+No compiler found, expected minor version match with...
+Try running "stack setup" to install the correct GHC...
+```
+
+Just do as it says and it will download and install
+the correct compiler version:
+
+```bash
+stack setup
+```
+
+If you want to play with your solution in GHCi, just run the command:
+
+```bash
+stack ghci
+```
+
+## Submitting your solution
+
+You can submit your solution using the `exercism submit src/Robot.hs package.yaml` command.
+This command will upload your solution to the Exercism website and print the solution page's URL.
+
+It's possible to submit an incomplete solution which allows you to:
+
+- See how others have completed the exercise
+- Request help from a mentor
+
+## Need to get help?
+
+If you'd like help solving the exercise, check the following pages:
+
+- The [Haskell track's documentation](https://exercism.org/docs/tracks/haskell)
+- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
+- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
+
+Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
+
+## Getting Started
+
+Please refer to the [installation](https://exercism.io/tracks/haskell/installation)
+and [learning](https://exercism.io/tracks/haskell/learning) help pages.
+
+## Feedback, Issues, Pull Requests
+
+The [exercism/haskell](https://github.com/exercism/haskell) repository on
+GitHub is the home for all of the Haskell exercises.
+
+If you have feedback about an exercise, or want to help implementing a new
+one, head over there and create an issue. We'll do our best to help you!
\ No newline at end of file
diff --git a/haskell/robot-simulator/README.md b/haskell/robot-simulator/README.md
new file mode 100644
index 00000000..73520c22
--- /dev/null
+++ b/haskell/robot-simulator/README.md
@@ -0,0 +1,74 @@
+# Robot Simulator
+
+Welcome to Robot Simulator on Exercism's Haskell Track.
+If you need help running the tests or submitting your code, check out `HELP.md`.
+
+## Instructions
+
+Write a robot simulator.
+
+A robot factory's test facility needs a program to verify robot movements.
+
+The robots have three possible movements:
+
+- turn right
+- turn left
+- advance
+
+Robots are placed on a hypothetical infinite grid, facing a particular
+direction (north, east, south, or west) at a set of {x,y} coordinates,
+e.g., {3,8}, with coordinates increasing to the north and east.
+
+The robot then receives a number of instructions, at which point the
+testing facility verifies the robot's new position, and in which
+direction it is pointing.
+
+- The letter-string "RAALAL" means:
+ - Turn right
+ - Advance twice
+ - Turn left
+ - Advance once
+ - Turn left yet again
+- Say a robot starts at {7, 3} facing north. Then running this stream
+ of instructions should leave it at {9, 4} facing west.
+
+To complete this exercise, you need to create the data type `Robot`,
+and implement the following functions:
+
+- `bearing`
+- `coordinates`
+- `mkRobot`
+- `simulate`
+- `turnLeft`
+- `turnRight`
+
+You will find a dummy data declaration and type signatures already in place,
+but it is up to you to define the functions and create a meaningful data type,
+newtype or type synonym.
+
+## Source
+
+### Created by
+
+- @etrepum
+
+### Contributed to by
+
+- @iHiD
+- @kytrinyx
+- @lpalma
+- @petertseng
+- @ppartarr
+- @rbasso
+- @sshine
+- @tejasbubane
+- @thalesmg
+
+### Based on
+
+Inspired by an interview question at a famous company.
+
+### My Solution
+
+- [my solution](./src/Robot.hs)
+- [run-tests](./run-tests-haskell.txt)
diff --git a/haskell/robot-simulator/package.yaml b/haskell/robot-simulator/package.yaml
new file mode 100644
index 00000000..ec8ac351
--- /dev/null
+++ b/haskell/robot-simulator/package.yaml
@@ -0,0 +1,21 @@
+name: robot-simulator
+version: 3.2.0.8
+
+dependencies:
+ - base
+
+library:
+ exposed-modules: Robot
+ source-dirs: src
+ ghc-options: -Wall
+ # dependencies:
+ # - foo # List here the packages you
+ # - bar # want to use in your solution.
+
+tests:
+ test:
+ main: Tests.hs
+ source-dirs: test
+ dependencies:
+ - robot-simulator
+ - hspec
diff --git a/haskell/robot-simulator/report.html b/haskell/robot-simulator/report.html
new file mode 100644
index 00000000..8cd3f07d
--- /dev/null
+++ b/haskell/robot-simulator/report.html
@@ -0,0 +1,186 @@
+
+
+
+
+HLint Report
+
+
+
+
+
+
+
+
+
+
+
+ Report generated by HLint
+v3.3.6
+ - a tool to suggest improvements to your Haskell code.
+
+
+No hints
+
+
+
+
diff --git a/haskell/robot-simulator/robot-simulator.cabal b/haskell/robot-simulator/robot-simulator.cabal
new file mode 100644
index 00000000..a061b3b8
--- /dev/null
+++ b/haskell/robot-simulator/robot-simulator.cabal
@@ -0,0 +1,34 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.35.2.
+--
+-- see: https://github.com/sol/hpack
+
+name: robot-simulator
+version: 3.2.0.8
+build-type: Simple
+
+library
+ exposed-modules:
+ Robot
+ other-modules:
+ Paths_robot_simulator
+ hs-source-dirs:
+ src
+ ghc-options: -Wall
+ build-depends:
+ base
+ default-language: Haskell2010
+
+test-suite test
+ type: exitcode-stdio-1.0
+ main-is: Tests.hs
+ other-modules:
+ Paths_robot_simulator
+ hs-source-dirs:
+ test
+ build-depends:
+ base
+ , hspec
+ , robot-simulator
+ default-language: Haskell2010
diff --git a/haskell/robot-simulator/run-tests-haskell.txt b/haskell/robot-simulator/run-tests-haskell.txt
new file mode 100644
index 00000000..a59bf83c
--- /dev/null
+++ b/haskell/robot-simulator/run-tests-haskell.txt
@@ -0,0 +1,138 @@
+Running automated test file(s):
+
+
+===============================================================================
+
+Running: hlint src --report
+Writing report to report.html ...
+No hints
+
+real 0m0.167s
+user 0m0.131s
+sys 0m0.027s
+
+===============================================================================
+
+Running: brittany --verbose --write-mode=inplace ./src/Robot.hs ./test/Tests.hs
+
+real 0m0.094s
+user 0m0.076s
+sys 0m0.010s
+
+===============================================================================
+
+Running: stack test --coverage
+robot-simulator-3.2.0.8: unregistering (dependencies changed)
+robot-simulator> configure (lib + test)
+Configuring robot-simulator-3.2.0.8...
+robot-simulator> build (lib + test)
+Preprocessing library for robot-simulator-3.2.0.8..
+Building library for robot-simulator-3.2.0.8..
+[1 of 2] Compiling Robot
+[2 of 2] Compiling Paths_robot_simulator
+Preprocessing test suite 'test' for robot-simulator-3.2.0.8..
+Building test suite 'test' for robot-simulator-3.2.0.8..
+[1 of 2] Compiling Main [HPC flags changed]
+[2 of 2] Compiling Paths_robot_simulator [HPC flags changed]
+Linking .stack-work/dist/x86_64-linux/Cabal-3.4.1.0/build/test/test ...
+robot-simulator> copy/register
+Installing library in /home/vpayno/git_vpayno/exercism-workspace/haskell/robot-simulator/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/lib/x86_64-linux-ghc-9.0.2/robot-simulator-3.2.0.8-5KG2YVkK1Y02Tr96mMJ3Ue
+Registering library for robot-simulator-3.2.0.8..
+robot-simulator> test (suite: test)
+
+
+mkRobot
+ Create robot at origin facing north
+ Create robot at negative position facing south
+Rotating clockwise
+ from North
+ should change direction
+ shouldn't change position
+ from East
+ should change direction
+ shouldn't change position
+ from South
+ should change direction
+ shouldn't change position
+ from West
+ should change direction
+ shouldn't change position
+Rotating counter-clockwise
+ from North
+ should change direction
+ shouldn't change position
+ from West
+ should change direction
+ shouldn't change position
+ from South
+ should change direction
+ shouldn't change position
+ from East
+ should change direction
+ shouldn't change position
+Moving forward one
+ North from (0,1)
+ shouldn't change direction
+ facing north increments Y
+ South from (0,-1)
+ shouldn't change direction
+ facing south decrements Y
+ East from (1,0)
+ shouldn't change direction
+ facing east increments X
+ West from (-1,0)
+ shouldn't change direction
+ facing west decrements X
+Follow series of instructions
+ moving east and north from README
+ moving west and north
+ moving west and south
+ moving east and north
+
+Finished in 0.0006 seconds
+30 examples, 0 failures
+
+
+
+robot-simulator> Test suite test passed
+Generating coverage report for robot-simulator's test-suite "test".
+ 90% expressions used (86/95)
+100% boolean coverage (0/0)
+ 100% guards (0/0)
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (0/0)
+ 94% alternatives used (16/17)
+100% local declarations used (0/0)
+ 78% top-level declarations used (11/14)
+The coverage report for robot-simulator's test-suite "test" is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/robot-simulator/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/robot-simulator/test/hpc_index.html.
+Completed 2 action(s).
+Generating unified report.
+ 90% expressions used (86/95)
+100% boolean coverage (0/0)
+ 100% guards (0/0)
+ 100% 'if' conditions (0/0)
+ 100% qualifiers (0/0)
+ 94% alternatives used (16/17)
+100% local declarations used (0/0)
+ 78% top-level declarations used (11/14)
+The unified report is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/robot-simulator/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/combined/all/hpc_index.html.
+
+An index of the generated HTML coverage reports is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/robot-simulator/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/index.html.
+
+real 0m3.087s
+user 0m2.264s
+sys 0m0.687s
+
+===============================================================================
+
+Running: misspell .
+
+real 0m0.034s
+user 0m0.048s
+sys 0m0.017s
+
+===============================================================================
+
diff --git a/haskell/robot-simulator/src/Robot.hs b/haskell/robot-simulator/src/Robot.hs
new file mode 100644
index 00000000..4ceaee0a
--- /dev/null
+++ b/haskell/robot-simulator/src/Robot.hs
@@ -0,0 +1,56 @@
+module Robot
+ ( Bearing(East, North, South, West)
+ , bearing
+ , coordinates
+ , mkRobot
+ , move
+ ) where
+
+data Bearing = North
+ | East
+ | South
+ | West
+ deriving (Eq, Show)
+
+data Robot = Robot
+ { facing :: Bearing
+ , location :: (Integer, Integer)
+ }
+ deriving (Eq, Show)
+
+bearing :: Robot -> Bearing
+bearing = facing
+
+coordinates :: Robot -> (Integer, Integer)
+coordinates = location
+
+mkRobot :: Bearing -> (Integer, Integer) -> Robot
+mkRobot = Robot
+
+move :: Robot -> String -> Robot
+move robot [] = robot
+move robot ('A' : instructions) = move (advance robot) instructions
+move robot ('R' : instructions) = move (turnRight robot) instructions
+move robot ('L' : instructions) = move (turnLeft robot) instructions
+move robot (_ : instructions) = move (doNothing robot) instructions
+
+doNothing :: Robot -> Robot
+doNothing (Robot _ (_, _)) = Robot North (0, 0)
+
+advance :: Robot -> Robot
+advance (Robot North (x, y)) = Robot North (x, y + 1)
+advance (Robot West (x, y)) = Robot West (x - 1, y)
+advance (Robot South (x, y)) = Robot South (x, y - 1)
+advance (Robot East (x, y)) = Robot East (x + 1, y)
+
+turnRight :: Robot -> Robot
+turnRight (Robot North (x, y)) = Robot East (x, y)
+turnRight (Robot East (x, y)) = Robot South (x, y)
+turnRight (Robot South (x, y)) = Robot West (x, y)
+turnRight (Robot West (x, y)) = Robot North (x, y)
+
+turnLeft :: Robot -> Robot
+turnLeft (Robot North (x, y)) = Robot West (x, y)
+turnLeft (Robot West (x, y)) = Robot South (x, y)
+turnLeft (Robot South (x, y)) = Robot East (x, y)
+turnLeft (Robot East (x, y)) = Robot North (x, y)
diff --git a/haskell/robot-simulator/stack.yaml b/haskell/robot-simulator/stack.yaml
new file mode 100644
index 00000000..97a3d909
--- /dev/null
+++ b/haskell/robot-simulator/stack.yaml
@@ -0,0 +1,2 @@
+---
+resolver: lts-19.27
diff --git a/haskell/robot-simulator/stack.yaml.lock b/haskell/robot-simulator/stack.yaml.lock
new file mode 100644
index 00000000..d035878d
--- /dev/null
+++ b/haskell/robot-simulator/stack.yaml.lock
@@ -0,0 +1,12 @@
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+# https://docs.haskellstack.org/en/stable/lock_files
+
+packages: []
+snapshots:
+- completed:
+ sha256: 1ecad1f0bd2c27de88dbff6572446cfdf647c615d58a7e2e2085c6b7dfc04176
+ size: 619403
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/27.yaml
+ original: lts-19.27
diff --git a/haskell/robot-simulator/test/Tests.hs b/haskell/robot-simulator/test/Tests.hs
new file mode 100644
index 00000000..2b24a353
--- /dev/null
+++ b/haskell/robot-simulator/test/Tests.hs
@@ -0,0 +1,105 @@
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+
+import Test.Hspec ( Spec
+ , describe
+ , it
+ , shouldBe
+ )
+import Test.Hspec.Runner ( configFastFail
+ , defaultConfig
+ , hspecWith
+ )
+
+import Robot ( Bearing
+ ( East
+ , North
+ , South
+ , West
+ )
+ , bearing
+ , coordinates
+ , mkRobot
+ , move
+ )
+
+main :: IO ()
+main = hspecWith defaultConfig { configFastFail = True } specs
+
+specs :: Spec
+specs = do
+
+ describe "mkRobot" $ do
+
+ -- The function described by the reference file
+ -- as `create` is called `mkRobot` in this track.
+
+ it "Create robot at origin facing north" $ do
+ let robot = mkRobot North (0, 0)
+ coordinates robot `shouldBe` (0, 0)
+ bearing robot `shouldBe` North
+
+ it "Create robot at negative position facing south" $ do
+ let robot = mkRobot South (-1, -1)
+ coordinates robot `shouldBe` (-1, -1)
+ bearing robot `shouldBe` South
+
+ let turnTest inst dir dir2 =
+ let robot = mkRobot dir (0, 0)
+ in describe ("from " ++ show dir) $ do
+ it "should change direction"
+ $ bearing (move robot inst)
+ `shouldBe` dir2
+ it "shouldn't change position"
+ $ coordinates (move robot inst)
+ `shouldBe` (0, 0)
+
+ describe "Rotating clockwise" $ do
+ let rightTest = turnTest "R"
+ rightTest North East
+ rightTest East South
+ rightTest South West
+ rightTest West North
+
+ describe "Rotating counter-clockwise" $ do
+ let leftTest = turnTest "L"
+ leftTest North West
+ leftTest West South
+ leftTest South East
+ leftTest East North
+
+ describe "Moving forward one" $ do
+ let dir `from` pos = move (mkRobot dir pos) "A"
+ let test desc dir pos = describe (show dir ++ " from " ++ show pos) $ do
+ it "shouldn't change direction"
+ $ bearing (dir `from` (0, 0))
+ `shouldBe` dir
+ it desc $ coordinates (dir `from` (0, 0)) `shouldBe` pos
+
+ test "facing north increments Y" North (0 , 1)
+ test "facing south decrements Y" South (0 , -1)
+ test "facing east increments X" East (1 , 0)
+ test "facing west decrements X" West (-1, 0)
+
+ describe "Follow series of instructions" $ do
+
+ let simulation pos dir = move (mkRobot dir pos)
+
+ it "moving east and north from README" $ do
+ let robot = simulation (7, 3) North "RAALAL"
+ coordinates robot `shouldBe` (9, 4)
+ bearing robot `shouldBe` West
+
+ it "moving west and north" $ do
+ let robot = simulation (0, 0) North "LAAARALA"
+ coordinates robot `shouldBe` (-4, 1)
+ bearing robot `shouldBe` West
+
+ it "moving west and south" $ do
+ let robot = simulation (2, -7) East "RRAAAAALA"
+ coordinates robot `shouldBe` (-3, -8)
+ bearing robot `shouldBe` South
+
+ it "moving east and north" $ do
+ let robot = simulation (8, 4) South "LAAARRRALLLL"
+ coordinates robot `shouldBe` (11, 5)
+ bearing robot `shouldBe` North
diff --git a/haskell/yacht/.exercism/config.json b/haskell/yacht/.exercism/config.json
new file mode 100644
index 00000000..e35cd47b
--- /dev/null
+++ b/haskell/yacht/.exercism/config.json
@@ -0,0 +1,30 @@
+{
+ "authors": [
+ "guygastineau"
+ ],
+ "contributors": [
+ "iHiD",
+ "petertseng",
+ "ppartarr",
+ "sshine",
+ "tejasbubane"
+ ],
+ "files": {
+ "solution": [
+ "src/Yacht.hs",
+ "package.yaml"
+ ],
+ "test": [
+ "test/Tests.hs"
+ ],
+ "example": [
+ ".meta/examples/success-standard/src/Yacht.hs"
+ ],
+ "invalidator": [
+ "stack.yaml"
+ ]
+ },
+ "blurb": "Score a single throw of dice in the game Yacht.",
+ "source": "James Kilfiger, using wikipedia",
+ "source_url": "https://en.wikipedia.org/wiki/Yacht_(dice_game)"
+}
diff --git a/haskell/yacht/.exercism/metadata.json b/haskell/yacht/.exercism/metadata.json
new file mode 100644
index 00000000..8e5f3d4c
--- /dev/null
+++ b/haskell/yacht/.exercism/metadata.json
@@ -0,0 +1 @@
+{"track":"haskell","exercise":"yacht","id":"eeb7f25e703a4ba38bc021b87f9f0154","url":"https://exercism.org/tracks/haskell/exercises/yacht","handle":"vpayno","is_requester":true,"auto_approve":false}
\ No newline at end of file
diff --git a/haskell/yacht/HELP.md b/haskell/yacht/HELP.md
new file mode 100644
index 00000000..e121e2b3
--- /dev/null
+++ b/haskell/yacht/HELP.md
@@ -0,0 +1,86 @@
+# Help
+
+## Running the tests
+
+To run the test suite, execute the following command:
+
+```bash
+stack test
+```
+
+#### If you get an error message like this...
+
+```
+No .cabal file found in directory
+```
+
+or
+
+```
+RedownloadInvalidResponse Request {
+...
+}
+ "/home/username/.stack/build-plan/lts-xx.yy.yaml" (Response {responseStatus = Status {statusCode = 404, statusMessage = "Not Found"},
+```
+
+You are probably running an old stack version and need
+to upgrade it. Try running:
+
+```bash
+stack upgrade
+```
+
+Or see other options for upgrading at [Stack documentation](https://docs.haskellstack.org/en/stable/install_and_upgrade/#upgrade).
+
+#### Otherwise, if you get an error message like this...
+
+```
+No compiler found, expected minor version match with...
+Try running "stack setup" to install the correct GHC...
+```
+
+Just do as it says and it will download and install
+the correct compiler version:
+
+```bash
+stack setup
+```
+
+If you want to play with your solution in GHCi, just run the command:
+
+```bash
+stack ghci
+```
+
+## Submitting your solution
+
+You can submit your solution using the `exercism submit src/Yacht.hs package.yaml` command.
+This command will upload your solution to the Exercism website and print the solution page's URL.
+
+It's possible to submit an incomplete solution which allows you to:
+
+- See how others have completed the exercise
+- Request help from a mentor
+
+## Need to get help?
+
+If you'd like help solving the exercise, check the following pages:
+
+- The [Haskell track's documentation](https://exercism.org/docs/tracks/haskell)
+- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
+- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
+
+Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
+
+## Getting Started
+
+Please refer to the [installation](https://exercism.io/tracks/haskell/installation)
+and [learning](https://exercism.io/tracks/haskell/learning) help pages.
+
+## Feedback, Issues, Pull Requests
+
+The [exercism/haskell](https://github.com/exercism/haskell) repository on
+GitHub is the home for all of the Haskell exercises.
+
+If you have feedback about an exercise, or want to help implementing a new
+one, head over there and create an issue. We'll do our best to help you!
\ No newline at end of file
diff --git a/haskell/yacht/README.md b/haskell/yacht/README.md
new file mode 100644
index 00000000..cd6341bc
--- /dev/null
+++ b/haskell/yacht/README.md
@@ -0,0 +1,63 @@
+# Yacht
+
+Welcome to Yacht on Exercism's Haskell Track.
+If you need help running the tests or submitting your code, check out `HELP.md`.
+
+## Instructions
+
+The dice game [Yacht](https://en.wikipedia.org/wiki/Yacht_(dice_game)) is from
+the same family as Poker Dice, Generala and particularly Yahtzee, of which it
+is a precursor. In the game, five dice are rolled and the result can be entered
+in any of twelve categories. The score of a throw of the dice depends on
+category chosen.
+
+## Scores in Yacht
+
+| Category | Score | Description | Example |
+| -------- | ----- | ----------- | ------- |
+| Ones | 1 × number of ones | Any combination | 1 1 1 4 5 scores 3 |
+| Twos | 2 × number of twos | Any combination | 2 2 3 4 5 scores 4 |
+| Threes | 3 × number of threes | Any combination | 3 3 3 3 3 scores 15 |
+| Fours | 4 × number of fours | Any combination | 1 2 3 3 5 scores 0 |
+| Fives | 5 × number of fives| Any combination | 5 1 5 2 5 scores 15 |
+| Sixes | 6 × number of sixes | Any combination | 2 3 4 5 6 scores 6 |
+| Full House | Total of the dice | Three of one number and two of another | 3 3 3 5 5 scores 19 |
+| Four of a Kind | Total of the four dice | At least four dice showing the same face | 4 4 4 4 6 scores 16 |
+| Little Straight | 30 points | 1-2-3-4-5 | 1 2 3 4 5 scores 30 |
+| Big Straight | 30 points | 2-3-4-5-6 | 2 3 4 5 6 scores 30 |
+| Choice | Sum of the dice | Any combination | 2 3 3 4 6 scores 18 |
+| Yacht | 50 points | All five dice showing the same face | 4 4 4 4 4 scores 50 |
+
+If the dice do not satisfy the requirements of a category, the score is zero.
+If, for example, *Four Of A Kind* is entered in the *Yacht* category, zero
+points are scored. A *Yacht* scores zero if entered in the *Full House* category.
+
+## Task
+Given a list of values for five dice and a category, your solution should return
+the score of the dice for that category. If the dice do not satisfy the requirements
+of the category your solution should return 0. You can assume that five values
+will always be presented, and the value of each will be between one and six
+inclusively. You should not assume that the dice are ordered.
+
+## Source
+
+### Created by
+
+- @guygastineau
+
+### Contributed to by
+
+- @iHiD
+- @petertseng
+- @ppartarr
+- @sshine
+- @tejasbubane
+
+### Based on
+
+James Kilfiger, using wikipedia - https://en.wikipedia.org/wiki/Yacht_(dice_game)
+
+### My Solution
+
+- [my solution](./src/Yacht.hs)
+- [run-tests](./run-tests-haskell.txt)
diff --git a/haskell/yacht/package.yaml b/haskell/yacht/package.yaml
new file mode 100644
index 00000000..33afa6ec
--- /dev/null
+++ b/haskell/yacht/package.yaml
@@ -0,0 +1,21 @@
+---
+name: yacht
+version: 1.2.0.0
+
+dependencies:
+ - base
+
+library:
+ exposed-modules: Yacht
+ source-dirs: src
+ ghc-options: -Wall
+ dependencies:
+ - containers
+
+tests:
+ test:
+ main: Tests.hs
+ source-dirs: test
+ dependencies:
+ - yacht
+ - hspec
diff --git a/haskell/yacht/report.html b/haskell/yacht/report.html
new file mode 100644
index 00000000..8cd3f07d
--- /dev/null
+++ b/haskell/yacht/report.html
@@ -0,0 +1,186 @@
+
+
+
+
+HLint Report
+
+
+
+
+
+
+
+
+
+
+
+ Report generated by HLint
+v3.3.6
+ - a tool to suggest improvements to your Haskell code.
+
+
+No hints
+
+
+
+
diff --git a/haskell/yacht/run-tests-haskell.txt b/haskell/yacht/run-tests-haskell.txt
new file mode 100644
index 00000000..41e0b209
--- /dev/null
+++ b/haskell/yacht/run-tests-haskell.txt
@@ -0,0 +1,118 @@
+Running automated test file(s):
+
+
+===============================================================================
+
+Running: hlint src --report
+Writing report to report.html ...
+No hints
+
+real 0m0.216s
+user 0m0.178s
+sys 0m0.031s
+
+===============================================================================
+
+Running: brittany --verbose --write-mode=inplace ./src/Yacht.hs ./test/Tests.hs
+
+real 0m0.114s
+user 0m0.098s
+sys 0m0.013s
+
+===============================================================================
+
+Running: stack test --coverage
+yacht-1.2.0.0: unregistering (local file changes: src/Yacht.hs)
+yacht> configure (lib + test)
+Configuring yacht-1.2.0.0...
+yacht> build (lib + test)
+Preprocessing library for yacht-1.2.0.0..
+Building library for yacht-1.2.0.0..
+[1 of 2] Compiling Paths_yacht
+[2 of 2] Compiling Yacht
+Preprocessing test suite 'test' for yacht-1.2.0.0..
+Building test suite 'test' for yacht-1.2.0.0..
+Linking .stack-work/dist/x86_64-linux/Cabal-3.4.1.0/build/test/test ...
+yacht> copy/register
+Installing library in /home/vpayno/git_vpayno/exercism-workspace/haskell/yacht/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/lib/x86_64-linux-ghc-9.0.2/yacht-1.2.0.0-DdPkwXoEJy03oJFna6yTIt
+Registering library for yacht-1.2.0.0..
+yacht> test (suite: test)
+
+
+yacht
+ Yacht
+ Not Yacht
+ Ones
+ Ones, out of order
+ No ones
+ Twos
+ Fours
+ Yacht counted as threes
+ Yacht of 3s counted as fives
+ Sixes
+ Full house two small, three big
+ Full house three small, two big
+ Two pair is not a full house
+ Four of a kind is not a full house
+ Yacht is not a full house
+ Four of a Kind
+ Yacht can be scored as Four of a Kind
+ Full house is not Four of a Kind
+ Little Straight
+ Little Straight as Big Straight
+ Four in order but not a little straight
+ No pairs but not a little straight
+ Minimum is 1, maximum is 5, but not a little straight
+ Big Straight
+ Big Straight as little straight
+ No pairs but not a big straight
+ Choice
+ Yacht as choice
+
+Finished in 0.0003 seconds
+28 examples, 0 failures
+
+
+
+yacht> Test suite test passed
+Generating coverage report for yacht's test-suite "test".
+100% expressions used (120/120)
+100% boolean coverage (5/5)
+ 100% guards (0/0)
+ 100% 'if' conditions (5/5)
+ 100% qualifiers (0/0)
+100% alternatives used (24/24)
+100% local declarations used (2/2)
+100% top-level declarations used (6/6)
+The coverage report for yacht's test-suite "test" is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/yacht/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/yacht/test/hpc_index.html.
+Completed 2 action(s).
+Generating unified report.
+100% expressions used (120/120)
+100% boolean coverage (5/5)
+ 100% guards (0/0)
+ 100% 'if' conditions (5/5)
+ 100% qualifiers (0/0)
+100% alternatives used (24/24)
+100% local declarations used (2/2)
+100% top-level declarations used (6/6)
+The unified report is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/yacht/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/combined/all/hpc_index.html.
+
+An index of the generated HTML coverage reports is available at
+/home/vpayno/git_vpayno/exercism-workspace/haskell/yacht/.stack-work/install/x86_64-linux/6b1a8da4b1549c5ef09335b033ed2c154e3872c256ff97c98f949b661c169d68/9.0.2/hpc/index.html.
+
+real 0m3.004s
+user 0m2.098s
+sys 0m0.801s
+
+===============================================================================
+
+Running: misspell .
+
+real 0m0.031s
+user 0m0.058s
+sys 0m0.020s
+
+===============================================================================
+
diff --git a/haskell/yacht/src/Yacht.hs b/haskell/yacht/src/Yacht.hs
new file mode 100644
index 00000000..62ebba95
--- /dev/null
+++ b/haskell/yacht/src/Yacht.hs
@@ -0,0 +1,67 @@
+module Yacht
+ ( yacht
+ , Category(..)
+ ) where
+
+import qualified Data.Map as M
+import Data.Map ( (!)
+ , Map
+ )
+
+data Category = Ones
+ | Twos
+ | Threes
+ | Fours
+ | Fives
+ | Sixes
+ | FullHouse
+ | FourOfAKind
+ | LittleStraight
+ | BigStraight
+ | Choice
+ | Yacht
+
+yacht :: Category -> [Int] -> Int
+yacht category dice =
+ let
+ numbersCount :: Map Int Int
+ numbersCount = countNumbers dice
+ in
+ case category of
+ Ones -> countN 1 numbersCount
+ Twos -> countN 2 numbersCount
+ Threes -> countN 3 numbersCount
+ Fours -> countN 4 numbersCount
+ Fives -> countN 5 numbersCount
+ Sixes -> countN 6 numbersCount
+ FullHouse ->
+ if distinctNbs numbersCount == 2 && elem 3 (M.elems numbersCount)
+ then sum dice
+ else 0
+ FourOfAKind -> maybe 0 (4 *) $ firstIdxOf numbersCount (4 <=)
+ LittleStraight ->
+ if distinctNbs numbersCount == 5 && numbersCount ! 6 == 0 then 30 else 0
+ BigStraight -> if distinctNbs numbersCount == 5 && numbersCount ! 1 == 0
+ then 30
+ else 0
+ Choice -> sum dice
+ Yacht -> if distinctNbs numbersCount == 1 then 50 else 0
+
+countN :: Int -> Map Int Int -> Int
+countN n counts = n * (counts ! n)
+
+countItem :: Int -> Map Int Int -> Map Int Int
+countItem n = M.insertWith (+) n 1
+
+countNumbers :: [Int] -> Map Int Int
+countNumbers = foldr countItem (M.fromList [ (i, 0) | i <- [1 .. 6] ])
+
+distinctNbs :: Map Int Int -> Int
+distinctNbs counts = length $ filter (0 <) $ M.elems counts
+
+firstIdxOf :: Map Int Int -> (Int -> Bool) -> Maybe Int
+firstIdxOf counts condition =
+ let aux mapAsList = case mapAsList of
+ [] -> Nothing
+ (idx, cnt) : q -> if condition cnt then Just idx else aux q
+ in aux $ M.toList counts
diff --git a/haskell/yacht/stack.yaml b/haskell/yacht/stack.yaml
new file mode 100644
index 00000000..97a3d909
--- /dev/null
+++ b/haskell/yacht/stack.yaml
@@ -0,0 +1,2 @@
+---
+resolver: lts-19.27
diff --git a/haskell/yacht/stack.yaml.lock b/haskell/yacht/stack.yaml.lock
new file mode 100644
index 00000000..d035878d
--- /dev/null
+++ b/haskell/yacht/stack.yaml.lock
@@ -0,0 +1,12 @@
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+# https://docs.haskellstack.org/en/stable/lock_files
+
+packages: []
+snapshots:
+- completed:
+ sha256: 1ecad1f0bd2c27de88dbff6572446cfdf647c615d58a7e2e2085c6b7dfc04176
+ size: 619403
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/27.yaml
+ original: lts-19.27
diff --git a/haskell/yacht/test/Tests.hs b/haskell/yacht/test/Tests.hs
new file mode 100644
index 00000000..c04db8e8
--- /dev/null
+++ b/haskell/yacht/test/Tests.hs
@@ -0,0 +1,176 @@
+{-# LANGUAGE RecordWildCards #-}
+
+import Data.Foldable ( for_ )
+import Test.Hspec ( Spec
+ , describe
+ , it
+ , shouldBe
+ )
+import Test.Hspec.Runner ( configFastFail
+ , defaultConfig
+ , hspecWith
+ )
+
+import Yacht ( Category(..)
+ , yacht
+ )
+
+main :: IO ()
+main = hspecWith defaultConfig { configFastFail = True } specs
+
+specs :: Spec
+specs = describe "yacht" $ for_ cases test
+ where
+ test Case {..} = it description assertion
+ where assertion = yacht category dice `shouldBe` expected
+
+data Case = Case
+ { description :: String
+ , dice :: [Int]
+ , category :: Category
+ , expected :: Int
+ }
+
+cases :: [Case]
+cases =
+ [ Case { description = "Yacht"
+ , dice = [5, 5, 5, 5, 5]
+ , category = Yacht
+ , expected = 50
+ }
+ , Case { description = "Not Yacht"
+ , dice = [1, 3, 3, 2, 5]
+ , category = Yacht
+ , expected = 0
+ }
+ , Case { description = "Ones"
+ , dice = [1, 1, 1, 3, 5]
+ , category = Ones
+ , expected = 3
+ }
+ , Case { description = "Ones, out of order"
+ , dice = [3, 1, 1, 5, 1]
+ , category = Ones
+ , expected = 3
+ }
+ , Case { description = "No ones"
+ , dice = [4, 3, 6, 5, 5]
+ , category = Ones
+ , expected = 0
+ }
+ , Case { description = "Twos"
+ , dice = [2, 3, 4, 5, 6]
+ , category = Twos
+ , expected = 2
+ }
+ , Case { description = "Fours"
+ , dice = [1, 4, 1, 4, 1]
+ , category = Fours
+ , expected = 8
+ }
+ , Case { description = "Yacht counted as threes"
+ , dice = [3, 3, 3, 3, 3]
+ , category = Threes
+ , expected = 15
+ }
+ , Case { description = "Yacht of 3s counted as fives"
+ , dice = [3, 3, 3, 3, 3]
+ , category = Fives
+ , expected = 0
+ }
+ , Case { description = "Sixes"
+ , dice = [2, 3, 4, 5, 6]
+ , category = Sixes
+ , expected = 6
+ }
+ , Case { description = "Full house two small, three big"
+ , dice = [2, 2, 4, 4, 4]
+ , category = FullHouse
+ , expected = 16
+ }
+ , Case { description = "Full house three small, two big"
+ , dice = [5, 3, 3, 5, 3]
+ , category = FullHouse
+ , expected = 19
+ }
+ , Case { description = "Two pair is not a full house"
+ , dice = [2, 2, 4, 4, 5]
+ , category = FullHouse
+ , expected = 0
+ }
+ , Case { description = "Four of a kind is not a full house"
+ , dice = [1, 4, 4, 4, 4]
+ , category = FullHouse
+ , expected = 0
+ }
+ , Case { description = "Yacht is not a full house"
+ , dice = [2, 2, 2, 2, 2]
+ , category = FullHouse
+ , expected = 0
+ }
+ , Case { description = "Four of a Kind"
+ , dice = [6, 6, 4, 6, 6]
+ , category = FourOfAKind
+ , expected = 24
+ }
+ , Case { description = "Yacht can be scored as Four of a Kind"
+ , dice = [3, 3, 3, 3, 3]
+ , category = FourOfAKind
+ , expected = 12
+ }
+ , Case { description = "Full house is not Four of a Kind"
+ , dice = [3, 3, 3, 5, 5]
+ , category = FourOfAKind
+ , expected = 0
+ }
+ , Case { description = "Little Straight"
+ , dice = [3, 5, 4, 1, 2]
+ , category = LittleStraight
+ , expected = 30
+ }
+ , Case { description = "Little Straight as Big Straight"
+ , dice = [1, 2, 3, 4, 5]
+ , category = BigStraight
+ , expected = 0
+ }
+ , Case { description = "Four in order but not a little straight"
+ , dice = [1, 1, 2, 3, 4]
+ , category = LittleStraight
+ , expected = 0
+ }
+ , Case { description = "No pairs but not a little straight"
+ , dice = [1, 2, 3, 4, 6]
+ , category = LittleStraight
+ , expected = 0
+ }
+ , Case { description = "Minimum is 1, maximum is 5, but not a little straight"
+ , dice = [1, 1, 3, 4, 5]
+ , category = LittleStraight
+ , expected = 0
+ }
+ , Case { description = "Big Straight"
+ , dice = [4, 6, 2, 5, 3]
+ , category = BigStraight
+ , expected = 30
+ }
+ , Case { description = "Big Straight as little straight"
+ , dice = [6, 5, 4, 3, 2]
+ , category = LittleStraight
+ , expected = 0
+ }
+ , Case { description = "No pairs but not a big straight"
+ , dice = [6, 5, 4, 3, 1]
+ , category = BigStraight
+ , expected = 0
+ }
+ , Case { description = "Choice"
+ , dice = [3, 3, 5, 6, 6]
+ , category = Choice
+ , expected = 23
+ }
+ , Case { description = "Yacht as choice"
+ , dice = [2, 2, 2, 2, 2]
+ , category = Choice
+ , expected = 10
+ }
+ ]
diff --git a/haskell/yacht/yacht.cabal b/haskell/yacht/yacht.cabal
new file mode 100644
index 00000000..aca47437
--- /dev/null
+++ b/haskell/yacht/yacht.cabal
@@ -0,0 +1,35 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.35.2.
+--
+-- see: https://github.com/sol/hpack
+
+name: yacht
+version: 1.2.0.0
+build-type: Simple
+
+library
+ exposed-modules:
+ Yacht
+ other-modules:
+ Paths_yacht
+ hs-source-dirs:
+ src
+ ghc-options: -Wall
+ build-depends:
+ base
+ , containers
+ default-language: Haskell2010
+
+test-suite test
+ type: exitcode-stdio-1.0
+ main-is: Tests.hs
+ other-modules:
+ Paths_yacht
+ hs-source-dirs:
+ test
+ build-depends:
+ base
+ , hspec
+ , yacht
+ default-language: Haskell2010