オプショナルな値の配列を配列のオプショナルに変えたいことはよくある。(たぶん)
[Int?]
を [Int]?
にしたい。
Haskellを例にだす。
[Just 1, Just 2, Nothing, Just 3] :: [Maybe Int]
sequence [Just 1, Just 2, Nothing, Just 3] :: Maybe [Int] -- => Nothing
sequence [Just 1, Just 2, Just 3] :: Maybe [Int] -- => Just [1,2,3]
ひとつでもNothing
があればNothing
になる。
Optinalに限定にしているので、こんな風に書いておいた。
func sequence<T>(xs: [T?]) -> [T]? {
var result: [T]? = []
for optX in xs {
if let x = optX {
result?.append(x)
} else {
return nil
}
}
return result
}
let xs: [Int?] = [1, 2, nil, 3] // => [{Some 1}, {Some 2}, nil, {Some 3}]
sequence(xs) // => nil
let ys: [Int?] = [1,2,3] // => [{Some 1}, {Some 2}, {Some 3}]
sequence(ys) // => [1, 2, 3]
内部に副作用がある場合は途中でreturnすべきでない気がする。
一応 reduceでもかいておこう。
func sequence2<T>(xs: [T?]) -> [T]? {
return xs.reduce([], combine: { (var acc,optX) in
if let x = optX {
acc?.append(x)
return acc
} else {
return nil
}
})
}
sequence2([1, 2, nil, 3])
sequence2([1,2,3])
accに変更を加えないといけないのでvarにした。このあたりどうかいていくのがいいのかよくわからない。
より良い方法やライブラリがあったら教えて欲しい。
実際のsequenceはもっと一般的なので注意.
> :t sequence
sequence :: (Monad m, Traversable t) => t (m a) -> m (t a)