【问题标题】:What makes function composition so powerful?是什么让函数组合如此强大?
【发布时间】:2021-05-07 17:21:00
【问题描述】:

我读过关于函数式编程的文章,它的核心概念似乎是大量使用不可变数据结构,这反过来又导致了纯函数。这些纯函数应该很容易组合,如下例所示:

def add(x, y):
    return 3 + 3

def minus1(z):
    return z - 1

print(minus1(add(3,3)))

我明白,我可以通过这种方法组合函数并构建新函数。在下面的例子中,我编写了两个不纯函数:

def add_list_last(arr):
    arr.append(1)
    return arr

def insert_entry_at_start(arr):
    arr.insert(0,1)
    return arr

print(add_list_last(insert_entry_at_start([1,2,3])))

为什么我不能像第二个例子那样编写不纯函数,为什么它如此强大?第二个例子的缺点是什么,为什么数组的突变会阻止可组合性?

【问题讨论】:

  • 由于列表在 python 中是可变的,因此您将更改原始数组。假设您有一个名为 original 的数组,并且您运行 modified = add_list_last(insert_entry_at_start(original)) 您会期望原始数组和修改后的数组不同,但它们是完全相同的数组(不是副本,而是实际上相同的数组)
  • 只要函数是纯函数,您可以使用许多巧妙的技巧。但是,如果它们不纯,那么当f(x) 不再是每次都相同的操作时,这会极大地限制您。最简单的例子是 memoization - 如果 f 不再是 memoizable,那么你就失去了一个基本上免费的代码优化路径。
  • @VLAZ memoizable 是什么意思?
  • memoization 是一种缓存方式。您实际上构建了一个输入到输出到函数的映射。因此,如果您调用f(1) 并获得"a",则在将1 传递给它时,您不需要再次重新评估f,您只需从缓存映射中获取它。但是,如果f(1) 可以产生"a""b",那么您就无法记住该函数——相同的输入不一定会产生相同的输出。

标签: python python-3.x functional-programming


【解决方案1】:
T = TypeVar('T')

def split(v: T) -> Tuple[T, T]:
    return v, v

def apply_to_first(f: Callable[[T], T], *xs: T) -> Sequence[T]:
    return (f(xs[0]), *xs[1:])

apply_to_first(insert_entry_at_start, *split([1, 2]))

你会在这里期待这个结果:

([1, 2, 1], [1, 2])

但实际上你得到:

([1, 2, 1], [1, 2, 1])

因为insert_entry_at_start 不纯。

【讨论】:

  • 所以纯函数的组合是如此强大,因为你可以从纯函数中组合出新的纯函数,对吗?
  • 是的……!?换句话说,如果你的函数式程序中的任何函数是不纯的并且有副作用,那么你就很难推断你的程序会如何表现。
【解决方案2】:

这是一个简化的例子:

def prepend_impure(lst, element):
    lst.insert(0, element)
    return lst

def prepend_pure(lst, element):
    cpy = lst[:]
    cpy.insert(0, element)
    return cpy

def combine(list1, list2):
    return [i + j for i, j in zip(list1, list2)]

list1 = [2, 3, 4]
list2 = [2, 3, 4]

print(combine(prepend_impure(list1, 1), prepend_impure(list1, 1)))
print(combine(prepend_pure(list2, 1), prepend_pure(list2, 1)))

输出:

[2, 2, 4, 6, 8]
[2, 4, 6, 8]

prepend 函数在给定list 的开头插入一个元素并返回list

combine 函数将 2 个列表加在一起。

就个人而言,我希望代码既能返回lists 的[1, 2, 3, 4],又能将两者相加。

不纯的版本不仅没有达到预期效果。在大型代码库中,试图注意函数可以改变或修改对象的所有方式会产生大量的认知超载。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    相关资源
    最近更新 更多