2016-10-13 11 views
1

機能的なスタイルでSwiftを使用するには、headtailのリストをどのように扱うべきですか? ArrayArraySliceが適切です(ArraySliceはサブリストを取得する効率的なメカニズムなので、このように見えます)。 ArrayArraySliceに変換し、.first!.dropFirst()headtailの同等物として使用する正しいメカニズムはありますか?スウィフトでファースト/ヘッドとレスト/テールの使い方は?

番号のリストを追加する例として:

func add(_ nums: ArraySlice<Int>) -> Int { 
    if nums.count == 0 { 
     return 0 
    } else { 
     return nums.first! + add(nums.dropFirst()) 
    } 
} 
+0

私はあなたの質問を満足しましたか? – Alexander

答えて

3

Arrayは、ArraySliceとして、任意SequenceからArrayを生成することができるイニシャライザ(init(_:))を有しています。

func sum(_ nums: [Int]) -> Int { 
    guard let head = nums.first else { return 0; } //base case, empty list. 
    return head + sum(Array(nums.dropFirst())) 
} 

let input = Array(1...10) 
let output = sum(input) 
print(output) 

実際には、mattが言ったように、これをしないでください。プログラミングに対するhead/tailアプローチは、パターンマッチング、良いコンパイラの最適化、テールコールの最適化などを容易にする言語で意味があります。Swiftのデザインはreduceを使用することを奨励しています。それは短くて読みやすいだけでなく、より効果的です。

比較のために、ここでは代表的なスウィフトのアプローチはこれにどうなるかです:

extension Sequence where Iterator.Element: Integer { 
    func sum() -> Iterator.Element { 
     return self.reduce(0, +) 
    } 
} 
  • それは、簡単かつ短いです。それはただのIntegerタイプだけでなく、IntArray
  • それはジェネリックだに限定されるのではなく、任意のSequenceでうまくいくよう

  • それは、多形です。したがって、これらすべての作業は:

    print(Array<UInt> (1...10).sum()) 
    print(Array<UInt8> (1...10).sum()) 
    print(Array<UInt16>(1...10).sum()) 
    print(Array<UInt32>(1...10).sum()) 
    print(Array<UInt64>(1...10).sum()) 
    print(Array< Int> (1...10).sum()) 
    print(Array< Int8> (1...10).sum()) 
    print(Array< Int16>(1...10).sum()) 
    print(Array< Int32>(1...10).sum()) 
    print(Array< Int64>(1...10).sum()) 
    

ただし、このヘッド/テールアプローチを取るに主張すれば、これを試してみてください。

extension Array { 
    func HeadTail<ReturnType>(_ closure: (Element?, [Element]) -> ReturnType) -> ReturnType { 
     return closure(self.first, Array(self.dropFirst())) 
    } 
} 

func sum(_ nums: [Int]) -> Int { 
    return nums.HeadTail { head, tail in 
     guard let head = head else { return 0 } //base case, empty list 
     return head + sum(tail) 
    } 
} 

print(sum(Array(1...10))) 

HeadTail(_:)リストをに分割する方法の詳細を抽象化それはあなたのために提供されるheadtailについて心配するだけでsumと書くことを可能にする頭の尾です。

+0

興味深い 'Array'クラスの拡張です。 'reduce'はすべての反復と再帰のニーズを解決するわけではないので、関係はありません。 –

+0

@at。私はあなたの質問に答えましたか? – Alexander

+0

はい、スウィフトでよりエレガントな「頭」と「尾」の仕組みが期待されましたが、おそらくこれはエレガントです。 –

1

あなたの例での問題は、あなたは番号のリストを追加するheadtailを使用しないだろうということです。ことを考えると、私は次の男としてLISP /スキームのように好きですが、あなたは私たちがheadtailを必要とするときの、より説得力のあるケースが必要になります、だから、

let nums = [1,2,3,4,5] 
let sum = nums.reduce(0,+) 

:あなたはreduceを呼びたいですmapfilter、およびreduce(など)があります。

+0

これは教育目的のサンプルでした。 –

+1

それは私が言ったことです。良いサンプルではありません。より魅力的なケースが必要です。 – matt

+0

@matt okは、 'reduce'の実装を実証します。なぜ、' reduce'が存在するだけで、なぜリストを反復する基本的な再帰関数が「説得力のあるケース」でないのか分かりません。 – naomik

関連する問題