Swift 中的函数式思维?
Functional thinking in Swift?
我开始学习 Haskell 和 Swift。我想知道这是否是 "functional" 方式的正确思考方式?
问题是创建卡片组:
我需要遍历花色和等级——为每个花色创建具有给定花色和等级的卡片。 "imperative" 方式是:
let suits: Array<Character> = ...
let ranks: Array<Int> = ...
var cards: [Card]
for suit in suits {
for rank in ranks {
cards.addObject(Card(suit: suit, rank: rank))
}
}
然后我尝试使用递归的纯函数,它有效但是,可以用更少的代码来完成吗?
对我来说 Swift 中的 "functional" 可读性较差,或者我做错了......
let cards = cardsWithSuits(suits, ranks, [Card]());
func cardsWithSuits(suits: [Character], ranks: [Int], cards: [Card]) -> [Card] {
if suits.count == 0 { return cards }
let suit: Character = head(suits)!
let acc = cardsWithRanks(ranks, suit, cards)
return cardsWithSuits(drop(1, suits), ranks, acc)
}
func cardsWithRanks(ranks: [Int], suit: Character, cards: [Card]) -> [Card] {
if ranks.count == 0 { return cards }
let acc = cards + [Card(suit: suit, rank: head(ranks)!)]
return cardsWithRanks(drop(1, ranks), suit, acc)
}
基于 Haskell 的应用概念以及 <$>
和 <*>
的用法,您可能会发现以下内容通常有用(我认为我翻译正确,尽管它基于在数组而不是序列上):
// use <^> because <$> is already used
infix operator <^> { associativity left }
public func <^> <T, U>(left:(T)->U, right:[T]) -> [U] {
return map(right) { return left([=10=]) }
}
public func flatten<T>(input:[[T]]) -> [T] {
return input.reduce([], +)
}
infix operator <*> { associativity left }
public func <*> <T, U>(left:[(T)->U], right:[T]) -> [U] {
return flatten(map(left) { (function) -> [U] in
return map(right) { return function([=10=]) }
})
}
然后允许您使用以下内容:
let suits : [Character] = [ "C", "D", "H", "S"]
let ranks = Array(2...14)
struct Card {
let suit : Character
let rank : Int
static func build(suit:Character)(rank:Int) -> Card {
return Card(suit: suit, rank:rank)
}
}
Card.build <^> suits <*> ranks
这可能不漂亮,我不认为它是函数式编程,但它的代码更少,而且它使用了 Swift 非常棒的 map 和 reduce 函数:
struct Card {
let suit: String
let rank: Int
}
let cards = ["Heart", "Diamond", "Club", "Spade"].reduce([Card]()) { (cards, suit) in
return cards + map(1...13) { rank in return Card(suit: suit, rank: rank) }
}
Swift 不是函数式语言。但是,您可以编写 swift 函数式代码。
func map<T: Collection, U>( _ transform: (T.Iterator.Element) -> U, _ xs: T) -> [U] {
return xs.reduce([U](), {[=10=] + [transform()]})
}
func concatMap<A, B> (_ process: (A)->[B], _ xs: [A]) -> [B] {
return xs.reduce([B](), {[=10=] + process()})
}
infix operator <*>
func <*><A, B>(_ xs: [A], _ ys: [B]) -> [(A, B)]{
let transform: (A, B) -> (A, B) = {([=10=], )}
return concatMap({x in map({transform(x, [=10=])}, ys)}, xs)
}
struct Card {
let suit : Character
let rank : Int
static func build(_ sr: (s:Character, r:Int)) -> Card {
return Card(suit: sr.0, rank: sr.1)
}
}
func test() {
let suits : [Character] = [ "C", "D", "H", "S"]
let ranks = Array(1...13)
let cards = map(Card.build, suits <*> ranks)
print(cards)
}
如果你想学习Haskell和Swift,你可以参考https://github.com/unchartedworks/HaskellSwift
我开始学习 Haskell 和 Swift。我想知道这是否是 "functional" 方式的正确思考方式? 问题是创建卡片组: 我需要遍历花色和等级——为每个花色创建具有给定花色和等级的卡片。 "imperative" 方式是:
let suits: Array<Character> = ...
let ranks: Array<Int> = ...
var cards: [Card]
for suit in suits {
for rank in ranks {
cards.addObject(Card(suit: suit, rank: rank))
}
}
然后我尝试使用递归的纯函数,它有效但是,可以用更少的代码来完成吗? 对我来说 Swift 中的 "functional" 可读性较差,或者我做错了......
let cards = cardsWithSuits(suits, ranks, [Card]());
func cardsWithSuits(suits: [Character], ranks: [Int], cards: [Card]) -> [Card] {
if suits.count == 0 { return cards }
let suit: Character = head(suits)!
let acc = cardsWithRanks(ranks, suit, cards)
return cardsWithSuits(drop(1, suits), ranks, acc)
}
func cardsWithRanks(ranks: [Int], suit: Character, cards: [Card]) -> [Card] {
if ranks.count == 0 { return cards }
let acc = cards + [Card(suit: suit, rank: head(ranks)!)]
return cardsWithRanks(drop(1, ranks), suit, acc)
}
基于 Haskell 的应用概念以及 <$>
和 <*>
的用法,您可能会发现以下内容通常有用(我认为我翻译正确,尽管它基于在数组而不是序列上):
// use <^> because <$> is already used
infix operator <^> { associativity left }
public func <^> <T, U>(left:(T)->U, right:[T]) -> [U] {
return map(right) { return left([=10=]) }
}
public func flatten<T>(input:[[T]]) -> [T] {
return input.reduce([], +)
}
infix operator <*> { associativity left }
public func <*> <T, U>(left:[(T)->U], right:[T]) -> [U] {
return flatten(map(left) { (function) -> [U] in
return map(right) { return function([=10=]) }
})
}
然后允许您使用以下内容:
let suits : [Character] = [ "C", "D", "H", "S"]
let ranks = Array(2...14)
struct Card {
let suit : Character
let rank : Int
static func build(suit:Character)(rank:Int) -> Card {
return Card(suit: suit, rank:rank)
}
}
Card.build <^> suits <*> ranks
这可能不漂亮,我不认为它是函数式编程,但它的代码更少,而且它使用了 Swift 非常棒的 map 和 reduce 函数:
struct Card {
let suit: String
let rank: Int
}
let cards = ["Heart", "Diamond", "Club", "Spade"].reduce([Card]()) { (cards, suit) in
return cards + map(1...13) { rank in return Card(suit: suit, rank: rank) }
}
Swift 不是函数式语言。但是,您可以编写 swift 函数式代码。
func map<T: Collection, U>( _ transform: (T.Iterator.Element) -> U, _ xs: T) -> [U] {
return xs.reduce([U](), {[=10=] + [transform()]})
}
func concatMap<A, B> (_ process: (A)->[B], _ xs: [A]) -> [B] {
return xs.reduce([B](), {[=10=] + process()})
}
infix operator <*>
func <*><A, B>(_ xs: [A], _ ys: [B]) -> [(A, B)]{
let transform: (A, B) -> (A, B) = {([=10=], )}
return concatMap({x in map({transform(x, [=10=])}, ys)}, xs)
}
struct Card {
let suit : Character
let rank : Int
static func build(_ sr: (s:Character, r:Int)) -> Card {
return Card(suit: sr.0, rank: sr.1)
}
}
func test() {
let suits : [Character] = [ "C", "D", "H", "S"]
let ranks = Array(1...13)
let cards = map(Card.build, suits <*> ranks)
print(cards)
}
如果你想学习Haskell和Swift,你可以参考https://github.com/unchartedworks/HaskellSwift