diff --git a/config.json b/config.json index 1b39a73f9..022f39ef1 100644 --- a/config.json +++ b/config.json @@ -279,6 +279,13 @@ "topics": [ ] }, + { + "slug": "bracket-push", + "difficulty": 5, + "topics": [ + "Stack" + ] + }, { "slug": "crypto-square", "difficulty": 5, diff --git a/exercises/bracket-push/examples/success-standard/package.yaml b/exercises/bracket-push/examples/success-standard/package.yaml new file mode 100644 index 000000000..19972da2f --- /dev/null +++ b/exercises/bracket-push/examples/success-standard/package.yaml @@ -0,0 +1,17 @@ +name: bracket-push + +dependencies: + - base + +library: + exposed-modules: Brackets + source-dirs: src + dependencies: + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - bracket-push + - hspec diff --git a/exercises/bracket-push/examples/success-standard/src/Brackets.hs b/exercises/bracket-push/examples/success-standard/src/Brackets.hs new file mode 100644 index 000000000..593001893 --- /dev/null +++ b/exercises/bracket-push/examples/success-standard/src/Brackets.hs @@ -0,0 +1,36 @@ +module Brackets (arePaired) where + +data BracketType = Opening | Closing +data Stack a = Empty | Elem a (Stack a) + +push :: Char -> Stack Char -> Stack Char +push = Elem + +pop :: Stack Char -> Stack Char +pop Empty = Empty +pop (Elem _ stack) = stack + +arePaired :: String -> Bool +arePaired xs = checkBalance xs Empty + +checkBalance :: String -> Stack Char -> Bool +checkBalance [] Empty = True +checkBalance [] _ = False +checkBalance (x:xs) stack = + case classify x of + Just Opening -> checkBalance xs $ push x stack + Just Closing -> (x `closes` stack) && checkBalance xs (pop stack) + _ -> checkBalance xs stack + +classify :: Char -> Maybe BracketType +classify x + | x `elem` "([{" = Just Opening + | x `elem` ")]}" = Just Closing + | otherwise = Nothing + +closes :: Char -> Stack Char -> Bool +closes _ Empty = False +closes x (Elem y _) = + x == ')' && y == '(' + || x == ']' && y == '[' + || x == '}' && y == '{' diff --git a/exercises/bracket-push/package.yaml b/exercises/bracket-push/package.yaml new file mode 100644 index 000000000..358afc4c6 --- /dev/null +++ b/exercises/bracket-push/package.yaml @@ -0,0 +1,19 @@ +name: bracket-push + +dependencies: + - base + +library: + exposed-modules: Brackets + source-dirs: src + dependencies: + # - foo # List here the packages you + # - bar # want to use in your solution. + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - bracket-push + - hspec diff --git a/exercises/bracket-push/src/Brackets.hs b/exercises/bracket-push/src/Brackets.hs new file mode 100644 index 000000000..df83bb29b --- /dev/null +++ b/exercises/bracket-push/src/Brackets.hs @@ -0,0 +1,4 @@ +module Brackets (arePaired) where + +arePaired :: String -> Bool +arePaired xs = error "You need to implement this function." diff --git a/exercises/bracket-push/stack.yaml b/exercises/bracket-push/stack.yaml new file mode 100644 index 000000000..72bc099fa --- /dev/null +++ b/exercises/bracket-push/stack.yaml @@ -0,0 +1 @@ +resolver: lts-8.2 diff --git a/exercises/bracket-push/test/Tests.hs b/exercises/bracket-push/test/Tests.hs new file mode 100644 index 000000000..b99ae19f5 --- /dev/null +++ b/exercises/bracket-push/test/Tests.hs @@ -0,0 +1,85 @@ +{-# LANGUAGE RecordWildCards #-} + +import Data.Foldable (for_) +import Test.Hspec (Spec, describe, it, shouldBe) +import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith) + +import Brackets (arePaired) + +main :: IO () +main = hspecWith defaultConfig {configFastFail = True} specs + +specs :: Spec +specs = describe "bracket-push" $ + describe "isPaired" $ for_ cases test + where + test Case{..} = it description $ arePaired input `shouldBe` expected + +-- Adapted from +-- Source: exercism/x-common/exercises/bracket-push/canonical-data.json +-- Version: 1.1.0 +-- Date: 2017-04-07. + +data Case = Case { description :: String + , input :: String + , expected :: Bool + } + +cases :: [Case] +cases = [ Case { description = "paired square brackets" + , input = "[]" + , expected = True + } + , Case { description = "empty string" + , input = "" + , expected = True + } + , Case { description = "unpaired brackets" + , input = "[[" + , expected = False + } + , Case { description = "wrong ordered brackets" + , input = "}{" + , expected = False + } + , Case { description = "wrong closing brackets" + , input = "{]" + , expected = False + } + , Case { description = "paired with whitespace" + , input = "{ }" + , expected = True + } + , Case { description = "simple nested brackets" + , input = "{[]}" + , expected = True + } + , Case { description = "several paired brackets" + , input = "{}[]" + , expected = True + } + , Case { description = "paired and nested brackets" + , input = "([{}({}[])])" + , expected = True + } + , Case { description = "unopened closing brackets" + , input = "{[)][]}" + , expected = False + } + , Case { description = "unpaired and nested brackets" + , input = "([{])" + , expected = False + } + , Case { description = "paired and wrong nested brackets" + , input = "[({]})" + , expected = False + } + , Case { description = "math expression" + , input = "(((185 + 223.85) * 15) - 543)/2" + , expected = True + } + , Case { description = "complex latex expression" + , input = "\\left(\\begin{array}{cc} \\frac{1}{3} & x\\\\ \\mathrm{e}^{x} &... x^2 \\end{array}\\right)" + , expected = True + } + ]