diff --git a/exercises/palindrome-products/HINTS.md b/exercises/palindrome-products/HINTS.md new file mode 100644 index 000000000..f60649054 --- /dev/null +++ b/exercises/palindrome-products/HINTS.md @@ -0,0 +1,19 @@ +## Hints + +To solve this exercise you need to implement these two functions: + +- `largestPalindrome` +- `smallestPalindrome` + +Both functions receive lower and upper factor limits, returning a pair +`(value, [(factor1, factor2)])` containing the palindrome and its possible +pairs of factors. + +Your can use the provided signatures if you are unsure about the types, but +don't let them restrict your creativity. + +It's ok to return duplicates in the factors list, and the order of the factors +is irrelevant. + +You should consider using a slightly different algorithm to find small or +large palindromes. diff --git a/exercises/palindrome-products/package.yaml b/exercises/palindrome-products/package.yaml index 64ad1ef26..482880d62 100644 --- a/exercises/palindrome-products/package.yaml +++ b/exercises/palindrome-products/package.yaml @@ -16,5 +16,4 @@ tests: source-dirs: test dependencies: - palindrome-products - - containers - - HUnit + - hspec diff --git a/exercises/palindrome-products/src/Palindromes.hs b/exercises/palindrome-products/src/Palindromes.hs index 39442c125..ca55998a5 100644 --- a/exercises/palindrome-products/src/Palindromes.hs +++ b/exercises/palindrome-products/src/Palindromes.hs @@ -1,15 +1,7 @@ module Palindromes (largestPalindrome, smallestPalindrome) where --- It's ok to return duplicates in the factor list, and the order of the factors --- is irrelevant. --- --- You should consider using a slightly different algorithm to find small or --- large palindromes. +largestPalindrome :: Integer -> Integer -> (Integer, [(Integer, Integer)]) +largestPalindrome minFactor maxFactor = undefined --- largestPalindrome minFactor maxFactor = (value, [(factor1, factor2)]) -largestPalindrome :: Integral a => a -> a -> (a, [(a, a)]) -largestPalindrome = undefined - --- smallestPalindrome minFactor maxFactor = (value, [(factor1, factor2)]) -smallestPalindrome :: Integral a => a -> a -> (a, [(a, a)]) -smallestPalindrome = undefined +smallestPalindrome :: Integer -> Integer -> (Integer, [(Integer, Integer)]) +smallestPalindrome minFactor maxFactor = undefined diff --git a/exercises/palindrome-products/test/Tests.hs b/exercises/palindrome-products/test/Tests.hs index fe2db4bb8..b8e0e3f14 100644 --- a/exercises/palindrome-products/test/Tests.hs +++ b/exercises/palindrome-products/test/Tests.hs @@ -1,73 +1,36 @@ -import Test.HUnit (Assertion, (@=?), runTestTT, Test(..), Counts(..)) -import System.Exit (ExitCode(..), exitWith) -import Palindromes (largestPalindrome, smallestPalindrome) -import qualified Data.Set as S - --- largestPalindrome, smallestPalindrome :: Integral a => a -> a -> (a,[(a, a)]) --- largestPalindrome minFactor maxFactor = (value, [(factor1, factor2)]) - --- It's ok to return duplicates in the factor list, and the order of the factors --- is irrelevant. - --- You should consider using a slightly different algorithm to find small or --- large palindromes. +{-# OPTIONS_GHC -fno-warn-type-defaults #-} -exitProperly :: IO Counts -> IO () -exitProperly m = do - counts <- m - exitWith $ if failures counts /= 0 || errors counts /= 0 then ExitFailure 1 else ExitSuccess +import Data.Foldable (for_) +import Data.List (nub, sort) +import Test.Hspec (Spec, describe, it, shouldBe) +import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith) -testCase :: String -> Assertion -> Test -testCase label assertion = TestLabel label (TestCase assertion) +import Palindromes (largestPalindrome, smallestPalindrome) main :: IO () -main = exitProperly $ runTestTT $ TestList - [ TestList palindromesTests ] - -norm :: Ord a => [(a, a)] -> [(a, a)] -norm = S.toList . S.fromList . map normPair - where normPair p@(a, b) = if b < a then (b, a) else p - -palindromesTests :: [Test] -palindromesTests = - [ testCase "largest palindrome from single digit factors" $ do - let (largest, factors) = largestPalindrome 1 9 - (9 :: Int) @=? largest - [(1, 9), (3, 3)] @=? norm factors - , testCase "smallest palindrome from single digit factors" $ do - let (smallest, factors) = smallestPalindrome 1 9 - (1 :: Int) @=? smallest - [(1, 1)] @=? norm factors - , testCase "largest palindrome from double digit factors" $ do - let (largest, factors) = largestPalindrome 10 99 - (9009 :: Int) @=? largest - [(91, 99)] @=? norm factors - , testCase "smallest palindrome from double digit factors" $ do - let (smallest, factors) = smallestPalindrome 10 99 - (121 :: Int) @=? smallest - [(11, 11)] @=? norm factors - , testCase "largest palindrome from triple digit factors" $ do - let (largest, factors) = largestPalindrome 100 999 - (906609 :: Int) @=? largest - [(913, 993)] @=? norm factors - , testCase "smallest palindrome from triple digit factors" $ do - let (smallest, factors) = smallestPalindrome 100 999 - (10201 :: Int) @=? smallest - [(101, 101)] @=? norm factors - , testCase "largest palindrome from four digit factors" $ do - let (largest, factors) = largestPalindrome 1000 9999 - (99000099 :: Int) @=? largest - [(9901, 9999)] @=? norm factors - , testCase "smallest palindrome from four digit factors" $ do - let (smallest, factors) = smallestPalindrome 1000 9999 - (1002001 :: Int) @=? smallest - [(1001,1001)] @=? norm factors - , testCase "largest palindrome from five digit factors" $ do - let (largest, factors) = largestPalindrome 10000 99999 - (9966006699 :: Integer) @=? largest - [(99681, 99979)] @=? norm factors - , testCase "smallest palindrome from five digit factors" $ do - let (smallest, factors) = smallestPalindrome 10000 99999 - (100020001 :: Integer) @=? smallest - [(10001,10001)] @=? norm factors - ] +main = hspecWith defaultConfig {configFastFail = True} specs + +specs :: Spec +specs = describe "palindrome-products" $ for_ cases test + where + test (desc, minFactor, maxFactor, sPal, sPalFactors, lPal, lPalFactors) = + describe desc $ do + let sortPair (a, b) = if a < b then (a, b) else (b, a) + let normalize = sort . nub . map sortPair + describe "smallesPalindrome" $ do + let (value, factors) = smallestPalindrome minFactor maxFactor + it "value" $ value `shouldBe` sPal + it "factors" $ normalize factors `shouldBe` sPalFactors + describe "largestPalindrome" $ do + let (value, factors) = largestPalindrome minFactor maxFactor + it "value" $ value `shouldBe` lPal + it "factors" $ normalize factors `shouldBe` lPalFactors + + -- As of 2016-09-07, there was no reference file + -- for the test cases in `exercism/x-common`. + + cases = [ ("palindromes from single digit factors", 1, 9, 1, [( 1, 1)], 9, [(1, 9), (3, 3)]) + , ("palindromes from double digit factors", 10, 99, 121, [( 11, 11)], 9009, [( 91, 99)]) + , ("palindromes from triple digit factors", 100, 999, 10201, [( 101, 101)], 906609, [( 913, 993)]) + , ("palindromes from four digit factors" , 1000, 9999, 1002001, [( 1001, 1001)], 99000099, [( 9901, 9999)]) + , ("palindromes from five digit factors" , 10000, 99999, 100020001, [(10001, 10001)], 9966006699, [(99681, 99979)]) ]