aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Sucan <jan@jansucan.com>2023-09-27 15:59:19 +0200
committerJan Sucan <jan@jansucan.com>2023-09-27 15:59:19 +0200
commit1bb8a1fb9a13840f96fd395093ae1a8694917ac3 (patch)
treeaa8a68a308c7278507b93a74df8179202a0cd7a8
parent5d47dc25454d0e2e9472aedd7b66099821e6658c (diff)
9_b_4: Add solution
-rw-r--r--README.md4
-rw-r--r--ch09/9_b_4.hs94
-rw-r--r--ch09/ControlledVisit.hs1
-rw-r--r--ch09/Module_9_b_3.hs (renamed from ch09/9_b_3.hs)16
-rw-r--r--ch09/test-9_b_4/A.cbin0 -> 1 bytes
-rw-r--r--ch09/test-9_b_4/B.cbin0 -> 2 bytes
-rw-r--r--ch09/test-9_b_4/C.cbin0 -> 3 bytes
-rw-r--r--ch09/test-9_b_4/D.hsbin0 -> 4 bytes
-rw-r--r--ch09/test-9_b_4/E.hsbin0 -> 5 bytes
-rw-r--r--ch09/test-9_b_4/F.hsbin0 -> 6 bytes
10 files changed, 104 insertions, 11 deletions
diff --git a/README.md b/README.md
index 9893c65..6e79e6a 100644
--- a/README.md
+++ b/README.md
@@ -127,8 +127,8 @@ are prefixed with 'Module_'.
| **_9_a_1_** | yes | 221 | 9. I/O case study: a library for searching the filesystem |
| **_9_b_1_** | yes | 228 | |
| 9_b_2 | yes | | |
-| 9_b_3 | yes | | |
-| 9_b_4 | | | |
+| Module_9_b_3 | yes | | |
+| 9_b_4 | yes | | |
| **_9_c_1_** | | 232 | |
| 9_c_2 | | | |
| 9_c_3 | | | |
diff --git a/ch09/9_b_4.hs b/ch09/9_b_4.hs
new file mode 100644
index 0000000..b771271
--- /dev/null
+++ b/ch09/9_b_4.hs
@@ -0,0 +1,94 @@
+-- Write a wrapper for 'traverse' that lets you control traversal using one
+-- predicate and filter results using another.
+
+-- From the assignment it's not completely clear what controlling traversal
+-- means.
+--
+-- Let's assume that it means visiting files for which the control predicate is
+-- true first.
+
+import ControlledVisit (traverse', Info(..))
+-- Use predicates for the new Info type from the previous exercise
+import Module_9_b_3
+
+import Data.List
+import System.FilePath (takeExtension)
+
+traverseWrapper :: (Info -> Bool) -> (Info -> Bool) -> FilePath -> IO [Info]
+traverseWrapper orderP filterP path = do
+ res <- traverse' (order orderP) path
+ return (filterResults filterP res)
+
+compareInfos :: (Info -> Bool) -> Info -> Info -> Ordering
+compareInfos p infoA infoB = if a && (not b)
+ then LT -- "greater" Info should appear in the sorted list first
+ else if (not a) && b
+ then GT
+ else EQ
+ where a = p infoA
+ b = p infoB
+
+order :: (Info -> Bool) -> ([Info] -> [Info])
+order p = sortBy (compareInfos p)
+
+filterResults :: (Info -> Bool) -> [Info] -> [Info]
+filterResults p infos = filter p infos
+
+
+-- > ls -l
+-- total 24
+-- -rw-r--r-- 1 jan users 1 Sep 27 15:28 A.c
+-- -rw-r--r-- 1 jan users 2 Sep 27 15:28 B.c
+-- -rw-r--r-- 1 jan users 3 Sep 27 15:28 C.c
+-- -rw-r--r-- 1 jan users 4 Sep 27 15:28 D.hs
+-- -rw-r--r-- 1 jan users 5 Sep 27 15:28 E.hs
+-- -rw-r--r-- 1 jan users 6 Sep 27 15:28 F.hs
+
+idTest :: Info -> Bool
+idTest _ = True
+
+-- ghci> :l 9_b_4.hs
+-- [1 of 3] Compiling ControlledVisit ( ControlledVisit.hs, interpreted )
+-- [2 of 3] Compiling Module_9_b_3 ( Module_9_b_3.hs, interpreted )
+-- [3 of 3] Compiling Main ( 9_b_4.hs, interpreted )
+-- Ok, three modules loaded.
+
+sizeTest1 = infoSize `lesserP` (Just 3)
+
+sizeTest2 = infoSize `greaterP` (Just 2)
+
+nameTest = (liftPath takeExtension) `equalP` ".c"
+
+complexTest1 = (infoSize `lesserP` (Just 4)) `andP` ((liftPath takeExtension) `equalP` ".hs")
+
+complexTest2 = (infoSize `greaterP` (Just 4)) `andP` (infoSize `lesserP` (Just 6))
+ `andP` ((liftPath takeExtension) `equalP` ".hs")
+
+-- ghci> traverseWrapper idTest idTest "test-9_b_4/"
+-- [Info {infoPath = "test-9_b_4/", ..., infoSize = Nothing, ...},
+-- Info {infoPath = "test-9_b_4/F.hs", ..., infoSize = Just 6, ...},
+-- Info {infoPath = "test-9_b_4/A.c", ..., infoSize = Just 1, ...},
+-- Info {infoPath = "test-9_b_4/B.c", ..., infoSize = Just 2, ...},
+-- Info {infoPath = "test-9_b_4/D.hs", ..., infoSize = Just 4, ...},
+-- Info {infoPath = "test-9_b_4/E.hs", ..., infoSize = Just 5, ...},
+-- Info {infoPath = "test-9_b_4/C.c", ..., infoSize = Just 3, ...}]
+
+-- ghci> traverseWrapper sizeTest1 idTest "test-9_b_4/"
+-- [Info {infoPath = "test-9_b_4/", ..., infoSize = Nothing, ...},
+-- Info {infoPath = "test-9_b_4/A.c", ..., infoSize = Just 1, ...},
+-- Info {infoPath = "test-9_b_4/B.c", ..., infoSize = Just 2, ...},
+-- Info {infoPath = "test-9_b_4/F.hs", ..., infoSize = Just 6, ...},
+-- Info {infoPath = "test-9_b_4/D.hs", ..., infoSize = Just 4, ...},
+-- Info {infoPath = "test-9_b_4/E.hs", ..., infoSize = Just 5, ...},
+-- Info {infoPath = "test-9_b_4/C.c", ..., infoSize = Just 3, ...}]
+
+-- ghci> traverseWrapper sizeTest2 nameTest "test-9_b_4/"
+-- [Info {infoPath = "test-9_b_4/C.c", ..., infoSize = Just 3, ...},
+-- Info {infoPath = "test-9_b_4/A.c", ..., infoSize = Just 1, ...},
+-- Info {infoPath = "test-9_b_4/B.c", ..., infoSize = Just 2, ...}]
+
+-- ghci> traverseWrapper idTest complexTest1 "test-9_b_4/"
+-- []
+
+-- ghci> traverseWrapper idTest complexTest2 "test-9_b_4/"
+-- [Info {infoPath = "test-9_b_4/E.hs", ..., infoSize = Just 5, ...}]
diff --git a/ch09/ControlledVisit.hs b/ch09/ControlledVisit.hs
index 9793cdd..52f4e9a 100644
--- a/ch09/ControlledVisit.hs
+++ b/ch09/ControlledVisit.hs
@@ -4,6 +4,7 @@ module ControlledVisit
, getInfo
, getUsefulContents
, isDirectory
+ , traverse'
) where
import Control.Exception
diff --git a/ch09/9_b_3.hs b/ch09/Module_9_b_3.hs
index 882f7db..ce38717 100644
--- a/ch09/9_b_3.hs
+++ b/ch09/Module_9_b_3.hs
@@ -1,18 +1,15 @@
-- Take the predicates and combinators from "Gluing predicates together" on page
-- 224 and make them work with our new Info type.
+module Module_9_b_3 where
+
{-- From examples/examples/ch09/BetterPredicate.hs modified according to the assignment --}
import Data.Time (UTCTime(..))
import System.Directory (Permissions(..))
import System.FilePath (takeExtension)
+import ControlledVisit (Info(..))
-data Info = Info {
- infoPath :: FilePath
- , infoPerms :: Maybe Permissions
- , infoSize :: Maybe Integer
- , infoModTime :: Maybe UTCTime
- } deriving (Eq, Ord, Show)
type InfoF a = Info -> a
@@ -51,9 +48,10 @@ myTest2 = (liftPath takeExtension `equalP` ".cpp") `andP`
(infoSize `greaterP` (Just 131072))
{-- End of code from examples --}
--- ghci> :l 9_b_3.hs
--- [1 of 1] Compiling Main ( 9_b_3.hs, interpreted )
--- Ok, one module loaded.
+-- ghci> :l Module_9_b_3.hs
+-- [1 of 2] Compiling ControlledVisit ( ControlledVisit.hs, interpreted )
+-- [2 of 2] Compiling Module_9_b_3 ( Module_9_b_3.hs, interpreted )
+-- Ok, two modules loaded.
-- ghci> infoA = Info "asdf.cpp" Nothing (Just 131072) Nothing
-- ghci> myTest2 infoA
diff --git a/ch09/test-9_b_4/A.c b/ch09/test-9_b_4/A.c
new file mode 100644
index 0000000..f76dd23
--- /dev/null
+++ b/ch09/test-9_b_4/A.c
Binary files differ
diff --git a/ch09/test-9_b_4/B.c b/ch09/test-9_b_4/B.c
new file mode 100644
index 0000000..09f370e
--- /dev/null
+++ b/ch09/test-9_b_4/B.c
Binary files differ
diff --git a/ch09/test-9_b_4/C.c b/ch09/test-9_b_4/C.c
new file mode 100644
index 0000000..4227ca4
--- /dev/null
+++ b/ch09/test-9_b_4/C.c
Binary files differ
diff --git a/ch09/test-9_b_4/D.hs b/ch09/test-9_b_4/D.hs
new file mode 100644
index 0000000..593f470
--- /dev/null
+++ b/ch09/test-9_b_4/D.hs
Binary files differ
diff --git a/ch09/test-9_b_4/E.hs b/ch09/test-9_b_4/E.hs
new file mode 100644
index 0000000..40b450d
--- /dev/null
+++ b/ch09/test-9_b_4/E.hs
Binary files differ
diff --git a/ch09/test-9_b_4/F.hs b/ch09/test-9_b_4/F.hs
new file mode 100644
index 0000000..ab2c684
--- /dev/null
+++ b/ch09/test-9_b_4/F.hs
Binary files differ