元の資料は市ヶ谷Geek★Night #3で発表されていた「ループで遊ぼう」です。
Swift2.0でやりました。
前提
Product
・ Item
・ Code
の構造体かクラスを作る。 Product
が name
を持っていれば何でもいい
struct Product {
let id: Int
let name: String
}
struct Item {
}
struct Code {
}
Product
から Item
を、 String
と Item
から Code
の配列を作る関数を用意しておく。これも作れさえすればなんでもいい
func ItemMake(product: Product) -> Item {
return Item()
}
func CodesMake(name: String, item: Item) -> [Code] {
return [Code()]
}
そして今回のお題に使うもとになる Product
を適当に配列で用意して準備完了
let products = [
Product(id: 0, name: "ぜろ"),
Product(id: 1, name: "いち"),
Product(id: 2, name: "に")
]
本題
for文あり
きもい
var allItemsBuf = [Item]()
var allCodesBuf = [Code]()
for product in products {
let item = ItemMake(product)
allItemsBuf.append(item)
allCodesBuf += CodesMake(product.name, item: item)
}
let allItems = allItemsBuf
let allCodes = allCodesBuf
map
このくらいだったら標準のやつですぐにやれて良い。
let allItems = products.map(ItemMake)
let allCodes = products.flatMap{ p in
CodesMake(p.name, item: ItemMake(p))
}
Monoid
Monoidの準備
struct Monoid<T> {
let op: (T, T) -> T
let zero: T
}
let sum = Monoid<Int>(op: +, zero: 0)
func concatMake<T>(type: T.Type) -> Monoid<Array<T>> {
return Monoid<Array<T>>(op: +, zero: [])
}
func foldMap<T,U>(array: [T], mb: Monoid<U>)(f: T -> U) -> U {
return array.reduce(mb.zero){ a, b in
mb.op(a, f(b))
}
}
concat
については sum
と同様 let concat = ...
みたいにやりたかったけど、そうすると Array<T>
の T
を指定できなくなったので誤魔化した。もう少し調べたらやり方出てくるのかな?
元のScalaの資料では foldMap
の mb: Monoid<U>
を implicit
で省略させる話が出てるけどSwiftでのやり方がよくわからないのでナシ。 protocol Monoid
作れば mb
がなくても zero
や op
を呼び出せるけどそうすると後で出てくるtuple版の書き方がよくわからなくなる…。
Monoid(まだ無駄が残る版)
let allItems = foldMap(products, mb: concatMake(Item))(f: {p in [ItemMake(p)]})
let allCodes = foldMap(products, mb: concatMake(Code))(f: {p in CodesMake(p.name, item: ItemMake(p))})
Monoid(tuple使用版)
func tuple2<T,U>(ma: Monoid<T>, mb: Monoid<U>) -> Monoid<(T,U)> {
return Monoid<(T,U)>(
op: {(x: (T,U), y: (T,U)) -> (T,U) in
(ma.op(x.0, y.0), mb.op(x.1, y.1))
},
zero: (ma.zero, mb.zero)
)
}
let (allItems, allCodes) = foldMap(products, mb: tuple2(concatMake(Item), mb: concatMake(Code)))(f: {p in
let item = ItemMake(p)
return ([item], CodesMake(p.name, item: item))
}
)
Swiftだとtupleが0はじまりでfoldLeftがreduceでもうよくわからない
以上です。
mb
を省略する手段と Monoid<T>
・ Monoid<Array<T>>
をどうにかしたかったです。難しいです。