aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--LICENSE21
-rw-r--r--README.md13
-rw-r--r--collatz.hs39
4 files changed, 74 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4967dc2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/collatz
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2ee9985
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Timo Wilken
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..df96978
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# Playing with the Collatz conjecture
+
+This program prints at least `SETSIZE` (its only command-line argument) numbers
+known to collapse to 1 for the Collatz conjecture. If the program loops
+infinitely, the number doesn't reach 1! This is obviously not a practical way of
+trying to prove the conjecture.
+
+## Try it
+
+```{sh}
+$ ghc -O2 -dynamic collatz
+$ ./collatz 100
+```
diff --git a/collatz.hs b/collatz.hs
new file mode 100644
index 0000000..ff7e8dd
--- /dev/null
+++ b/collatz.hs
@@ -0,0 +1,39 @@
+module Main where
+
+import System.Environment
+import Data.Foldable
+import qualified Data.Set as S
+
+collatz :: Integral a => a -> a
+collatz n = case n `mod` 2 of 0 -> n `div` 2
+ 1 -> 3*n + 1
+
+chain :: Integral a => a -> [a]
+chain = takeWhile (/= 1) . iterate collatz
+
+chainUntilKnown :: Integral a => S.Set a -> a -> [a]
+chainUntilKnown known start
+ | collatz start `elem` known = [start]
+ | otherwise = start : chainUntilKnown known (collatz start)
+
+checkNextUnknown :: Integral a => S.Set a -> S.Set a
+checkNextUnknown knownToCollapse = S.union knownToCollapse newKnown
+ where firstUnknown = head $ filter (`notElem` knownToCollapse) [1..]
+ newKnown = S.fromList $ chainUntilKnown knownToCollapse firstUnknown
+
+checkAll :: Integral a => [S.Set a]
+checkAll = iterate checkNextUnknown $ S.singleton 1
+
+data Args = Args Int
+
+handleArgs :: [String] -> Args
+handleArgs [] = Args 10
+handleArgs [setSize] = Args (read setSize :: Int)
+handleArgs _ = error "usage: collatz [SETSIZE=10]"
+
+main :: IO ()
+main = do
+ args <- getArgs
+ let Args wantedSize = handleArgs args
+ wantedSet = head . dropWhile ((< wantedSize) . S.size) $ checkAll
+ traverse_ print $ S.toAscList wantedSet