13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Elm の Maybe の知見

Last updated at Posted at 2020-02-25

Elm を書いていて、いい感じにリファクタできた部分を説明する。

やりたいこと

文字列のリストを受け取って、先頭の文字列を数値に変えた物を返す関数を作る。
この際、途中で Nothing になった場合は 0 を返す。

はじめに実装したもの

getFirstNum : List String -> Int
getFirstNum strs = maybeStringToInt <| List.head strs

maybeStringToInt : Maybe String -> Int
maybeStringToInt s =
    case s of
        Nothing ->
            0
        Just str ->
            stringToInt str

stringToInt : String -> Int
stringToInt s =
    let
        n = String.toInt s 
    in
    case n of
        Nothing ->
            0
        Just num ->
            num

とりあえず動くものを最初に作ることはよくあるが、これはひどい...。

リファクタしてみる

文字列から数値への変換

Elm の公式ドキュメントをみてみる。
https://package.elm-lang.org/packages/elm/core/latest/Maybe

なるほど Maybe.withDefault というものがあるのか。

> Maybe.withDefault
<function> : a -> Maybe a -> a

それを使うと

stringToInt s = Maybe.withDefault 0 <| String.toInt s

case を書くことなく記述できる。

リストの先頭を取得する際の注意

リストから先頭要素をとる時に、空のリストを渡された時は Nothing となる。
つまり List.head は Maybe 型で返却される。

> List.head
<function> : List a -> Maybe a

返り値の型が Maybe である関数を合成したとき

今回やりたいことを実現するには、

  • 文字列リストの先頭を取得する
  • 文字列を数値に変換する

の二つの関数を合成すればよい。
ここで注意したいのは、両方の処理の返り値の型は Maybe である。

その時 Maybe.andThen というものを使うといい感じにかける。

> Maybe.andThen
<function> : (a -> Maybe b) -> Maybe a -> Maybe b

この関数は Maybe 型を返す関数と Maybe 型の値を受け取っていい感じに処理をしてくれる関数である。
今回の場合は String.toInt という Maybe 型を返す関数と、リストの先頭を取得した値 Maybe String を渡す。

Maybe.andThen String.toInt <| List.head strs

という感じで書く。
もし、リストの先頭が取れなかった時 (Nothing) は String.toInt の処理ではそのまま Nothing が返却される。リストの先頭が取得できた時 (Just "hoge") は String.toInt の処理で "hoge" が渡される。

これを使うことによって Maybe 型が返却される関数の合成が非常に楽になる。

それらを組み合わせる

Maybe.withDefault と Maybe.andThen を使って書き直してみる。

getFirstNum : List String -> Int
getFirstNum strs = Maybe.withDefault 0 <| Maybe.andThen String.toInt <| List.head strs

そうすることによって一行で書けるようになった!!

さらにリファクタ

<| を使うよりも |> の方が処理の順番通りに書けるので読みやすくなる。

getFirstNum : List String -> Int
getFirstNum strs = List.head strs |> Maybe.andThen String.toInt |> Maybe.withDefault 0

また、いちいちパスを書くのは面倒なので import して exposing させる。

import Maybe exposing (andThen, withDefault)
import String exposing (toInt)
import List exposing (head)

getFirstNum : List String -> Int
getFirstNum strs = head strs |> andThen toInt |> withDefault 0

これによってだいぶ読みやすくなった。

まとめ

withDefault に相当する関数は絶対あるだろうと思って調べたらあったので、ちゃんと調べることは大切だなと感じた(小並感)。

13
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?