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

HW: Week 1 #4

Open
wants to merge 4 commits into
base: ogz
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .ghci
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:set -isrc/Cis194/Hw/Week1.hs -itest/Cis194/Hw
Copy link
Collaborator

Choose a reason for hiding this comment

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

I didn't know you could do this. That is awesome!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, this is another thing I tried using before I was able to run the spec file. IIRC the .ghci file has no impact when executing stack runghc.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That is too bad. I wonder if stack has something like that. Like can I set a default command? I'll do some digging when I get a moment.

30 changes: 23 additions & 7 deletions src/Cis194/Hw/Week1.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@ module Cis194.Hw.Week1 where
-------------

toDigits :: Integer -> [Integer]
toDigits x = [x]
toDigits = reverse . toDigitsRev

toDigitsRev :: Integer -> [Integer]
toDigitsRev x = [x]
toDigitsRev x
| x > 0 = (mod x 10) : (toDigitsRev $ div x 10)
| otherwise = []
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if having the thing that happens the most on top of the where clauses have a performance gain? I would think so since the compiler doesn't know which will happen more often. I like that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Technically, yes, I believe there is a slight performance gain when placing the most frequently matched patterns as near to the top as possible. I just wanted to put the "default" case last. Even if the compiler was unable to optimize for your use cases, if the function was being called frequently (enough to warrant optimization) then you would hopefully benefit from processor branch prediction.

I found these relevant posts
https://elixirforum.com/t/does-placing-the-most-likely-matched-function-heads-first-offer-any-benefit/17428
https://stackoverflow.com/questions/48572426/performance-of-exhaustive-haskell-pattern-matching


doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther xs = xs
doubleEveryOther xs = reverse $ doubleEveryOther' $ reverse xs
doubleEveryOther' [] = []
doubleEveryOther' (x:xs) = x : doubleEveryOther'' xs
doubleEveryOther'' [] = []
doubleEveryOther'' (x:xs) = x * 2 : doubleEveryOther' xs

sumDigits :: [Integer] -> Integer
sumDigits _ = 0
sumDigits = sum . (map $ sum . toDigits)

validate :: Integer -> Bool
validate _ = False
-- validate x = mod (sumDigits (doubleEveryOther $ toDigits x)) 10 == 0
validate x = mod ((sumDigits . doubleEveryOther . toDigits) x) 10 == 0

---------------------
-- Towers of Hanoi --
Expand All @@ -27,7 +34,16 @@ type Peg = String
type Move = (Peg, Peg)

hanoi :: Integer -> Peg -> Peg -> Peg -> [Move]
hanoi _ _ _ _ = []
hanoi 1 a b _ = [(a, b)]
hanoi 0 _ _ _ = []
hanoi n a b c = (hanoi (n - 1) a c b) ++ (hanoi 1 a b c) ++ (hanoi (n - 1) c b a)

hanoi4 :: Integer -> Peg -> Peg -> Peg -> Peg -> [Move]
hanoi4 _ _ _ _ _ = []
hanoi4 2 a b c _ = [(a, c), (a, b), (c, b)]
hanoi4 1 a b _ _ = [(a, b)]
hanoi4 0 _ _ _ _ = []
Copy link
Collaborator

Choose a reason for hiding this comment

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

All of the hanoi4 above this point can just delegate to hanoi since the outcomes are the same. I spent some time looking at this on mine and trying to see how I could utilize hanoi and noticed those outputs are the same.

Copy link
Collaborator Author

@WizardOfOgz WizardOfOgz Nov 20, 2018

Choose a reason for hiding this comment

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

Your comment made me realize that the case hanoi4 2 a b c _ on line 42 can be omitted completely (which I just tested)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice, I didn't think about that.

hanoi4 n a b c d =
(hanoi4 (n - m) a c b d) ++
(hanoi m a b d) ++
(hanoi4 (n - m) c b a d)
where m = floor (sqrt (fromIntegral (n * 2)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

You found a minimal solution! That is awesome. I looked at it for quite a while and gave up. I also love that you used hanoi in this solution.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@adkron I found out that it's not actually an optimal solution (technically no solution has been proven to be optimal, but many believe that this is optimal). I didn't properly form a recurrence relation when analyzing the algorithm...mostly because it was a complex case and my math skills are weak. However, I got close enough to satisfy the specs, which made me happy.

18 changes: 8 additions & 10 deletions test/Cis194/Hw/Week1Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ module Cis194.Hw.Week1Spec (main, spec) where

import Test.Hspec
import Test.QuickCheck
import Cis194.Hw.Week1
{-import Cis194.Hw.AcceptHanoi-}
import Cis194.Hw.Week1 hiding (main)
adkron marked this conversation as resolved.
Show resolved Hide resolved
import Cis194.Hw.AcceptHanoi

main :: IO ()
main = hspec spec
Expand Down Expand Up @@ -65,16 +65,15 @@ spec = do
it "should solve for 1 disc" $ do
hanoi 1 "a" "b" "c" `shouldBe` [("a", "b")]

{-it "should solve for 2 discs" $ do-}
{-(acceptHanoi3 hanoi 2) `shouldBe` Just (HanoiState3 [] [1..2] [])-}
it "should solve for 2 discs" $ do
(acceptHanoi3 hanoi 2) `shouldBe` Just (HanoiState3 [] [1..2] [])

{-it "should solve for 5 discs" $ do-}
{-(acceptHanoi3 hanoi 5) `shouldBe` Just (HanoiState3 [] [1..5] [])-}
it "should solve for 5 discs" $ do
(acceptHanoi3 hanoi 5) `shouldBe` Just (HanoiState3 [] [1..5] [])

{-it "should solve for 10 discs" $ do-}
{-(acceptHanoi3 hanoi 10) `shouldBe` Just (HanoiState3 [] [1..10] [])-}
it "should solve for 10 discs" $ do
(acceptHanoi3 hanoi 10) `shouldBe` Just (HanoiState3 [] [1..10] [])

{- This is an optional assigment
describe "hanoi4" $ do
it "should return an empty list for zero discs" $ do
hanoi4 0 "a" "b" "c" "d" `shouldBe` []
Expand All @@ -93,4 +92,3 @@ spec = do

it "should find an optimal solution for 15 disks" $ do
length (hanoi4 15 "a" "b" "c" "d") `shouldBe` 129
-}