Skip to content
Open
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
44 changes: 44 additions & 0 deletions src/curry_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
class MyError(Exception):
pass


def curry(func, arity):
# для ф inner этот список будет глобальным
if arity <= 0:
raise MyError("Арность не может быть меньше или равна 0.")
Comment on lines +7 to +8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А чем вам не угодила нулевая арность?

if arity > func.__code__.co_argcount:
raise MyError("Переданная арность больше действительной.")
if not isinstance(arity, int):
raise MyError("Переданная арность функции обязана быть целым числом.")
lst = []

def inner(arg):
nonlocal lst
lst.append(arg)
if len(lst) == arity:
tmp = func(*lst)
# освобождаем список, чтобы функцию можно было использовать повторно
lst = []
return tmp
return inner

return inner


def uncurry(curried_func, arity):
"""
Этой функции передается внутренняя функция inner функции curry, принимающая один аргумент.
Сначала возвращается функция, способная принимать любое кол-во аргументов.
Все последующее обращение будет к внутренней функции.
"""

def uncarried_func(*args):
tmp_func = curried_func
if len(args) != arity:
raise MyError("Передано неверное кол-во аргументов.")
if len(args) == arity:
for el in args:
tmp_func = tmp_func(el)
return tmp_func

return uncarried_func
84 changes: 84 additions & 0 deletions tests/test_for_curry_task.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я не до конца уловил вашу идею про универсальный тест. Вы могли бы сделать функцию, которая на случайных входах проверяет, что каррированная функция отрабатывает так же, как и изначальная. Проблема тут в типах, потому что генерировать случайные числа просто, а вот что-то более сложное -- надо постараться

import random

def fully_apply(f, args):
    res = f
    for arg in args:
        res = res(arg)
    return res

def generate_int_input(func):
    [random.randint(1, 10**6) for _ in range(func.__code__.co_argcount)]

def curried_equiv(func):
    func_c = curry(func, func.__code__.co_argcount)
    input = generate_int_input(func)
    assert fully_apply(func_c, input) == func(*input)

def test_summ():
    def summ(a, b, c):
        return a + b + c

    curried_equiv(summ)

Но функции должны работать только с int-ми (возвращать могут, впрочем, любой тип, главное, чтобы можно было два элемента сравнивать), и придумывать их вы должны тоже сами

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import hypothesis.strategies as st
from src.curry_task import curry, uncurry, MyError
from hypothesis import given


@given(a=st.integers(), b=st.integers(), c=st.integers())
def test_sum_three_elements_check(a, b, c):
def summ(a, b, c):
return a + b + c

func = curry(summ, 3)
uncarried_func = uncurry(func, 3)
for el in (a, b, c):
func = func(el)
assert func == a + b + c
Comment on lines +13 to +15
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему не просто func(a)(b)(c)?

assert uncarried_func(a, b, c) == a + b + c


@given(a=st.integers(), b=st.integers(), c=st.integers())
def test_mul_three_elements_check(a, b, c):
def mul(a, b, c):
return a * b * c

func = curry(mul, 3)
uncarried_func = uncurry(func, 3)
for el in (a, b, c):
func = func(el)
assert func == a * b * c
assert uncarried_func(a, b, c) == a * b * c


def test_wrong_arity_errors1():
try:

def summ(a, b, c):
return a + b + c

curry(summ, -1)
assert False
except MyError as e:
assert isinstance(e, MyError)
assert str(e) == "Арность не может быть меньше или равна 0."
Comment on lines +33 to +42
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Для таких вещей есть pytest.raises: https://docs.pytest.org/en/7.1.x/how-to/assert.html#assertraises



def test_wrong_arity_errors2():
try:

def summ(a, b, c):
return a + b + c

curry(summ, 5)
assert False
except MyError as e:
assert isinstance(e, MyError)
assert str(e) == "Переданная арность больше действительной."


def test_wrong_arity_errors3():
try:

def mul(a, b, c):
return a * b * c

curry(mul, 1.0)
assert False
except MyError as e:
assert isinstance(e, MyError)
assert str(e) == "Переданная арность функции обязана быть целым числом."


@given(args=st.lists(st.integers(), min_size=4))
def test_wrong_quantity_of_arguments(args):
try:

def summ(a, b, c):
return a + b + c

func = curry(summ, 3)
uncarried_func = uncurry(func, 3)
uncarried_func(args)
assert False
except MyError as e:
assert isinstance(e, MyError)
assert str(e) == "Передано неверное кол-во аргументов."