Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

anagram: Make the test suite as flexible as possible #393

Merged
merged 1 commit into from
Oct 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions exercises/anagram/HINTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## Hints

To complete this exercise you need to implement the function `anagramsFor`,
that takes a *word* and a group of *words*, returning the ones that are
anagrams of the given *word*.

If it is your first time solving this exercise, it is recommended that you
stick to the provided signature:

```haskell
anagramsFor :: String -> [String] -> [String]
```

Later, it may be a good idea to revisit this problem and play with other data
types and libraries:

- `Text`, from package *text*.
- `Sequence` and `Set`, from package *containers*.
- `MultiSet`, from package *multiset*

The test suite was intentionally designed to accept almost any type signature
that makes sense, so you are encouraged to find the one you think is the best.
3 changes: 3 additions & 0 deletions exercises/anagram/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ library:
dependencies:
# - foo # List here the packages you
# - bar # want to use in your solution.
- containers
- multiset
- text

tests:
test:
Expand Down
17 changes: 10 additions & 7 deletions exercises/anagram/src/Example.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
module Anagram (anagramsFor) where
import Data.List (sort)
import Data.Char (toLower)

anagramsFor :: String -> [String] -> [String]
anagramsFor word = filter (isAnagram . normalize)
import Data.Function (on)
import Data.MultiSet (fromList)
import Data.Set (Set, filter)
import Data.Text (Text, toLower, unpack)
import Prelude hiding (filter)

anagramsFor :: Text -> Set Text -> Set Text
anagramsFor x = filter (\w -> x `isDistinctOf` w && x `isAnagramOf` w)
where
normalize xs = let nxs = map toLower xs in (nxs, sort nxs)
(nw, sw) = normalize word
isAnagram (w, s) = nw /= w && sw == s
isDistinctOf = (/=) `on` toLower
isAnagramOf = (==) `on` fromList . unpack . toLower
12 changes: 9 additions & 3 deletions exercises/anagram/test/Tests.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{-# LANGUAGE RecordWildCards #-}

import Data.Foldable (for_)
import Test.Hspec (Spec, describe, it, shouldBe)
import GHC.Exts (fromList, toList)
import Test.Hspec (Spec, describe, it, shouldMatchList)
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)

import Anagram (anagramsFor)
Expand All @@ -14,9 +15,14 @@ specs = describe "anagram" $
describe "anagramsFor" $ for_ cases test
where

test Case{..} = it description $ expression `shouldBe` expected
test Case{..} = it description $ expression `shouldMatchList` expected
where
expression = anagramsFor subject candidates
expression = map toList
. toList
. anagramsFor (fromList subject)
. fromList
. map fromList
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note for my study - this allows either Text or String to be used. Interesting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsList is fantastic. Way more flexible than I imagined. 😄

$ candidates

-- Test cases adapted from `exercism/x-common/anagrams.json` on 2016-07-25.

Expand Down