Option型

プログラミング言語と型理論において、Option型（英語: Option type）またはMaybe型（英語: Maybe type）は存在しない可能性のある値をカプセル化して表す多相型（英語版）である。例えば、関数の戻り値が存在する場合と存在しない場合を表すためにこの型は使用される。この型は空またはオリジナルのデータ型Aをカプセルしたコンストラクタから構成されている。 関数型プログラミング以外において、全く異なるが関連する概念としてNullable型がオブジェクト指向プログラミングで一般的である。Option型とNullable型の主な違いは、Option型はネストすることができるのに対して、Nullable型はこれに対応していないことである。 型理論において、Option型は A ? = A + 1 {\displaystyle A^{?}=A+1} のように記述することができる。これは与えられた値の組 A {\displaystyle A} に対して、Option型は A {\displaystyle A} の有効な値の組に正確に1つの追加の値（空の値）を追加するという事実を表している。これはタグ付き共用体（英語版）を持つ言語において、Option型がカプセル化型とUnit型（英語版）のタグ付き共用体として表現できるという事実によってプログラミングに反映されている。 カリー＝ハワード同型対応において、Option型は∨: x∨1=1の消滅法則に関連している[どうやって?]。 Option型は1個または0個の要素を含むコレクション（英語版）と見なすこともできる[独自研究?]。 Option型もモナドであり、次のようになる: return = Just -- Wraps the value into a maybe Nothing >>= f = Nothing -- Fails if the previous monad fails (Just x) >>= f = f x -- Succeeds when both monads succeed Option型のモナディックな性質は、失敗とエラーを効率的に追跡するのに役立つ。 それぞれのプログラミング言語において、Option型は様々な名前と定義がある。 Agdaでは、nothingとjust aという要素を持ち、Maybeという名前で定義されている。 Coqでは、Inductive option (A:Type) : Type := | Some : A -> option A | None : option A.として定義されている。 Elmでは、Maybeという名前でtype Maybe a = Just a | Nothingとして定義されている。 Haskellでは、Maybeという名前でdata Maybe a = Nothing | Just aとして定義されている。 Idris（英語版）では、data Maybe a = Nothing | Just aとして定義されている。 OCamlでは、type 'a option = None | Some of 'aとして定義されている。 Pythonでは、3.10以降でtyping.Optional[T]またはT | Noneとして示される。 Rustでは、enum Option<T> { None, Some(T) }として定義されている。 Scalaでは、final case class Some[+A](value: A)とcase object Noneの型拡張によって、sealed abstract class Option[+A]として定義されている。 Standard MLでは、datatype 'a option = NONE | SOME of 'aとして定義されている。 Swiftでは、enum Optional<T> { case none, some(T) }として定義されているが、通常はT?として記述される。 コード例 let compute = Option.fold (fun _ x -> sprintf "The value is: %d" x) "No value" let full = Some 42 let empty = None compute full |> printfn "compute full -> %s" compute empty |> printfn "compute empty -> %s" 実行結果 compute full -> The value is: 42 compute empty -> No value コード例 compute :: Maybe Int -> String compute = foldl (\_ x -> "The value is: " ++ show x) "No value" main :: IO () main = do let full = Just 42 let empty = Nothing putStrLn $ "compute full -> " ++ compute full putStrLn $ "compute empty -> " ++ compute empty 実行結果 compute full -> The value is: 42 compute empty -> No value コード例 import std/options proc compute(opt: Option[int]): string = opt.map(proc (x: int): string = "The value is: " & $x).get("No value") let full = some(42) empty = none(int) echo "compute(full) -> ", compute(full) echo "compute(empty) -> ", compute(empty) 実行結果 compute(full) -> The Value is: 42 compute(empty) -> No value OCamlはOptionをパラメータ化された要素型として実装している。Optionは次のように構築及び分解される: コード例 let compute = Option.fold ~none:"No value" ~some:(fun x -> "The value is: " ^ string_of_int x) let () = let full = Some 42 in let empty = None in print_endline ("compute full -> " ^ compute full); print_endline ("compute empty -> " ^ compute empty) 実行結果 compute full -> The value is: 42 compute empty -> No value コード例 fn compute(opt: Option<i32>) -> String { opt.map_or("No value".to_owned(), |x| format!("The value is: {}", x)) } fn main() { let full = Some(42); let empty = None; println!("compute(full) -> {}", compute(full)); println!("compute(empty) -> {}", compute(empty)); } 実行結果 compute(full) -> The value is: 42 compute(empty) -> No value ScalaはOptionをパラメータ化された型として実装しているので、変数はOptionになることができ、次のようにアクセスできる: コード例 object Main { def compute(opt: Option[Int]): String = opt.fold("No value")(x => s"The value is: $x") def main(args: Array[String]): Unit = { val full = Some(42) val empty = None println(s"compute(full) -> ${compute(full)}") println(s"compute(empty) -> ${compute(empty)}") } } 実行結果 compute(full) -> The value is: 42 compute(empty) -> No value Optionの値を使用する方法は2つある。1つは、最良ではないが最初の例のようにパターンマッチングによる方法である。もう1つは、最良の方法である2番目の例のようなモナディックアプローチである。このように、プログラムは例外またはエラーを生成することができないので安全である。従って、これは基本的にnull値の型安全な代替手段として機能する。 コード例 func compute(_ opt: Int?) -> String { return opt.map { "The value is: \($0)" } ?? "No value" } let full = 42 let empty: Int? = nil print("compute(full) -> \(compute(full))") print("compute(empty) -> \(compute(empty))") 実行結果 compute(full) -> The value is: 42 compute(empty) -> No value コード例 const std = @import("std"); const print = std.io.getStdOut().writer().print; const Compute = struct { value: ?i32, pub fn init(value: ?i32) Compute { return Compute{ .value = value }; } pub fn format( self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: anytype, ) !void { _ = fmt; _ = options; if (self.value) |n| { return out_stream.print("The value is: {}", .{n}); } else { return out_stream.print("No value", .{}); } } }; pub fn main() !void { const full = Compute.init(42); const empty = Compute.init(null); try print("full -> {}\n", .{full}); try print("empty -> {}\n", .{empty}); } 実行結果 full -> The value is: 42 empty -> No value Zigでは、?i32 の様に型名の前に ? を追加するとOptional型となる。 if (opt) |n| { の様に if 文、あるいは while文でペイロード n をキャプチャーすることができ、null の場合 else 節が評価される。 ^ 特に関数型プログラミング言語において。 ^ 多くの場合、NoneまたはNothingという名前。 ^ 多くの場合、Just AまたはSome Aと書かれる。 ^ 多くの場合、A?として表される。 ^ 例えば、Maybe (Maybe String) ≠ Maybe String。 ^ 例えば、String?? = String?。 ^ 型ヒントを介して。 ^ 例えばNoneと等しいOption変数の値を取得しようとすることによって。 ^ Milewski, Bartosz (2015年1月13日). “Simple Algebraic Data Types” (英語). Bartosz Milewski's Programming Cafe. 2019年8月18日時点のオリジナルよりアーカイブ。2019年8月18日閲覧。 ^ “A Fistful of Monads - Learn You a Haskell for Great Good!”. www.learnyouahaskell.com. 2019年8月18日閲覧。 ^ Hutton, Graham (Nov 25, 2017). “What is a Monad?”. Computerphile Youtube. 2021年12月20日時点のオリジナルよりアーカイブ。Aug 18, 2019閲覧。 ^ “Maybe · An Introduction to Elm”. guide.elm-lang.org. 2022年6月11日閲覧。 ^ “Apple Developer Documentation”. developer.apple.com. 2020年9月6日閲覧。 ^ Martin Odersky; Lex Spoon; Bill Venners (2008). Programming in Scala. Artima Inc. pp. 282–284. ISBN 978-0-9815316-0-1. https://books.google.com/books?id=MFjNhTjeQKkC&pg=PA283 6 September 2011閲覧。  Result型 タグ付き共用体（英語版） Nullable型 Nullオブジェクトパターン（英語版） 例外処理 パターンマッチング