ITコンサルの日常

ITコンサル会社に勤務する普通のITエンジニアの日常です。

「Ansi Common Lisp」5章練習問題 - Haskell版

3. 引数の平方を返す関数を定義せよ。ただし、引数が5以下の正の整数である場合は平方の計算を行わないものとする。

mySquare :: Int -> Int
mySquare x
  | (x >= 0 && x <= 5) = x
  | otherwise          = x * x


main = do print $ mySquare 0
          print $ mySquare 5
          print $ mySquare (-5)
          print $ mySquare 6

結果はこう。

0
5
25
36

-5はカッコをつけないと、
print $ (mySquare - 5)
と扱われてしまうので注意らしいです。

    No instance for (Num (Integer -> Integer))
      arising from use of `-' at ex5-3.hs:9:18-28
    Possible fix:
      add an instance declaration for (Num (Integer -> Integer))
    In the second argument of `($)', namely `mySquare - 5'
    In the expression: print $ (mySquare - 5)
    In a 'do' expression: print $ (mySquare - 5)

5. オブジェクトxとベクタvを引数として、vの中でxの直前にくる全オブジェクトを返すような関数を定義せよ。

precedes :: (Eq a) => a -> [a] -> [a]
precedes x [] = []
precedes x (v:[]) = []
precedes x (v:vs) = let result = precedes x vs
                    in if (head vs) == x then
                         if elem v result then
                           result
                         else
                           v : result
                       else
                         result

main = print $ precedes 'a' "abracadabra"
precedes x (v:[]) = []

みたいな書き方できるんですね。ちょっとした発見でした。
結果はこう。

"cdr"

6. 1つのオブジェクトと1つのリストを引数として、このリストの要素間にオブジェクトを挿入した新しいリストを返す関数を、反復と再帰の両方の方法で定義せよ。

intersperse :: String -> String
intersperse x = cdr $ concatMap (\n -> "-" ++ [n]) x

cdr :: [a] -> [a]
cdr [] = []
cdr (x:xs) = xs

main = print $ intersperse "abcd"

結果はこう。

"a-b-c-d"

7. 数のリストを引数として、連続するペアの差が1となる場合に真を返す関数を以下の3つの方法で定義せよ。

testListDiffIs1 :: [Int] -> Bool
testListDiffIs1 [] = False
testListDiffIs1 (x:[]) = True
testListDiffIs1 (x:xs) = (abs(x - (head xs)) == 1) && (testListDiffIs1 xs)

main = do print $ testListDiffIs1 [1,2,3]
          print $ testListDiffIs1 [3,2,1]
          print $ testListDiffIs1 [3,1,2]
          print $ testListDiffIs1 [3,2,3]
          print $ testListDiffIs1 [3,3,2]

結果はこう。

True
True
False
True
False

8. ベクタの要素の最大・最小の2値を返す(二重でない)再帰関数を定義せよ。

vectorMaxMin :: [Int] -> (Int,Int)
vectorMaxMin [] = (0,0)
vectorMaxMin (x:[]) = (x,x)
vectorMaxMin (x:xs) = let result = vectorMaxMin xs
                      in case x of
                           x | x > (fst result) -> (x, (snd result))
                             | x < (snd result) -> ((fst result), x)
                             | otherwise        -> result

main = print $ vectorMaxMin [3,1,2,5,4]

Haskellにはelseifがない(?)上に、
if 〜 then 〜 else (if 〜 then 〜 else 〜)みたいに
ネストしたif文を書けないらしい。ほんとかなあ。。

とりあえずcase式を使うことでなんとか出来ましたが、
こっちの方が見やすいですね。


結果はこう。

(5,1)