実例によるPureScript 4 章
演習はいっぱいあった。A, B, C, D, E とする。
演習 A.
こんなのでいいのかな。
isEven :: Int -> Boolean
isEven n =
if n == 0
then true
else if n == 1
then false
else if n < 0
then isEven (n + 2)
else isEven (n - 2)
evenCount :: Array Int -> Int
evenCount arr =
if null arr
then 0
else c + evenCount (unsafePartial tail arr)
where c = if isEven (unsafePartial head arr)
then 1
else 0
演習 B.
(\n -> n * n) <$> (1 .. 5)
filter (\n -> n >= 0) [-2, -1, 0, 1, 2]
infixl 4 filter as <$?>
演習 C.
isPrime :: Int -> Boolean
isPrime n =
if n < 2
then false
else if length (factors n) > 1
then false
else true
cartesianProduct :: forall a b. Array a -> Array b -> Array (Tuple a b)
cartesianProduct a b = do
x <- a
y <- b
pure (Tuple x y)
pythagoras3 :: Int -> Array (Array Int)
pythagoras3 n = do
a <- (1 .. n)
b <- (a .. n)
c <- (b .. n)
guard $ a * a + b * b == c * c
pure [a, b, c]
難しかった… 直積集合使った。改善の余地がありそうだが、今後レベルアップした際に振り返りたい。
factorizations :: Int -> Array (Array Int)
factorizations n = nubBy compare (concatMap (\a -> factorsProducts a) (factors n))
where
factorsProducts :: Array Int -> Array (Array Int)
factorsProducts [1, a] = [[a]]
factorsProducts [a, 1] = [[a]]
factorsProducts [a, b] = (\x -> sort $ (fst x) <> (snd x)) <$> (cartesianProduct (factorizations a) (factorizations b))
factorsProducts _ = [[]]
演習 D.
foldl (&&) true
(||) ではなく (==) なので、最後の要素が false となっている配列、だと思う。
countTailCall :: forall a. (a -> Boolean) -> Array a -> Int
countTailCall = countTailCall' 0
where
countTailCall' acc _ [] = acc
countTailCall' acc p xs = if p (unsafePartial head xs)
then countTailCall' (acc + 1) p (unsafePartial tail xs)
else countTailCall' acc p (unsafePartial tail xs)
生成された JS で tco (tail call optimization) が効いていることを確認した。この記事が大変勉強になった。https://23prime.hatenablog.com/entry/2018/12/02/230657
例で示されている count 関数は count コール後に + 1 がついているので呼び出し後に計算が必要であるが、上記の countTailCall はそのような計算はないので大丈夫。
foldl (\x xs -> cons xs x) []
からの
foldl (flip cons) []
演習 E.
onlyFiles :: Path -> Array Path
onlyFiles file = if isDirectory file
then concatMap onlyFiles (ls file)
else [file]
maxSizeFile :: Path -> Path
maxSizeFile path = foldl maxPath path (onlyFiles path)
where
maxPath :: Path -> Path -> Path
maxPath a b = if (size a) > (size b) then a else b
minSizeFile :: Path -> Path
minSizeFile path = foldl minPath path (onlyFiles path)
where
minPath :: Path -> Path -> Path
minPath a b = if isNothing(sizeB) || (isJust(sizeA) && (sizeA < sizeB)) then a else b
where
sizeA = size a
sizeB = size b
minSizeFile の Maybe の処理はもうちょっとなんとかなりそうだが… レベルアップして帰って来たときの課題にしよう。
whereIs :: String -> Maybe Path
whereIs s = head do
file <- allFiles root
child <- ls file
guard $ s == (filename child)
pure file
こっちの head は Data.Array の方の head (Data.Array.Partial ではない)。
この記事が気に入ったらサポートをしてみませんか?