Skip to content

Commit

Permalink
Improve options type declarations and add andThen method (#398)
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee authored Jan 24, 2023
1 parent ebe7297 commit 33496f6
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 4 deletions.
31 changes: 27 additions & 4 deletions src/Psl/Option/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,11 @@ public function unwrap(): mixed
* @note: Arguments passed to `Option::unwrapOr()` are eagerly evaluated;
* if you are passing the result of a function call, it is recommended to use `Option::unwrapOrElse()`, which is lazily evaluated.
*
* @param T $default
* @template O
*
* @return T
* @param O $default
*
* @return T|O
*/
public function unwrapOr(mixed $default): mixed
{
Expand All @@ -114,9 +116,11 @@ public function unwrapOr(mixed $default): mixed
/**
* Returns the contained some value or computes it from a closure.
*
* @param (Closure(): T) $default
* @template O
*
* @return T
* @param (Closure(): O) $default
*
* @return T|O
*/
public function unwrapOrElse(Closure $default): mixed
{
Expand Down Expand Up @@ -215,6 +219,25 @@ public function map(Closure $closure): Option
return $this;
}

/**
* Maps an `Option<T>` to `Option<Tu>` by applying a function to a contained value that returns an Option<Tu>.
*
* @template Tu
*
* @param (Closure(T): Option<Tu>) $closure
*
* @return Option<Tu>
*/
public function andThen(Closure $closure): Option
{
if ($this->option !== null) {
return $closure($this->option[0]);
}

/** @var Option<Tu> */
return $this;
}

/**
* Applies a function to the contained value (if some),
* or returns `Option<Tu>::some()` with the provided `$default` value (if none).
Expand Down
25 changes: 25 additions & 0 deletions tests/static-analysis/Option/unwrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

use Psl\Option;

function test_some_unwrap_or(): ?string
{
return Option\some('string')->unwrapOr(null);
}

function test_none_unwrap_or(): ?string
{
return Option\none()->unwrapOr(null);
}

function test_some_unwrap_or_else(): ?string
{
return Option\some('string')->unwrapOrElse(static fn () => null);
}

function test_none_unwrap_or_else(): ?string
{
return Option\none()->unwrapOrElse(static fn() => null);
}
7 changes: 7 additions & 0 deletions tests/unit/Option/NoneTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,11 @@ public function testMapOrElse(): void

static::assertSame(4, $option->mapOrElse(static fn($i) => $i + 1, static fn() => 4)->unwrap());
}

public function testAndThen(): void
{
$option = Option\none();

static::assertNull($option->andThen(static fn($i) => Option\some($i + 1))->unwrapOr(null));
}
}
7 changes: 7 additions & 0 deletions tests/unit/Option/SomeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,11 @@ public function testMapOrElse(): void

static::assertSame(3, $option->mapOrElse(static fn($i) => $i + 1, static fn() => 4)->unwrap());
}

public function testAndThen(): void
{
$option = Option\some(2);

static::assertSame(3, $option->andThen(static fn($i) => Option\some($i + 1))->unwrapOr(null));
}
}

0 comments on commit 33496f6

Please sign in to comment.