(It seems like I ask too many basic questions, but Scala is very difficult, especially when it comes to the language feature or syntactic sugar, and I come from a Java background..)
I am watching this video: Scalaz State Monad on YouTube. The lecturer wrote these code:
trait State[S, +A] {
def run(initial: S):(S, A)
def map[B](f: A=>B): State[S, B] =
State { s =>
val (s1, a) = run(s)
(s1, f(a))
}
He said the State on the forth line is a "lambda" expression (I may have misheard). I'm a bit confused about this. He did have an object State, which looks like this:
Object State {
def apply[S, A](f: S=>(S, A)): State[S, A] =
new State[S, A] {
def run(i: S) = f(i)
}
}
The lecturer said he was invoking the apply method of Object State by invoking like that, and yes he did pass in a function that returns a correct tuple, but what is that { s=>? Where the hell did he get the s and is this about the implicit mechanism in Scala?
Also the function that is passed in map function changes A to B already, how can it still pass the generics check (from [S, A] to [S, B] assuming A and B are two different types, or are they the same type?If true, why use B not A in map function?)?
The video link is here and is set to be at 18:17
http://youtu.be/Jg3Uv_YWJqI?t=18m17s
Thank you (Monad is a bit daunting to anyone that's not so familiar with functional programming)
You are on right way here.
He passes the function as parameter, but what is the function in general? Function takes argument and return a value. Returned value here is tuple (s1, f(a)), but also we need to reffer to function argument. s in your example is function argument.
It is same as
def map[B](f: A=>B): State[S, B] = {
def buildState(s: S) = {
val (s1, a) = run(s)
(s1, f(a))
}
State(buildState)
}
But, since we dont need this function anywhere else we just inline it in apply call.
Related
In this session SystemFw gives an example of implementing State[S, A] wih vanilla scala, When follow the exmple, I run into a trouble in supplying a Applicative definition for the vanilla State type (In order to get the commands.traverse work. See code here
I tried to make a implicit def to solve the Applicative instance, but didn't figure out how to deal with the 2 type parameter.
How to implement Applicative for this type:
case class State[S, A](modify: S => (A, S)) {
def runA(initial: S): A = modify(initial)._1
def flatMap[B](f: A => State[S, B]): State[S, B] =
State { s =>
val (result, nextState) = modify(s)
f(result).modify(nextState)
}
}
Wrong code:
implicit def stateApplicative[S, A]: Applicative[State[S, A]] = new Applicative[State[S, A]] {
override def pure[A](x: A): State[A???] = ??? // error
override def ap[A, B](ff: State[A => B])(fa: State[A???]): State[B] = ??? // error
}
Basically, the solution to this problem is always fixing one type parameter.
In the case of a State you want the value inside the state to change but no the type of the state itself so you fix S.
So you can create an application for a given particular state, for example Int
type IntState[A] = State[A, Int]
implicit final val intStateApplicative: Applicative[IntState] =
new Applicative[IntState] {
// Some implementation.
}
However, after you fill the implementation you will see that the fact of knowing that S was Int was meaningless. And that we could just copy and paste the whole code if S would have been String or whatever.
So, what we want is a way to say that this works for any S, we can do that with a type lambda (i.e. a function in the type level).
type StateTypeFun[S] = { type F[A] = State[A, S] }
implicit final def stateApplicative[S]: Applicative[StateTypeFun[S]#F] =
new Applicative[StateTypeFun[S]#F] {
// Some implementation.
}
And that is how we solve this problem.
Note that the type alias is unnecessary but makes the code easier to read, but you could have done Applicative[({ type F[A] = State[A, S]})#F].
BTW, because this necessity of creating type lambdas is somewhat common in Scala 2 we have kind projector, and Scala 3 has proper syntax support for it.
flatMap signature:
/* applies a transformation of the monad "content" by composing
* this monad with an operation resulting in another monad instance
* of the same type
*/
def flatMap(f: A => M[B]): M[B]
is there anyway to understand by its signature (input to output) (except for the name flat) that its flattening the structure? or must I read its implementation to understand that? isn't good coding practice means I can understand by the signature of the function (input to output even without function name) exactly what it does? if so how does flatMap follows this basic programming practice? or does it violates it?
It helps to understand that the type of the thing that flatMap is defined on is also M and would be something like Traversable[A] or a subclass such as a List[A], or another Monad such as Option or Future. Therefore the left hand side of the function definition that flatMap requires (f: A => M[B]) hints to us that this function processes the individual items contained within the Monad, and produces M[B] for each one. The fact that it then returns M[B] rather than M[M[B]] is a hint that some flattening is taking place.
However I disagree that it should be possible to know exactly what a function does by its signature. For example:
Trait Number {
def plus(that: Number): Number
def minus(that: Number): Number
}
Without the function names and possible also some documentation, I don't think it is reasonable to expect that another person can know what plus and minus do.
Does flatMap functional signature (input -> output) proposes its doing any flattening?
Yes, it does.
In fact, join (or flatten), map and unit form a minimal set of primitive functions needed to implement a monad.
flatMap can be implemented in terms of these other functions.
//minimal set
def join[A](mma: M[M[A]]): M[A] = ???
def map[A](ma: M[A], f: A => B): M[B] = ???
def unit[A](a: A): M[A] = ???
def flatMap[A](ma: M[A], f: A => M[B]): M[B] = join(map(ma))
It should now be clear that flatMap flattens the structure of the mapped monad.
For comparison, here's another mimimal set of primitives, where join/flatten is implemented in terms of flatMap.
// minimal set
def unit[A](a: A): M[A] = ???
def flatMap[A](ma: M[A], f: A => M[B]): M[B] = ???
def map[A](ma: M[A], f: A => B): M[B] = flatMap(ma, a => unit(f(a)))
def join[A](mma: M[M[A]]): M[A] = flatMap(mma, ma => ma)
I would like to try partial functions with a deep pattern matching use case. This initially (of course) didn't work after applying Some(Some(3)), but seemed defined instead :
def deepTest : PartialFunction [Option[Option[Int]], Int] = {
case Some(v) => v match {
case None => 3
}
case None => 1
}
and I thought that by decoupling the nested pattern matching, things would be easier:
def deepTestLvl1 : PartialFunction [Option[Option[Int]], Option[Int]] = {
case Some(v) => v
case None => Some(1)
}
def deepTestLvl2 : PartialFunction [Option[Int], Int] = {
case None => 3
}
but the result was the following:
scala> (deepTestLvl1 andThen deepTestLvl2) isDefinedAt(Some(Some(3)))
res24: Boolean = true
and after applying:
scala> (deepTestLvl1 andThen deepTestLvl2) (Some(Some(3)))
scala.MatchError: Some(3) (of class scala.Some)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:248)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:246)
at $anonfun$deepTestLvl2$1.applyOrElse(<console>:7)
at $anonfun$deepTestLvl2$1.applyOrElse(<console>:7)
....
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
Am I doing something incorrectly? Shouldn't the isDefinedAt be called twice when I composed sequentially deepTestLvl{1,2} and give me the correct answer?
Very good question.
Let's check the source and see what's happening under the covers:
override def andThen[C](k: B => C): PartialFunction[A, C] =
new AndThen[A, B, C] (this, k)
We can observe here that andThen doesn't even expect a Partial Function, any Function that transforms the result will do. Your code works, because: trait PartialFunction[-A, +B] extends (A => B). This can actually be found in the documentation:
def andThen[C](k: (B) ⇒ C): PartialFunction[A, C]
Composes this partial function with a transformation function that gets applied to results of this partial function.
C the result type of the transformation function.
k the transformation function
returns a partial function with the same domain as this partial function, which maps arguments x to k(this(x)).
So there's currently no way to chain PartialFunctions in the way you would like, because as Robin said, it would require applying the function. Next to being computationally expensive it could also have side effects, which is a bigger problem.
Update
Whipped together an implementation you're looking for. Use it cautiously! As I already mentioned, if your code has side effects it will cause problems:
implicit class PartialFunctionExtension[-A, B](pf: PartialFunction[A, B]) {
def andThenPf[C](pf2: PartialFunction[B, C]) = new PfAndThen(pf, pf2)
class PfAndThen[+C](pf: PartialFunction[A, B], nextPf: PartialFunction[B, C]) extends PartialFunction[A, C] {
def isDefinedAt(x: A) = pf.isDefinedAt(x) && nextPf.isDefinedAt(pf.apply(x))
def apply(x: A): C = nextPf(pf(x))
}
}
Trying it out:
deepTestLvl1.andThenPf(deepTestLvl2).isDefinedAt(Some(Some(3))) // false
deepTestLvl1.andThenPf(deepTestLvl2).isDefinedAt(Some(None)) // true
deepTestLvl1.andThenPf(deepTestLvl2).apply(Some(None)) // 3
The reason why isDefinedAt on a PartialFunction produced by andThen returns inconsistent results is that it doesn't actually apply the first partial function to its argument, which could be an expensive operation.
This behaviour is likely to trip people up and isn't documented - you might want to submit a patch to add documentation for that.
P.S. My guess is that the reason for deepTest to behave as it does, is that the outermost match in the source code of a partial function definition, and only the outermost match, is considered for definedness purposes - but you'd have to check the source code of scalac to be sure, I think.
I'm working on this Functional Programming in Scala exercise:
// But what if our list has an element type that doesn't have a Monoid instance?
// Well, we can always map over the list to turn it into a type that does.
As I understand this exercise, it means that, if we have a Monoid of type B, but our input List is of type A, then we need to convert the List[A] to List[B], and then call foldLeft.
def foldMap[A, B](as: List[A], m: Monoid[B])(f: A => B): B = {
val bs = as.map(f)
bs.foldLeft(m.zero)((s, i) => m.op(s, i))
}
Does this understanding and code look right?
First I'd simplify the syntax of the body a bit:
def foldMap[A, B](as: List[A], m: Monoid[B])(f: A => B): B =
as.map(f).foldLeft(m.zero)(m.ops)
Then I'd move the monoid instance into its own implicit parameter list:
def foldMap[A, B](as: List[A])(f: A => B)(implicit m: Monoid[B]): B =
as.map(f).foldLeft(m.zero)(m.ops)
See the original "Type Classes as Objects and Implicits" paper for more detail about how Scala implements type classes using implicit parameter resolution, or this answer by Rex Kerr that I've also linked above.
Next I'd switch the order of the other two parameter lists:
def foldMap[A, B](f: A => B)(as: List[A])(implicit m: Monoid[B]): B =
as.map(f).foldLeft(m.zero)(m.ops)
In general you want to place the parameter lists containing parameters that change the least often first, in order to make partial application more useful. In this case there may only be one possible useful value of A => B for any A and B, but there are lots of values of List[A].
For example, switching the order allows us to write the following (which assumes a monoid instance for Bar):
val fooSum: List[Foo] => Bar = foldMap(fooToBar)
Finally, as a performance optimization (mentioned by stew above), you could avoid creating an intermediate list by moving the application of f into the fold:
def foldMap[A, B](f: A => B)(as: List[A])(implicit m: Monoid[B]): B =
as.foldLeft(m.zero) {
case (acc, a) => m.op(acc, f(a))
}
This is equivalent and more efficient, but to my eye much less clear, so I'd suggest treating it like any optimization—if you need it, use it, but think twice about whether the gains are really worth the loss of clarity.
Is there any quick way to use as a concrete function (of type, say, (A) => B) as a PartialFunction[A, B]? The most concise syntax I know of is:
(a: A) => a match { case obj => func(obj) }
Is there an implicit conversion anywhere, something like:
implicit def funcAsPartial[A, B](func: A => B) = new PartialFunction[A, B] {
def isDefinedAt(a: A) = true
def apply(a: A) = func(a)
}
I guess I just wrote what I was looking for, but does this already exist in the Scala libraries?
Doing this with an implicit conversion is dangerous, for the same reason that (A) => B should not inherit from PartialFunction[A, B]. That is, the contract of PartialFunction guarantees that you can safely* call apply wherever isDefinedAt returns true. Function1's contract provides no such guarantee.
Your implicit conversion will result in a PartialFunction that violates its contract if you apply it to a function that is not defined everywhere. Instead, use a pimp to make the conversion explicit:
implicit def funcAsPartial[A, B](f: A => B) = new {
/** only use if `f` is defined everywhere */
def asPartial(): PartialFunction[A, B] = {
case a => f(a)
}
def asPartial(isDefinedAt: A => Boolean): PartialFunction[A, B] = {
case a if isDefinedAt(a) => f(a)
}
}
// now you can write
val f = (i: Int) => i * i
val p = f.asPartial // defined on all integers
val p2 = f.asPartial(_ > 0) // defined only on positive integers
* As discussed in the comments, it may not be entirely clear what "safety" means here. The way I think about it is that a PartialFunction explicitly declares its domain in the following precise sense: if isDefinedAt returns true for a value x, then apply(x) can be evaluated in a way that is consistent with the intent of the function's author. That does not imply that apply(x) will not throw an exception, but merely that the exception was part of the design of the function (and should be documented).
No, I tried to find one a few months ago and ended up writing my own that's essentially the same as yours.