02

27

[Haskell] 第7回 演習問題と解答例

2013.02.27(21:02)

関数型プログラミング言語 社内学習会 第7回 型や型クラスを自分で作ろう 演習問題と解答例
講師がこしらえた問題を解いてみた

{-# OPTIONS -Wall -Werror #-}
module Exercise7 where
import Test.HUnit

-- | EX1
{- 
data キーワードを使って、a 型の値を 1 つ保持する
Nullable a 型を作ってください。Nullable a 型は、無効な値
を表す Null 値か、有効な値を表す Effective x 値を持ちます。
x は a 型の値になります。なお、等値比較できるようにEq 型クラスと、
ghci コマンドなどで表示できるように Show 型クラスから自動導出す
るように宣言してください。
-}
data Nullable a = Null | Effective a
                  deriving (Eq,Show)

-- | case式を使ってみました。
-- | EX2(a)
{-
Nullable a 型の引数を 1 つ取り、その値が Null なら Falseを、
そうでなければ True を返す関数を作って下さい。
型宣言:
hasValue :: Nullable a -> Bool
実行例:
ghci> hasValue ( Effective 100 )
True
ghci> hasValue Null
False
-}
hasValue :: Nullable a -> Bool
hasValue nu = case nu of
              Null -> False
              Effective _ -> True

-- | EX2(b)
{-
Nullable a 型の引数を 1 つ取り、それが Effective x 値であれば 
x を返し、Null の場合は “invalid operation” を表示して例外を
発生させる関数を作って下さい。
型宣言 : 
value :: Nullable a -> a
実行例 : ghci> value ( Effective 20 )
20
ghci> value ( Effective [ 1,2,3 ] )
[ 1,2,3 ]
ghci> value Null
*** Exception : invalid operation
-}
value :: Nullable a -> a
value nu =  case nu of
            Null -> error "invalid operation"
            Effective a -> a

-- | EX3
{-
整数型の引数を 2 つ取り、1 つ目 (分子) の値を 2 つ目 (分母) の値で
除算した結果をNullable a 型の値として返す関数を作って下さい。
型宣言:
divNull :: 考えてみて下さい
実行イメージ:
divNull 1 0 == Null
divNull 2 1 == Effective 2
divNull 0 1 == Effective 0
divNull 0 0 == Null
-}
divNull :: Int -> Int -> Nullable Int
divNull nu1 nu2 = case (nu1,nu2) of
                  (_,0) -> Null
                  (n1,n2) -> Effective (n1 `div` n2)

-- | EX4
{-
Nullable a 型の値 ( a は整数型 ) を 2つ取り、
1つ目の値 (分子) を 2つ目の値 (分母) で除算した結果を
Nullable a 型の値として返す関数を作って下さい。
ただし、引数のいずれか一方、または両方が Null 値の場合は Null を返
します。また、分母が Effective 0 値の場合も Null を返します。
型宣言:
divNullEx :: 考えてみて下さい
実行時のイメージ:
divNullEx Null Null == Null
divNullEx ( Effective 20 ) Null == Null
divNullEx Null ( Effective 5 ) == Null
divNullEx ( Effective 20 ) ( Effective 0 ) == Null
divNullEx ( Effective 0 ) ( Effective 10 ) == Effective 0
divNullEx ( Effective 0 ) ( Effective 0 ) == Null
divNullEx ( Effective 100 ) ( Effective 20 ) == Effective 5
-}
divNullEx :: Nullable Int -> Nullable Int -> Nullable Int
divNullEx nu1 nu2 = case (nu1,nu2) of
                    (Null,_) -> Null
                    (_,Null) -> Null
                    (Effective _,Effective 0) -> Null
                    (Effective n1,Effective n2) -> Effective (n1 `div` n2)

-- | EX5
{-
Nullable を Functor にしよう
(a) Nullable をFunctor にする instance 宣言を作って下さい。
fmap 関数(メソッド)の実装を与えることをお忘れなく。
(b) Nullable a 型の引数を 1 つ取って、有効な a 型の値がある
場合はそれを 2 倍した a 型の値を保有する
Nullable a 型を返す関数を作って下さい。
型宣言: 
doubleNull :: 考えてみて下さい。
実行イメージ: 
doubleNull Effective 100 == Effective 200
doubleNull Effective 200.1 == Effective 400.2
doubleNull Null == Null
-}
instance Functor Nullable where
  fmap f (Effective a) = Effective (f a)
  fmap _ Null = Null

doubleNull :: (Num a) => Nullable a -> Nullable a
doubleNull nu = fmap (*2) nu

-- | ユニットテスト
nullableTest :: Test
nullableTest = test [
    Effective (10::Int) == Effective 10 ~=? True,
    hasValue (Effective (100::Int)) ~=? True,
    hasValue Null ~=? False,
    value (Effective (20::Int)) ~=? 20,
    value (Effective ([1,2,3]::[Int])) ~=? [1,2,3],

    divNull 1 0 ~=? Null,
    divNull 2 1 ~=? Effective 2,
    divNull 0 1 ~=? Effective 0,
    divNull 0 0 ~=? Null,

    divNullEx Null Null ~=? Null,
    divNullEx (Effective 20) Null ~=? Null,
    divNullEx Null (Effective 5) ~=? Null,
    divNullEx (Effective 20) (Effective 0) ~=? Null,
    divNullEx (Effective 0) (Effective 10) ~=? Effective 0,
    divNullEx (Effective 0) (Effective 0) ~=? Null,
    divNullEx (Effective 100) (Effective 20) ~=? Effective 5,

    doubleNull ((Effective 100)::Nullable Int) ~=? Effective 200,
    doubleNull ((Effective 200.1)::Nullable Float) ~=? Effective 400.2,
    doubleNull (Null::Nullable Int) ~=? Null,

    True ~=? True
 ]

main :: IO ()
main = do
  _ <- runTestTT nullableTest
  _ <- value Null
  return ()


プロフィール

島敏博

Shima Toshihiro 島敏博
信州アルプスハイランド在住。HaskellとElixirが好き。組み込みソフトウェアアーキテクト、C++プログラマ、山歩き、美術館巡り、和食食べ歩き、日本赤十字社救急法指導員、インデックス投資、クラシック音楽、SESSAME会員、状態マシン設計、モデル駆動開発、ソフトウェアプロダクトライン、Rubyist、実践ビジネス英語

■ ツイッター
http://twitter.com/saltheads
■ Facebook
http://www.facebook.com/saltheads
■ Qiita
http://qiita.com/saltheads

印刷する場合は、ブラウザの印刷メニューではなく、このページの上から3cmくらいの青いところにある、「印刷」を押してみてください。少しうまく印刷できます。まだ完全ではないのですが、これで勘弁してください。


カテゴリ
最新記事
月別アーカイブ
最新コメント
検索フォーム
リンク
sessame
RSSリンクの表示