views:

152

answers:

2

I found a blog post today that mention's scalaz's sequence function.

Couldn't you do something as simple as:

if (l contains None) None else l

If so, what would this function signature look like? contains is in SeqLike, right?

Also, from the blog post I thought sequence was going to be something similar to map, but one that would break once None is encountered. Is there something like this?

+2  A: 

Yes, you could, but it should be:

if (l contains None) None else Some(l.map(_.get))

The code in the blog post tries to write that function as general as possible (using scalaz' abstractions), so it will work not only for Options in a Seq.

[Edit] Corrected

Landei
`Some(l.map(_.get))`
retronym
Thanks. My question was more toward getting the types right on a method that would encapsulate this logic. I should have been more clear. def fakeSequence(a: ?): ?
Bradford
Ehrm, isn't this wrong? `sequence(List(Some(a), Some(b)))` should return `Some(List(a,b))`, while your version would return `Some(List(Some(a),Some(b)))`. Or am I missing something?
sepp2k
No, you are right. I think that's what retronym was trying to point out.
Bradford
@retronym: Thank you, I forgot that...
Landei
+1  A: 

Yes you can definitely write the sequence function specialized to some specific data structure. The Scalaz version, however is as general as possible. So it will work for any combination of F and G for which F[G[A]] => G[F[A]] is possible.

The other function you're looking for is called traverse. It has the signature

def traverse[F[_]:Traverse,G[_]:Applicative,A,B](m: F[A], f: A => G[B]): G[F[B]]

x.traverse(f) is equivalent to x.map(f).sequence.

x.sequence is equivalent to x.traverse(a => a)

Apocalisp
Sorry, I'm new (and if I am questioning you, I am probably wrong), but is this really correct: "x.traverse(f) is equivalent to x.map(f).sequence"? It just seems strange that the definition of sequence be in the definition of traverse. Also, what exactly do traverse and sequence do in layman terms? And List(Some(1), Some(2), None, Some(3)).traverse(a => { println(a); a }) seems to print all terms instead of just printing until it reaches None.
Bradford
`sequence` is in fact defined in Scalaz as `traverse(a => a)`. The implementation for `traverse` is per type constructor (it's different for every `G`). But yeah, that really is correct. Think about it. Do you think `x.traverse(f)` is equal to `x.map(f).traverse(a => a)`? How could it not be?
Apocalisp
The types are somewhat self-explanatory, but in layman's terms `sequence` distributes `F` over `G`. It helps to think about concrete types, i.e. turn a List of Options into an Option of List in the obvious way, or a List of functions into a function that returns a List. `traverse(f)` does exactly: `map(f).sequence`. The reason it doesn't break is that the implementation is overly strict. That can actually be fixed, but Scala doesn't make it easy.
Apocalisp
In the latest trunk head I've made Applicative functors nonstrict, so traverse in case of Option will now "break" upon encountering a None.
Apocalisp
I'm fairly new to scala and scalaz, so bear with me, but I'm trying trunk out and val l: List[Option[Int]] = List(Some(1), Some(2), Some(3)); l.sequence.get; throws an exception java.lang.ClassCastException: scala.collection.immutable.Stream$Cons cannot be cast to scala.collection.immutable.List
Bradford
Yeah, I wasn't careful enough about inheritance in the standard libraries. Thanks for finding that issue. Fixed now.
Apocalisp