Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@7shi

【解答例】Haskell Maybeモナド 超入門

More than 5 years have passed since last update.

Haskell Maybeモナド 超入門の解答例です。

フィボナッチ数

【問1】次の関数fibでエラーを回避するためMaybeモナドで書き換えてください。

import Control.Applicative

fib 0 = Just 0
fib 1 = Just 1
fib n | n > 1     = (+) <$> fib (n - 2) <*> fib (n - 1)
      | otherwise = Nothing

main = do
    print $ fib (-1)
    print $ fib 6
実行結果
Nothing
Just 8

再実装

bind

【問2】Maybeモナドを扱うbindを実装してください。

(Just a) `bind` b = b a
Nothing  `bind` _ = Nothing

main = do
    print $ Just 1 `bind` \a -> Just $ a * 2
    print $ Just 1 `bind` \a -> Nothing `bind` \b -> Just $ a * b
実行結果
Just 2
Nothing

mapMaybe

再帰

【問3】mapMaybeを再帰で再実装して、先ほどのサンプルで検証してください。

import Control.Applicative

mapMaybe _ []     = []
mapMaybe f (x:xs) = case f x of
    Just y  -> y : mapMaybe f xs
    Nothing ->     mapMaybe f xs

fact 0 = Just 1
fact n | n > 0     = (n *) <$> fact (n - 1)
       | otherwise = Nothing

facts n = ( map      fact [n, n - 1, n - 2]
          , mapMaybe fact [n, n - 1, n - 2]
          )

main = do
    print $ facts 3
    print $ facts 2
    print $ facts 1  -- cで失敗
    print $ facts 0  -- bで失敗
実行結果
([Just 6,Just 2,Just 1],[6,2,1])
([Just 2,Just 1,Just 1],[2,1,1])
([Just 1,Just 1,Nothing],[1,1])
([Just 1,Nothing,Nothing],[1])

foldr

【問4】問3の解答をfoldrで書き換えてください。

import Control.Applicative

mapMaybe f = (`foldr` []) $ \x xs -> case f x of
    Just x' -> x':xs
    Nothing ->    xs

fact 0 = Just 1
fact n | n > 0     = (n *) <$> fact (n - 1)
       | otherwise = Nothing

facts n = ( map      fact [n, n - 1, n - 2]
          , mapMaybe fact [n, n - 1, n - 2]
          )

main = do
    print $ facts 3
    print $ facts 2
    print $ facts 1  -- cで失敗
    print $ facts 0  -- bで失敗
実行結果
([Just 6,Just 2,Just 1],[6,2,1])
([Just 2,Just 1,Just 1],[2,1,1])
([Just 1,Just 1,Nothing],[1,1])
([Just 1,Nothing,Nothing],[1])

文字列チェック

【問5】文字列sが「x文字の連続した数字+y文字の連続した大文字」で構成されるか判定する関数numUpper x y sを実装してください。成功した場合はJust s、失敗した場合はNothingを返してください。余計な文字は含まないものとします。

import Data.Char
import Control.Monad

numUpper x y s = do
    guard $ length s == x + y
    guard $ length (filter isDigit $ take x s) == x
    guard $ length (filter isUpper $ drop x s) == y
    Just s

main = do
    print $ numUpper 3 2 "123AB"
    print $ numUpper 3 2 "123ABC"
    print $ numUpper 3 2 "12ABC"
実行結果
Just "123AB"
Nothing
Nothing

Alternative

【問6】文字列sの先頭3文字が「数字+大文字+小文字」または「大文字+小文字+小文字」で構成されるかを判定する関数check sを実装してください。<|>を使って、成功した場合はJust s、失敗した場合はNothingを返してください。後続の文字は判定に影響しないものとします。

import Data.Char
import Control.Applicative
import Control.Monad

check s = do
    guard $ length s >= 3
    do
        guard $ isDigit $ s !! 0
        guard $ isUpper $ s !! 1
        <|> do
        guard $ isUpper $ s !! 0
        guard $ isLower $ s !! 1
    guard $ isLower $ s !! 2
    Just s

main = do
    print $ check "1"
    print $ check "2Ab"
    print $ check "Abc"
    print $ check "Ab1"
    print $ check "1AB"
実行結果
Nothing
Just "2Ab"
Just "Abc"
Nothing
Nothing
0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
7shi

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?