dbrattli / Expression

Functional programming for Python
https://expression.readthedocs.io
MIT License
471 stars 31 forks source link

extra feature: apply (issue #116) #149

Closed phi-friday closed 11 months ago

phi-friday commented 1 year ago

how to use

from expression import Ok
from expression.extra.result.apply import call, func, of_iterable, of_obj

### seq
values = (1, "q", b"w")
seq_0 = of_iterable(*values)
seq_1 = of_obj(values[0]) * of_obj(values[1]) * of_obj(values[2])
seq_2 = of_iterable(values[0]) * of_iterable(values[1]) * of_iterable(values[2])
seq_3 = of_obj(Ok(values[0])) * of_obj(Ok(values[1])) * of_obj(Ok(values[2]))
assert seq_0 == seq_1 == seq_2 == seq_3
assert seq_0 * of_obj(1) != of_obj(1) * seq_0
assert seq_0 * of_iterable(1, 2) != of_iterable(1, 2) * seq_0

### function
def test_func_0(a: int, b: str, c: bytes) -> tuple[int, str, bytes]:
    return (a, b, c)

@func
def test_func_1(a: int, b: str, c: bytes) -> tuple[int, str, bytes]:
    return (a, b, c)

test_func_2 = func(test_func_0)

left, right = of_obj(values[0]), of_iterable(*values[1:])
lr_seq = left * right
res_0 = test_func_1 * left * right * call
res_1 = left * test_func_1 * right * call
res_2 = left * right * test_func_1 * call
res_3 = lr_seq * test_func_1 * call
res_4 = test_func_1 * lr_seq * call
res_5 = test_func_1 % lr_seq
res_6 = lr_seq % test_func_1
res_7 = lr_seq % test_func_2
assert res_0 == res_1 == res_2 == res_3 == res_4 == res_5 == res_6

### only __mod__
assert test_func_0 % lr_seq == test_func_1 % lr_seq

### __call__
values = (1, "q", b"w")
seq = of_iterable(*values)
assert (
    Ok(test_func_0(*values))
    == test_func_1(*values)
    == test_func_2(*values)
    == test_func_1 * seq * call
    == seq * test_func_1 * call
    == test_func_1 % seq
    == seq % test_func_1
    == test_func_2 * seq * call
    == seq * test_func_2 * call
    == test_func_2 % seq
    == seq % test_func_2
)

TODO

phi-friday commented 1 year ago

As you can see in pep-646, It is not possible to use type hints in a form such as tuple[Unpack[ArgsT], Unpack[OtherArgsT]].

But anyway, in pyright, the type inference works fine (although it causes errors when define)

I think there's a better way, but I couldn't think of it right away, so I used Unpack twice. I wish there was another way.

phi-friday commented 1 year ago

As you can see in pep-646, It is not possible to use type hints in a form such as tuple[Unpack[ArgsT], Unpack[OtherArgsT]].

But anyway, in pyright, the type inference works fine (although it causes errors when define)

I think there's a better way, but I couldn't think of it right away, so I used Unpack twice. I wish there was another way.

I fixed this problem, but when inferring the type of a particular function, it rely entirely on pyright. ex:

def _iter_unpack_tuples_1(  # noqa: ANN202
    value: tuple[Unpack[ArgsT]],  # type: ignore[reportInvalidTypeVarUse]
    other: tuple[Unpack[OtherArgsT]],  # type: ignore[reportInvalidTypeVarUse]
):
    return (*other, *value)
""" in pyright,
(function) def _iter_unpack_tuples_1(
    value: tuple[*ArgsT@_iter_unpack_tuples_1],
    other: tuple[*OtherArgsT@_iter_unpack_tuples_1]
) -> tuple[*OtherArgsT@_iter_unpack_tuples_1, *ArgsT@_iter_unpack_tuples_1]
"""
dbrattli commented 1 year ago

This looks really interesting 👏 Please give me some time to review since my bandwidth is currently a bit limited

phi-friday commented 1 year ago

As you can see in pep-646, It is not possible to use type hints in a form such as tuple[Unpack[ArgsT], Unpack[OtherArgsT]]. But anyway, in pyright, the type inference works fine (although it causes errors when define) I think there's a better way, but I couldn't think of it right away, so I used Unpack twice. I wish there was another way.

I fixed this problem, but when inferring the type of a particular function, it rely entirely on pyright. ex:

def _iter_unpack_tuples_1(  # noqa: ANN202
    value: tuple[Unpack[ArgsT]],  # type: ignore[reportInvalidTypeVarUse]
    other: tuple[Unpack[OtherArgsT]],  # type: ignore[reportInvalidTypeVarUse]
):
    return (*other, *value)
""" in pyright,
(function) def _iter_unpack_tuples_1(
    value: tuple[*ArgsT@_iter_unpack_tuples_1],
    other: tuple[*OtherArgsT@_iter_unpack_tuples_1]
) -> tuple[*OtherArgsT@_iter_unpack_tuples_1, *ArgsT@_iter_unpack_tuples_1]
"""

I thought it would be better to use lambda, so I changed it to lambda.

phi-friday commented 1 year ago

This looks really interesting 👏 Please give me some time to review since my bandwidth is currently a bit limited

@dbrattli Of course. Thank you for your interest.

phi-friday commented 11 months ago

I tried it, and it wasn't as useful or robust as I thought it would be.