diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d910ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Created by https://www.gitignore.io/api/haskell + +### Haskell ### +dist +dist-* +cabal-dev +*.o +*.hi +*.chi +*.chs.h +*.dyn_o +*.dyn_hi +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +*.prof +*.aux +*.hp +*.eventlog +.stack-work/ +cabal.project.local +.HTF/ + +# End of https://www.gitignore.io/api/haskell diff --git a/ChangeLog.md b/ChangeLog.md new file mode 100644 index 0000000..3a52c4a --- /dev/null +++ b/ChangeLog.md @@ -0,0 +1,5 @@ +# Revision history for CtCI-6th-Edition-Haskell + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/CtCI-6th-Edition-Haskell.cabal b/CtCI-6th-Edition-Haskell.cabal new file mode 100644 index 0000000..c8d2297 --- /dev/null +++ b/CtCI-6th-Edition-Haskell.cabal @@ -0,0 +1,121 @@ +name: CtCI-6th-Edition-Haskell +version: 0.1.0.0 +synopsis: Haskell Solutions for Cracking the Coding Interview 6th Edition + +-- description: + +homepage: https://github.com/careercup/CtCI-6th-Edition-Haskell +bug-reports: https://github.com/careercup/CtCI-6th-Edition-Haskell/issues +-- license: +license-file: LICENSE +author: Variuos Contributors +maintainer: NA +-- copyright: +-- category: +build-type: Simple +cabal-version: >= 1.10 +tested-with: GHC == 8.0.* + +extra-source-files: + ChangeLog.md + , LICENSE + , README.md + , Setup.hs + +source-repository head + type: git + location: https://github.com/careercup/CtCI-6th-Edition-Haskell + +library + default-language: Haskell2010 + + ghc-options: -Wall -fwarn-tabs -fwarn-monomorphism-restriction + -fwarn-unused-do-bind + + hs-source-dirs: + src + + exposed-modules: + Introduction.VI.Example01 + + other-modules: + + build-depends: + base == 4.9.* + + other-extensions: + +test-suite CtCI-6th-Edition-Haskell-Tests + default-language: Haskell2010 + type: exitcode-stdio-1.0 + main-is: Spec.hs + + ghc-options: -Wall -fwarn-tabs -fwarn-monomorphism-restriction + -fwarn-unused-do-bind + + hs-source-dirs: + src + , test + + other-modules: + Introduction.VI.Example01 + , Introduction.VI.Example01Spec + + build-tool-depends: + hspec-discover:hspec-discover == 2.4.* + + build-depends: + base == 4.9.* + , hspec == 2.4.* + , QuickCheck == 2.9.* + + other-extensions: + +test-suite tests + default-language: Haskell2010 + type: exitcode-stdio-1.0 + main-is: Main.hs + + ghc-options: -Wall -fwarn-tabs -fwarn-monomorphism-restriction + -fwarn-unused-do-bind + + hs-source-dirs: + src + , src/chapter-1 + , src/chapter-2 + , src/chapter-3 + + other-modules: +-- Ch1 +-- , Ch2 +-- , Ch3 +-- , Data.Queue +-- , Data.Stack +-- , find-cycle +-- , intersection +-- , is-palindrome +-- , is-permutation +-- , is-rotation +-- , is-unique +-- , kth-last +-- , one-away +-- , palindrome-permutation +-- , partition +-- , Questions.MinStack +-- , remove-dups +-- , remove-node +-- , rotate-matrix +-- , string-compression +-- , sum-lists +-- , Test.MinStack +-- , Test.Queue +-- , Test.Stack +-- , url-encode +-- , zero-matrix + + build-depends: + base + , hspec + , QuickCheck + + other-extensions: diff --git a/haskell-solutions.cabal b/haskell-solutions.cabal deleted file mode 100644 index 7f3daf9..0000000 --- a/haskell-solutions.cabal +++ /dev/null @@ -1,83 +0,0 @@ --- Initial haskell-solutions.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/ - --- The name of the package. -name: haskell-solutions - --- The package version. See the Haskell package versioning policy (PVP) --- for standards guiding when and how versions should be incremented. --- http://www.haskell.org/haskellwiki/Package_versioning_policy --- PVP summary: +-+------- breaking API changes --- | | +----- non-breaking API additions --- | | | +--- code changes with no API change -version: 0.1.0.0 - --- A short (one-line) description of the package. --- synopsis: - --- A longer description of the package. --- description: - --- The license under which the package is released. --- license: - --- The file containing the license text. -license-file: LICENSE - --- The package author(s). -author: various contributors - --- An email address to which users can send suggestions, bug reports, and --- patches. -maintainer: none - --- A copyright notice. --- copyright: - --- category: - -build-type: Simple - --- Extra files to be distributed with the package, such as examples or a --- README. --- extra-source-files: - --- Constraint on the version of Cabal needed to build this package. -cabal-version: >=1.10 - - -library - -- Modules exported by the library. - exposed-modules: Main - - -- Modules included in this library but not exported. - -- other-modules: - - -- LANGUAGE extensions used by modules in this package. - -- other-extensions: - - -- Other library packages from which modules are imported. - build-depends: base >=4.8 && <4.9 - , hspec - , QuickCheck - - -- Directories containing source files. - hs-source-dirs: src - , src/chapter-1 - , src/chapter-2 - , src/chapter-3 --- , src/chapter-4 - - -- Base language which the package is written in. - default-language: Haskell2010 - -test-suite tests - ghc-options: -Wall -fno-warn-orphans - type: exitcode-stdio-1.0 - main-is: Main.hs - hs-source-dirs: . - build-depends: base - , hspec - , QuickCheck - - default-language: Haskell2010 \ No newline at end of file diff --git a/src/Introduction/VI/Example01.hs b/src/Introduction/VI/Example01.hs new file mode 100644 index 0000000..3f60363 --- /dev/null +++ b/src/Introduction/VI/Example01.hs @@ -0,0 +1,14 @@ +{-| +Module : Introduction.VI.Example01 +Description : Introduction VI (Big O) Example 1 on Page 40 +-} +module Introduction.VI.Example01 where + +import Prelude hiding (sum) + +sum :: Int -> Int +sum n | n <= 0 = 0 + | otherwise = n + sum (n - 1) + +main :: IO () +main = print $ sum 4 diff --git a/src/Main.hs b/src/Main.hs index aff7163..b0f11df 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -1,7 +1,5 @@ module Main where -import Test.Hspec -import Test.QuickCheck import Ch1 import Ch2 import Ch3 diff --git a/src/chapter-1/Ch1.hs b/src/chapter-1/Ch1.hs index 1e6845f..4629786 100644 --- a/src/chapter-1/Ch1.hs +++ b/src/chapter-1/Ch1.hs @@ -1,10 +1,8 @@ module Ch1 where -import Test.QuickCheck import Test.Hspec ch1 :: IO () -ch1 = hspec $ do - describe "_______________________Chapter 1 tests_______________________" $ do - it "should have tests" $ do - True +ch1 = hspec $ + describe "_______________________Chapter 1 tests_______________________" $ + it "should have tests" True diff --git a/src/chapter-1/one-away.hs b/src/chapter-1/one-away.hs index ce36d70..3d35439 100644 --- a/src/chapter-1/one-away.hs +++ b/src/chapter-1/one-away.hs @@ -3,7 +3,7 @@ oneAway a b = a `elem` candidates where candidates = deletes ++ transposes ++ replaces ++ inserts strlen = 1 + length b splits = zipWith splitAt [0..strlen] (replicate strlen b) - deletes = [x ++ (tail y) | (x, y) <- splits, length y > 0] + deletes = [x ++ tail y | (x, y) <- splits, not (null y)] transposes = [x ++ head t : head y : tail t | (x, y) <- splits, length y > 1, let t = tail y] - replaces = [x ++ c : (tail y) | (x, y) <- splits, c <- ['a'..'z'], length y > 0] + replaces = [x ++ c : tail y | (x, y) <- splits, c <- ['a'..'z'], not (null y)] inserts = [x ++ c : y | (x, y) <- splits, c <- ['a'..'z']] diff --git a/src/chapter-1/zero-matrix.hs b/src/chapter-1/zero-matrix.hs index 84ee5c0..73a6711 100644 --- a/src/chapter-1/zero-matrix.hs +++ b/src/chapter-1/zero-matrix.hs @@ -4,7 +4,7 @@ zeroMatrix :: [[Integer]] -> [[Integer]] zeroMatrix x = [[zero i j v | (j, v) <- zip [0..] row] | (i, row) <- zip [0..] x] where zeroRows = zeroIndices x zeroCols = zeroIndices $ transpose x - zeroIndices y = map fst $ filter snd $ zip [0..] (map (any (== 0)) y) + zeroIndices y = map fst $ filter snd $ zip [0..] (map (elem 0) y) zero row col val | row `elem` zeroRows = 0 | col `elem` zeroCols = 0 | otherwise = val diff --git a/src/chapter-2/Ch2.hs b/src/chapter-2/Ch2.hs index 7b6eedc..4de5c8a 100644 --- a/src/chapter-2/Ch2.hs +++ b/src/chapter-2/Ch2.hs @@ -1,11 +1,9 @@ module Ch2 where -import Test.QuickCheck import Test.Hspec ch2 :: IO () -ch2 = hspec $ do - describe "_______________________Chapter 2 tests_______________________" $ do - it "should have tests" $ do - True +ch2 = hspec $ + describe "_______________________Chapter 2 tests_______________________" $ + it "should have tests" True diff --git a/src/chapter-3/Ch3.hs b/src/chapter-3/Ch3.hs index c43951a..a45f9ec 100644 --- a/src/chapter-3/Ch3.hs +++ b/src/chapter-3/Ch3.hs @@ -1,13 +1,12 @@ module Ch3 where -import Test.QuickCheck import Test.Hspec import Test.Stack import Test.Queue import Test.MinStack ch3 :: IO () -ch3 = hspec $ do +ch3 = hspec $ describe "_______________________Chapter 3 tests_______________________" $ do testStack testQueue diff --git a/src/chapter-3/Data/Queue.hs b/src/chapter-3/Data/Queue.hs index a3a3edb..58e0dca 100644 --- a/src/chapter-3/Data/Queue.hs +++ b/src/chapter-3/Data/Queue.hs @@ -6,7 +6,7 @@ instance Eq a => Eq (Queue a) where (==) a b = let a' = reorder a b' = reorder b in checkEq a' b' - where checkEq (Queue xs ys) (Queue xs' ys') = ys == ys' + where checkEq (Queue _ ys) (Queue _ ys') = ys == ys' mkQueue :: a -> Queue a mkQueue a = Queue [a] [] @@ -16,18 +16,18 @@ enqueue a (Queue xs ys) = Queue (a:xs) ys dequeue :: Queue a -> Queue a dequeue q = case reorder q of - (Queue xs (y:ys)) -> Queue xs ys - otherwise -> reorder q + (Queue xs (_:ys)) -> Queue xs ys + _ -> reorder q peek :: Queue a -> Maybe a peek a = case reorder a of - (Queue _ (y:ys)) -> Just y - otherwise -> Nothing + (Queue _ (y:_)) -> Just y + _ -> Nothing isEmpty :: Queue a -> Bool isEmpty (Queue [] []) = True isEmpty (Queue _ _ ) = False reorder :: Queue a -> Queue a -reorder q@(Queue xs (y:ys)) = q reorder (Queue xs []) = Queue [] (reverse xs) +reorder q = q diff --git a/src/chapter-3/Data/Stack.hs b/src/chapter-3/Data/Stack.hs index b82a39a..ba88a4b 100644 --- a/src/chapter-3/Data/Stack.hs +++ b/src/chapter-3/Data/Stack.hs @@ -1,22 +1,22 @@ module Data.Stack where -data Stack a = Stack [a] +newtype Stack a = Stack [a] deriving (Eq, Show) push :: a -> Stack a -> Stack a push a (Stack xs) = Stack (a:xs) pop :: Stack a -> Stack a -pop (Stack (x:xs)) = Stack xs +pop (Stack (_:xs)) = Stack xs pop (Stack []) = Stack [] peek :: Stack a -> Maybe a -peek (Stack (x:xs)) = Just x +peek (Stack (x:_)) = Just x peek (Stack []) = Nothing isEmpty :: Stack a -> Bool isEmpty (Stack []) = True -isEmpty (Stack xs) = False +isEmpty (Stack _) = False mkStack :: a -> Stack a mkStack a = Stack [a] diff --git a/src/chapter-3/Questions/MinStack.hs b/src/chapter-3/Questions/MinStack.hs index 31d4aa2..30a1f49 100644 --- a/src/chapter-3/Questions/MinStack.hs +++ b/src/chapter-3/Questions/MinStack.hs @@ -11,7 +11,7 @@ data MinStack a = MinStack (S.Stack a) (S.Stack a) push :: Ord a => a -> MinStack a -> MinStack a push a (MinStack s1 (S.Stack [])) = MinStack (S.push a s1) (S.mkStack a) -push a (MinStack s1 s2@(S.Stack (x:xs))) = +push a (MinStack s1 s2@(S.Stack (x:_))) = if a <= x then MinStack (S.push a s1) (S.push a s2) else MinStack (S.push a s1) s2 @@ -21,7 +21,7 @@ pop ms@(MinStack s1 s2) = case (S.peek s1, S.peek s2) of (Just a, Just b) -> if a > b then MinStack (S.pop s1) s2 else MinStack (S.pop s1) (S.pop s2) - otherwise -> ms + _ -> ms smin :: MinStack a -> Maybe a diff --git a/src/chapter-3/Test/MinStack.hs b/src/chapter-3/Test/MinStack.hs index 89dd9e9..2ae03a8 100644 --- a/src/chapter-3/Test/MinStack.hs +++ b/src/chapter-3/Test/MinStack.hs @@ -1,22 +1,22 @@ module Test.MinStack where -import Test.QuickCheck import Test.Hspec import Questions.MinStack import qualified Data.Stack as S +exStack :: MinStack Int exStack = push 1 (push 7 (push 2 (push 6 (mkMinStack 9)))) testMinStack :: SpecWith () testMinStack = describe "MinStack" $ do - describe "mkMinStack" $ do - it "should create a MinStack" $ do - (MinStack (S.mkStack 1) (S.mkStack 1) :: MinStack Int) `shouldBe` (mkMinStack 1) - describe "smin" $ do - it "should return the current min" $ do + describe "mkMinStack" $ + it "should create a MinStack" $ + (MinStack (S.mkStack 1) (S.mkStack 1) :: MinStack Int) `shouldBe` mkMinStack 1 + describe "smin" $ + it "should return the current min" $ smin exStack `shouldBe` (Just 1 :: Maybe Int) - describe "push and pop" $ do + describe "push and pop" $ it "should maintain min" $ do smin (push 0 exStack) `shouldBe` (Just 0 :: Maybe Int) smin (pop exStack) `shouldBe` (Just 2 :: Maybe Int) diff --git a/src/chapter-3/Test/Queue.hs b/src/chapter-3/Test/Queue.hs index 7c0e0c8..b72b8a0 100644 --- a/src/chapter-3/Test/Queue.hs +++ b/src/chapter-3/Test/Queue.hs @@ -1,6 +1,5 @@ module Test.Queue where -import Test.QuickCheck import Test.Hspec import Data.Queue @@ -23,24 +22,24 @@ testQueue = it "should maintain FIFO order" $ do peek enqueueQueue `shouldBe` Just 1 peek dequeueQueue `shouldBe` Just 3 - describe "Eq instance" $ do - it "should maintain equality if regardless of enqueue/dequeue state" $ do - (Queue [1,2,3] [] == Queue [] [3,2,1]) `shouldBe` True - describe "mkQueue" $ do - it "should create a single element queue" $ do - mkQueue 1 `shouldBe` Queue [1] [] - describe "enqueue" $ do - it "should add an element to the queue" $ do - enqueue 1 emptyQueue `shouldBe` Queue [1] [] - describe "dequeue" $ do - it "should remove an element from the queue" $ do + describe "Eq instance" $ + it "should maintain equality if regardless of enqueue/dequeue state" $ + Queue [1,2,3] [] `shouldBe` (Queue [] [3,2,1] :: Queue Int) + describe "mkQueue" $ + it "should create a single element queue" $ + mkQueue 1 `shouldBe` (Queue [1] [] :: Queue Int) + describe "enqueue" $ + it "should add an element to the queue" $ + enqueue 1 emptyQueue `shouldBe` (Queue [1] [] :: Queue Int) + describe "dequeue" $ + it "should remove an element from the queue" $ dequeue exQueue `shouldBe` Queue [] [4,3,2,1] describe "peek" $ do - it "should return the next element in the queue if it exists" $ do + it "should return the next element in the queue if it exists" $ peek exQueue `shouldBe` Just 5 - it "should not crash on an empty queue" $ do + it "should not crash on an empty queue" $ peek emptyQueue `shouldBe` (Nothing :: Maybe Int) - describe "isEmpty" $ do + describe "isEmpty" $ it "should tell if a given queue is empty" $ do isEmpty emptyQueue `shouldBe` True isEmpty exQueue `shouldBe` False diff --git a/src/chapter-3/Test/Stack.hs b/src/chapter-3/Test/Stack.hs index a74e353..198975b 100644 --- a/src/chapter-3/Test/Stack.hs +++ b/src/chapter-3/Test/Stack.hs @@ -2,7 +2,6 @@ module Test.Stack where import Data.Stack import Test.Hspec -import Test.QuickCheck import Data.Maybe (fromMaybe) exStack :: Stack Int @@ -24,22 +23,22 @@ testStack = fromMaybe 0 (peek pushedStack) `shouldBe` 1 fromMaybe 0 (peek popedStack) `shouldBe` 3 - describe "mkStack" $ do - it "should create a single element Stack" $ do - (mkStack 1) `shouldBe` (Stack [1]) - describe "push" $ do + describe "mkStack" $ + it "should create a single element Stack" $ + mkStack 1 `shouldBe` (Stack [1] :: Stack Int) + describe "push" $ it "should add an element to the stack" $ do push 0 exStack `shouldBe` Stack [0,1,2,3,4,5] push 1 emptyStack `shouldBe` mkStack 1 - describe "pop" $ do + describe "pop" $ it "should remove an element from the stack" $ do - pop exStack `shouldBe` (Stack [2,3,4,5]) + pop exStack `shouldBe` Stack [2,3,4,5] pop emptyStack `shouldBe` emptyStack - describe "peek" $ do + describe "peek" $ it "should return the first element in a stack" $ do peek exStack `shouldBe` Just 1 peek (Stack []) `shouldBe` (Nothing :: Maybe Int) - describe "isEmpty" $ do + describe "isEmpty" $ it "should tell if a given stack is empty" $ do isEmpty exStack `shouldBe` False isEmpty (Stack []) `shouldBe` True diff --git a/test/Introduction/VI/Example01Spec.hs b/test/Introduction/VI/Example01Spec.hs new file mode 100644 index 0000000..5594378 --- /dev/null +++ b/test/Introduction/VI/Example01Spec.hs @@ -0,0 +1,25 @@ +{-| +Module : Introduction.VI.Example01Spec +Description : Introduction VI (Big O) Example 1 on Page 40---Tests +-} +module Introduction.VI.Example01Spec (main, spec) where + +import Prelude hiding (sum) + +import qualified Prelude as P (sum) + +import Test.Hspec (describe, hspec, Spec) +import Test.Hspec.QuickCheck (prop) +import Test.QuickCheck ((==>)) +import Test.QuickCheck.Modifiers (Positive (Positive)) + +import Introduction.VI.Example01 hiding (main) + +main :: IO () +main = hspec spec + +spec :: Spec +spec = + describe "properties" $ + do prop "x <= 0 ==> sum x == 0" (\ x -> x <= 0 ==> sum x == 0) + prop "Posiitve x ==> sum x == Prelude.sum [1..x]" (\ (Positive x) -> sum x == P.sum [1..x]) diff --git a/test/Spec.hs b/test/Spec.hs new file mode 100644 index 0000000..a824f8c --- /dev/null +++ b/test/Spec.hs @@ -0,0 +1 @@ +{-# OPTIONS_GHC -F -pgmF hspec-discover #-}