Monadic For-Yield
💡 お知らせ: このドキュメントはAIによって翻訳されています。表現に違和感がある場合は、原文(英語)を参照するか、翻訳にご協力ください。
Flix は、Scala の for 内包表記や Haskell の do 記法に似た、モナドの forM-yield 構文をサポートしています。forM 構文は、point と flatMap(これらは Monad トレイトによって提供されます)を使用するための糖衣構文です。forM 構文は、empty(これは MonadZero トレイトによって提供されます)を使用する guard 式もサポートしています。
たとえば、次のモナドの forM 式:
let l1 = 1 :: 2 :: Nil;
let l2 = 1 :: 2 :: Nil;
forM (x <- l1; y <- l2)
yield (x, y)
は、次のリストに評価されます:
(1, 1) :: (1, 2) :: (2, 1) :: (2, 2) :: Nil
ガード式を使用する
forM 式の中で ガード式 を使用することができます。たとえば、次のプログラム:
let l1 = 1 :: 2 :: Nil;
let l2 = 1 :: 2 :: Nil;
forM (x <- l1; y <- l2; if x < y)
yield (x, y)
は、次のリストに評価されます:
(1, 2) :: Nil
Option と Result を扱う
forM を使って Option データ型を扱うこともできます。たとえば:
def divide(x: Int32, y: Int32): Option[Int32] =
if (y == 0) None else Some(x / y)
def f(): Option[Int32] =
forM (
x <- divide(5, 2);
y <- divide(x, 8);
z <- divide(9, y)
) yield x + y + z
ここで、関数 f は None を返します。なぜなら x = 5 / 2 = 2 であり、2 / 8 = 0 となるため、最後の除算が失敗するからです。
同様に、forM を使って Result[e, t] データ型を扱うことができます。たとえば:
use Sys.Console
def main(): Result[String, Unit] \ IO =
println("Please enter your first name, last name, and age:");
forM (
fstName <- Console.readln();
lstName <- Console.readln();
ageLine <- Console.readln();
ageNum <- Int32.parse(10, ageLine)
) yield {
println("Hello ${lstName}, ${fstName}.");
println("You are ${ageNum} years old!")
}
ここで main は、ユーザーに名(first name)、姓(last name)、年齢の入力を促します。Console.readln の各呼び出しは、エラーまたは入力文字列のいずれかである Result[String, String] 値を返します。したがって、ローカル変数 fstName、lstName、ageLine は String です。Int32.parse を使用して ageLine を Int32 にパースします。これは Result[String, Int32] 値を返します。すべての操作が成功した場合、あいさつを表示して Ok(())(すなわち Unit の Ok)を返します。そうでなければ、Err(msg) 値を返します。
その他の Monad を扱う
forM は、Chain や Nel(空でないリスト)を含む、他の種類の Monad でも使用できます。たとえば、次のように書くことができます:
let l1 = Nel(1, 2 :: Nil);
let l2 = Nel(1, 2 :: Nil);
forM (x <- l1; y <- l2)
yield (x, y)
これは、次の空でないリストに評価されます:
Nel((1, 1), (1, 2) :: (2, 1) :: (2, 2) :: Nil)
注意: 空でないリストでは
if-ガードを使用することができません。なぜなら、そのようなif-ガードはMonadZeroトレイトのインスタンスを必要としますが、空でないリストはこれを実装していないからです(そのようなリストは空になることができないため)。
脱糖
forM 式は、Monad.flatMap、Applicative.point、MonadZero.empty を使用するための糖衣構文です。
たとえば、次の式:
let l1 = 1 :: 2 :: Nil;
let l2 = 1 :: 2 :: Nil;
forM (x <- l1; y <- l2; if x < y)
yield (x, y)
は、次のように脱糖されます:
Monad.flatMap(x ->
Monad.flatMap(y ->
if (x < y)
Applicative.point((x, y))
else
MonadZero.empty(),
l2),
l1);