Recursion over a Swift Sliceable

前端 未结 3 1020
南旧
南旧 2021-01-12 06:38

I feel that I must be missing something obvious. Decomposing a list into the head and tail and then recursing over the tail is a standard functional programming technique, y

3条回答
  •  我在风中等你
    2021-01-12 06:52

    Actually ArraySlice is Sliceable, so you can recurse on ArraySlice:

    func recurseArray(arr: ArraySlice) -> [Int] {
    
        guard let first = arr.first else {
            return []
        }
    
        let rest = recurseArray(dropFirst(arr))
        let next = rest.first ?? 0
    
        return [first + next] + rest
    }
    

    with a wrapper function which is called only once at the top level:

    func recurseArray(arr: [Int]) -> [Int] {
        return recurseArray(arr[arr.startIndex ..< arr.endIndex])
    }
    

    I don't have a solution for your second more general problem. The API docs for Sliceable state that SubSlice should be Sliceable itself (which is the case for all known Sliceable types).

    I have therefore the feeling that it should be possible by requesting that T.SubSlice is itself sliceable with the identical SubSlice type, however this does not compile:

    func recurseSeq(list: T.SubSlice) -> [Int] {
    
            guard let first = list.first else {
                return []
            }
            let rest = recurseSeq(dropFirst(list) as T.SubSlice)
            // error: cannot invoke 'recurseSeq' with an argument list of type '(T.SubSlice)'
    
            let next = rest.first ?? 0
    
            return [first + next] + rest
    }
    

    The compiler accepts that dropFirst(list) can be cast to T.SubSlice, but refuses to call recurseSeq() on that value, which I do not understand.


    Alternatively, you can recurse on a GeneratorType:

    func recurseGen(inout gen: G) -> [Int] {
    
        guard let first = gen.next() else {
            return []
        }
        let rest = recurseGen(&gen)
        let next = rest.first ?? 0
        return [first + next] + rest
    }
    

    with a wrapper that takes a SequenceType:

    func recurseSeq(list: T) -> [Int] {
        var gen = list.generate()
        return recurseGen(&gen)
    }
    

    Arrays and array slices all conform to SequenceType, so that should work in all your cases.

提交回复
热议问题