Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,43 @@ mx = Maybe(4)
print((mf @ mx) | (lambda x: x + 1)) # Just(9)
```

### Pattern Matching

```python
from darkcore.result import Ok, Err
from darkcore.maybe import Maybe
from darkcore.either import Right, Left
from darkcore.writer import Writer

def classify(r):
match r:
case Ok(v) if v > 10:
return ("big", v)
case Ok(v):
return ("ok", v)
case Err(e):
return ("err", e)

def maybe_demo(m):
match m:
case Maybe(value=None):
return "nothing"
case Maybe(value=v):
return v

def either_demo(x):
match x:
case Right(v):
return v
case Left(e):
return e

w = Writer(3, ["a"], empty=list, combine=lambda a, b: a + b)
match w:
case Writer(v, log=ls):
print(v, ls)
```

---

## 📖 Integration Example
Expand Down
8 changes: 8 additions & 0 deletions darkcore/either.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ def __eq__(self, other: object) -> bool:


class Left(Either[A]):
__match_args__ = ("error",)

def __init__(self, value: A) -> None:
self.value = value

@property
def error(self) -> A:
return self.value

@classmethod
def pure(cls, value: A) -> "Either[A]":
# Left.pure は Right に持ち上げるのが通例
Expand All @@ -41,6 +47,8 @@ def __repr__(self) -> str:


class Right(Either[A]):
__match_args__ = ("value",)

def __init__(self, value: A) -> None:
self.value = value

Expand Down
5 changes: 5 additions & 0 deletions darkcore/maybe.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

class Maybe(MonadOpsMixin[A], Generic[A]):
__slots__ = ("_value",)
__match_args__ = ("value",)

def __init__(self, value: Optional[A]) -> None:
self._value = value
Expand Down Expand Up @@ -48,3 +49,7 @@ def __eq__(self, other: object) -> bool:

def __repr__(self) -> str:
return "Nothing" if self._value is None else f"Just({self._value!r})"

@property
def value(self) -> Optional[A]:
return self._value
2 changes: 2 additions & 0 deletions darkcore/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def __eq__(self, other: object) -> bool:
return isinstance(other, Result) and self.__dict__ == other.__dict__

class Ok(Result[A]):
__match_args__ = ("value",)
def __init__(self, value: A) -> None:
self.value = value

Expand All @@ -50,6 +51,7 @@ def __repr__(self) -> str:


class Err(Result[A]):
__match_args__ = ("error",)
def __init__(self, error: str) -> None:
self.error = error

Expand Down
1 change: 1 addition & 0 deletions darkcore/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Writer(MonadOpsMixin[A], Generic[A, W]):
ログ型 ``W`` はモノイドを想定し、デフォルトでは ``list`` を用いる。
``combine`` を差し替えることで他のモノイドにも対応できる。
"""
__match_args__ = ("value", "log")

def __init__(
self,
Expand Down
11 changes: 11 additions & 0 deletions tests/test_match_either.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from darkcore.either import Right, Left

def test_match_either():
def handle(x):
match x:
case Right(v):
return ("right", v)
case Left(e):
return ("left", e)
assert handle(Right(7)) == ("right", 7)
assert handle(Left("e")) == ("left", "e")
14 changes: 14 additions & 0 deletions tests/test_match_maybe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from darkcore.maybe import Maybe

def test_match_maybe_value_none():
def handle(m):
match m:
case Maybe(value=None):
return "nothing"
case Maybe(value=v) if v % 2:
return ("odd", v)
case Maybe(value=v):
return ("even", v)
assert handle(Maybe(None)) == "nothing"
assert handle(Maybe(3)) == ("odd", 3)
assert handle(Maybe(4)) == ("even", 4)
14 changes: 14 additions & 0 deletions tests/test_match_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from darkcore.result import Ok, Err

def test_match_result_ok_err():
def handle(r):
match r:
case Ok(v) if v > 10:
return ("ok-big", v)
case Ok(v):
return ("ok", v)
case Err(e):
return ("err", e)
assert handle(Ok(5)) == ("ok", 5)
assert handle(Ok(42)) == ("ok-big", 42)
assert handle(Err("x")) == ("err", "x")
9 changes: 9 additions & 0 deletions tests/test_match_writer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from darkcore.writer import Writer

def test_match_writer():
w = Writer(3, ["a"], empty=list, combine=lambda a, b: a + b)
match w:
case Writer(v, log=ls):
assert v == 3 and ls == ["a"]
case _:
assert False, "unreachable"