(no title)
speedkills | 7 years ago
Here is how I read this in case it helps anyone
Def zip[A, B](a: ⇒ F[A], b: ⇒ F[B]): F[(A, B)]
F[Something] is a “container type” or a type constructor, a type that is parameterized by another type, for example F[Int] could be List[Int] or Future[Int].The method zip has two parameters, one a by name reference to something of type F[A] and the other a by name reference to something of type F[B] and returns an F of the pair of input types (A, B)
Looks like this deals with three total types, a container type F that must be the same for input param a, input param b, and the result.
I know nothing about F other than the fact that it contains another type. I know nothing about A and nothing about B which means I can’t be looking them up somewhere or using defaults, so the only way I could possibly return an F[(A, B)] is if I combined the two inputs.
Also, code written in this style is meant to follow the substitution principle, so I’ll think through a couple of substitutions to see how this method could be useful to me.
For: F = List, A = Int, B = String
Def zip[Int, String](a: => List[Int], b: => List[String]): List[(Int, String)]
Since I can’t invent new members of list and the two members of the list may be different lengths, this must return a list whose length is the minimum of a.length and b.length containing and int -> string mapping. Handy.F = Future, A = User, B = LastLoginDate
Def zip[User, LastLoginDate](a: => Future[User], b: => Future[LastLoginDate]): Future[(User, LastLoginDate)]
This can only return me a User if they have logged in at least once. The fact that it is two Futures makes me think I am probably querying two remote servers for this information and that I can’t resolve the new Future until both of the input Futures have resolved. By the time this Future is ready I will have a User with their last login date or the Future will fail.F = Option, A = IpAddress, B = Port
Def zip[IpAddress, Port](a: => Option[IpAddress], b: => Option[Port]): Option[(IpAddress, Port)]
I may have an IpAddress, I may have a Port, either return to me both the IpAddress and the Port, or neither.
This one is really easy to map out as their are only 4 possible code paths Some(IpAddress), Some(Port) => Some(IpAddress, Port)
Some(IpAddress), None => None
None, Some(Port) => None
None, None => None
I agree some documentation explaining this would be nice, but there is considerable information I can pull from this signature.
pas|7 years ago
Reading signatures is one thing (and zip is "easy"), but without examples it doesn't really help in most of the cases. Because even if I know the concept, I don't know when it comes handy. (For example I just looked at Forall ( https://static.javadoc.io/org.scalaz/scalaz_2.12/7.2.24/scal... ... Forall is an endofunctor in an endofunctor category ... ah yes!), and then there are tools that come with labels (DList's doc page: nice for append heavy workloads, eg. logging; yes, great, what's Forall good for? What's Strong? Why Alpha exists? What's =>: ? That's not even documented :( It cannot be searched for https://github.com/scalaz/scalaz/search?utf8=%E2%9C%93&q=%3D... ... It's not on the cheatsheet http://eed3si9n.com/scalaz-cheat-sheet .. .I mean it's on it, but it is only used, not defined. etc.)
That's not a type reading thing. That's the bad documentation, and the learner-unfriendly naming convention.