编写返回自身的Swift函数

时间:2019-02-01 12:38:26

标签: swift recursion

我在Python中有这段代码:

def f(x, y):
    # do something...
    return f

我正在尝试用Swift编写此代码,但无法弄清楚是否可行。返回类型将无限长。

这是我试图用Python编写的游戏的一部分。这是一个骰子游戏,具有多个注释功能,每一轮都会被调用。每轮结束后,注释函数可能会返回自身,但也会进行一些更改(例如更改封闭范围中的变量)。

def say_scores(score0, score1):
    """A commentary function that announces the score for each player."""
    print("Player 0 now has", score0, "and Player 1 now has", score1)
    return say_scores

def announce_lead_changes(previous_leader=None):
    """Return a commentary function that announces lead changes."""

    def say(score0, score1):
        if score0 > score1:
            leader = 0
        elif score1 > score0:
            leader = 1
        else:
            leader = None
        if leader != None and leader != previous_leader:
            print('Player', leader, 'takes the lead by', abs(score0 - score1))
        return announce_lead_changes(leader)
    return say

def both(f, g):
    """Return a commentary function that says what f says, then what g says."""
    def say(score0, score1):
        return both(f(score0, score1), g(score0, score1))
    return say


def announce_highest(who, previous_high=0, previous_score=0):
    """Return a commentary function that announces when WHO's score
    increases by more than ever before in the game.
    assert who == 0 or who == 1, 'The who argument should indicate a player.'"""
    # BEGIN PROBLEM 7
    "*** YOUR CODE HERE ***"
    def say(score0,score1):
        scores = [score0,score1]
        score_diff = scores[who]-previous_score
        if score_diff > previous_high:
            print(score_diff,"point(s)! That's the biggest gain yet for Player",who)
            return announce_highest(who,score_diff,scores[who])
        return announce_highest(who,previous_high,scores[who])
    return say
    # END PROBLEM 7

重复播放功能,直到某个玩家达到分数为止

def play(strategy0, strategy1, score0=0, score1=0, dice=six_sided,
         goal=GOAL_SCORE, say=silence):
    """Simulate a game and return the final scores of both players, with Player
    0's score first, and Player 1's score second.

    A strategy is a function that takes two total scores as arguments (the
    current player's score, and the opponent's score), and returns a number of
    dice that the current player will roll this turn.

    strategy0:  The strategy function for Player 0, who plays first.
    strategy1:  The strategy function for Player 1, who plays second.
    score0:     Starting score for Player 0
    score1:     Starting score for Player 1
    dice:       A function of zero arguments that simulates a dice roll.
    goal:       The game ends and someone wins when this score is reached.
    say:        The commentary function to call at the end of the first turn.
    """
    player = 0  # Which player is about to take a turn, 0 (first) or 1 (second)
    # BEGIN PROBLEM 5
    "*** YOUR CODE HERE ***"
    scores = [score0,score1]
    strategies = [strategy0,strategy1]
    while score0 < goal and score1 < goal:
        scores[player] += take_turn(strategies[player](scores[player], scores[other(player)]),
        scores[other(player)], dice)

        swap = is_swap(scores[player], scores[other(player)])
        player = other(player)
        if swap:
            scores[0],scores[1] = scores[1], scores[0]
        score0,score1 = scores[0],scores[1]
    # END PROBLEM 5
    # BEGIN PROBLEM 6
        "*** YOUR CODE HERE ***"
        say = say(score0,score1)
    # END PROBLEM 6
    return score0, score1

3 个答案:

答案 0 :(得分:8)

让我们尝试写这样的东西。

CREATE PROCEDURE GetMatches(@input varchar (100))
AS
BEGIN

    WITH CTE AS
    (
        SELECT value AS number
        FROM STRING_SPLIT(@input, ',') 
    )
    SELECT CTE.number, A.ColumnName
    FROM A
    INNER JOIN CTE
    ON ',' + A.ColumnName + ',' LIKE '%,' + CTE.number + ',%';

END

现在,编译器会抱怨,因为EXEC dbo.GetMatches @input = '101,104'; 在声明返回内容时未声明返回任何内容。

好吧,让我们尝试添加一个返回值类型,即不接受任何参数且不返回任何内容的闭包。

func f() {
    return f
}

现在,编译器抱怨ffunc f() -> (() -> ()) { return f } ,因此无法转换为f

我们应该编辑声明以返回() -> (() -> ()),对吧?

() -> ()

现在() -> (() -> ())成为func f() -> (() -> (() -> ())) { return f } ,无法转换为f

现在看到图案了吗?这将永远持续下去。

因此,您只能以类型不安全的方式执行此操作,并返回() -> (() -> (() -> ()))

() -> (() -> ())

用法:

Any

之所以可以在python中实现,恰恰是因为Python的类型很弱,您无需指定返回类型。

请注意,我不鼓励您使用Swift编写此类代码。在Swift中进行编码时,请尝试以Swift的心态解决问题。换句话说,您应该考虑另一种解决问题的方法,该方法不涉及此类功能。

答案 1 :(得分:2)

也许不是您想要的,但是您可以对闭包进行类似的操作

typealias Closure = (Int) -> Int

func doStuff(action: @escaping Closure, value: Int) -> Closure {
    let x = action(value)
    //do something
    return action
}

答案 2 :(得分:2)

好吧,实际上您可以在Swift中执行类似的操作,只需要将代码的线性部分与递归分开,并将递归代码包装在struct中即可:

// Recursive code goes here:
struct Rec<T> {
    let call: (T) -> Rec<T> // when code `from outside` calls it, it will execute linear part and return recursive
    init(closure: @escaping (T) -> Void) { // create new loop with linear `closure`
        self.call = {
            closure($0) // execute linear code
            return Rec(closure: closure) // return recursive wrapper
        }
    }

    subscript(input: T) -> Rec<T> { // this exist just to simulate `f(x)` calls, using square brackets notation 
        return self.call(input)
    }
}

// Linear code goes here
let sayScores = Rec { (score0: Int, score1: Int) in
    print("Player 0 now has", score0, "and Player 1 now has", score1)
}

用法:

let temp = sayScores.call((1, 2)) // will print: Player 0 now has 1 and Player 1 now has 2

temp[(0, 0)][(10, 42)] // temp is `Rec<(Int, Int)>`
// will print:
// Player 0 now has 0 and Player 1 now has 0
// Player 0 now has 10 and Player 1 now has 42

因此您可以使它工作,但是我不知道您是否应该在Swift中使用它。