这是什么功能性编程范式。

huangapple go评论58阅读模式
英文:

What functional paradigm is this

问题

I can provide the translated code and questions without additional content:

代码部分:
我正在编写一些Python代码,我一再实现了一个我在许多语言中都实现过的模式。我一直在思考这是否是一种函数式范式,并且是否可以在不使用for循环的情况下实现这个功能,但我没有看到它。 Map接受一个系列并返回一个新系列。 Reduce接受一个系列并将其减少为单个结果。这都不是那种情况。

下面的这个函数的想法是重复地对单个字符串应用转换。在这种情况下:

  1. 替换所有uuid
  2. 然后替换5到9位数字之间的所有数字组
  3. 还会有更多的转换
def to_template(message):
    mappers = [
        ('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', '{.uuid}'),
        (' [0-9]{5,9}.', ' {.request_id}.')
    ]
    result = message
    for pattern, replacement in mappers:
        result = re.sub(pattern, replacement, result)

    return result

问题:

  1. 这是否可以以函数式方式实现?
  2. 是否已知有用于此的函数式范式?
英文:

I am writing some python code and I am implementing a pattern that I have done repeatedly and in numerous languages. I keep thinking this is some sort of functional paradigm, and that this can be implemented functionally (without use of a for loop), but I am not seeing it. Map takes a series and returns a new series. Reduce takes a series and reduces it to a single result. This is neither of those.

The idea of this function below is to repeatedly apply a transformation to a single string. In this case:

  1. Replace all uuids
  2. then replace all number groups between 5-9 digits
  3. There will be more transforms
def to_template(message):
    mappers = [
        ('[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', '{.uuid}'),
        (' [0-9]{5,9}.', ' {.request_id}.')
    ]
    result = message
    for pattern, replacement in mappers:
        result = re.sub(pattern, replacement, result)

    return result

The questions:

  1. Can this be implemented functionally?
  2. Is there a known functional paradigm for this?

答案1

得分: 5

In functional programming terms, this is a fold: you are folding (i.e., reducing) a list of replacement operations to a single string, with a string as the starting point.

在函数式编程术语中,这是一个 折叠:你正在将替换操作的列表折叠(即,减少)为一个字符串,以字符串作为起始点。

In Python, you can write this using the reduce function in the functools module.

在Python中,你可以使用functools模块中的reduce函数来编写这个。

reduce repeatedly calls re.sub using an element from mappers for the first arguments and the result of the previous call as the second argument. (The first call uses message as the "zeroth" return value of re.sub.)

reduce重复调用re.sub,使用mappers中的一个元素作为第一个参数,上一次调用的结果作为第二个参数。(第一次调用时,将message用作re.sub的“零值”返回值。)

Recursively, one could implement reduce as

递归地,可以实现reduce如下:

Iteratively, it looks much like your function:

迭代方式看起来很像你的函数:

Theoretically, you could also imagine using function composition to fold a list of functions into a single function that gets applied to your message.

从理论上讲,你还可以想象使用函数组合将函数列表折叠成一个应用于你的消息的单个函数。

英文:

In functional programming terms, this is a fold: you are folding (i.e., reducing) a list of replacement operations to a single string, with a string as the starting point.

In Python, you can write this using the reduce function in the functools module.

from functools import reduce


def to_template(message):
    mappers = [ ... ]
    return reduce(lambda r, p: re.sub(*p, r), mappers, message)

reduce repeatedly calls re.sub using an element from mappers for the first arguments and the result of the previous call as the second argument. (The first call uses message as the "zeroth" return value of re.sub.)


Recursively, one could implement reduce as

def reduce(f, itr, init):
    if not itr:
        return init
    else:
        return reduce(f, itr[1:], f(init, itr[0]))

Iteratively, it looks much like your function:

def reduce(f, itr, init):
    result = init
    for x in itr:
        result = f(result, x)
    return result

Theoretically, you could also imagine using function composition to fold a list of functions into a single function that gets applied to your message.

from functools import reduce, partial


def to_template(message):
    mappers = [
        partial(re.sub, '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', '{.uuid}'),
        partial(re.sub, ' [0-9]{5,9}.', ' {.request_id}.')
    ]

    # Apply f first, so that reduce applies functions
    # in the order they appear in the list.
    def compose(f, g):
        return lambda x: g(f(x))

    def identity(x):
        return x

    f = reduce(compose, mappers, identity)
    return f(message)

However, for a large number of mapping operations, you would probably hit the recursion limit with the nested function calls that reduce and compose would build up.

huangapple
  • 本文由 发表于 2023年6月9日 00:22:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76433917.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定