I've got an exercise to create a product of two functions from the code below:
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) = {
}
My plan was to do something like this, but it doesn't work, because it can't resolve symbols A and B.
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) = {
v1: (A,B) => f(A)*g(B)
}
The syntax to define a function type signature and a function definition is different. When you return a value, you need to return the function definition.
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) =
(a: A, b: B) => (f(a), g(b))
Related
I started to learn the basics of scala and and I have problem with understanding simple function. I have three tasks to do. First of them was easy for me and i know how it works. But next two I don't understand what I have to write to return.
def compose[A,B,C](f: A => B)(g: B => C): A => C = {
a: A => g(f(a))
}
def prod[A,B,C,D](f: A => C, g: B => D): (A, B) => (C, D) {
???????????
}
def lift[A,T](op: (T,T) => T)(f: A => T, g: A => T): A => T {
??????????
}
Let's look at the types, you should be able to implement the method quite easily by looking at the them.
Start with prod, start by writing the input parameters and expected output:
def prod[A,B,C,D](f: A => C, g: B => D): (A, B) => (C, D) = {
(a: A, b: B) => {
val c: C = ???
val d: D = ???
(c, d)
}
}
Then, how can you build c and d given what you have (that is f and g)?
I let you answer this question by yourself.
The same can be applied for lift:
def lift[A,T](op: (T,T) => T)(f: A => T, g: A => T): A => T {
(a: A) => {
val t: T = ???
}
}
This one might be a bit trickier if you have no idea what lift is supposed to do though.
Hint: you probably have to use f and g, otherwise they wouldn't exist. Then from the values you get, how to get the desired output type?
I'm implementing the List type in Scala when following a book.
Here's the definition of my List type:
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
All the later mentioned functions are defined in the companion object List in the same file
object List
I wrote foldLeft and foldRight as the following
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
case Nil => z
case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
}
def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B = l match {
case Nil => z
case Cons(x, xs) => f(x, foldRight(xs, z)(f))
}
There's an exercise on the book, which is to implement foldLeft using foldRight. Here's my initial implementation
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)((a: A, b: B) => f(b, a))
}
Then I think I should write another function to do the reverse arguments if I'm to implement foldRight using foldLeft. As follows:
def reverseArgs[A,B](f: (A, B) => B): (B, A) => B = {
(b: B, a: A) => f(a, b)
}
So I changed code of foldLeftWithRight to the following:
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)(reverseArgs(f))
}
And IntelliJ is complaining about reverseArgs(f):
Type mismatch: expected (A, B) => B, actual (B, B) => B
When I try to compile the code, the error is the following:
Error:(21, 37) type mismatch;
found : (B, A) => B
required: (B, Any) => Any
foldRight(l, z)(reverseArgs(f))
An interesting observation is that when I use the reverseArgs on foldRightWithLeft, there's no problem at all:
def foldRightWithLeft[A,B](l: List[A], z: B)(f: (A, B) => B): B = {
foldLeft(l, z)(reverseArgs(f))
}
What is going on here?
If you rename type parameters of your reverseArgs function to X and Y, you'll get something like
def reverseArgs[X ,Y](f: (X, Y) => Y): (Y, X) => Y = ???
Type of f in foldLeftWithRight is (B, A) => B. Passing that to reverseArgs means that:
X = B
Y = A
Y = B
I guess Intellij infers from here that A = B and this is why it's complaining that (B, B) => B isn't (A, B) => B. Scalac decides that Y = Any instead, because it's the least upper bound of two potentially unrelated types.
Good solution here is to generalize more. Return type of reversed function does not have to be one of parameter types, so you can introduce another generic type for that:
def reverseArgs[X ,Y, Z](f: (X, Y) => Z): (Y, X) => Z = {
(b: Y, a: X) => f(a, b)
}
def curry[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => f(a, _)
def curry[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => (b: B) => f(a, b)
What I was thinking was that in the first implementation I would take the function f and pass in an A and an anything (but the compiler will type check that the second param is a B) to get a C out.
Yes, they are identical. If you compile:
object Test {
def curry[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => f(a, _)
def curry2[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => (b: B) => f(a, b)
}
with -Xprint:typer, you get the intermediate abstract syntax tree:
[[syntax trees at end of typer]]
package <empty> {
object Test extends scala.AnyRef {
def <init>(): Test.type = {
Test.super.<init>();
()
};
def curry[A, B, C](f: (A, B) => C): A => (B => C) = ((a: A) => ((x$1: B) => f.apply(a, x$1)));
def curry2[A, B, C](f: (A, B) => C): A => (B => C) = ((a: A) => ((b: B) => f.apply(a, b)))
}
}
During the "typer" stage, when the compiler assigns types to everything, it realizes that the _ (now named x$1) must be type B.
see https://www.fpcomplete.com/user/edwardk/phoas
some background code
trait ProfunctorStr[->[_, _]] {
def dimap[A, B, C, D]: (C => A) => (B => D) => (A -> B) => (C -> D) = { f =>
g => {
lazy val h: (A -> B) => (C -> B) = mapfst(f)
lazy val hh: (C -> B) => (C -> D) = mapsnd(g)
h andThen hh
}
}
def mapfst[A, B, C]: (C => A) => (A -> B) => (C -> B) =
f => p => dimap[A, B, C, B](f)(x => x)(p)
def mapsnd[A, B, C]: (B => C) => (A -> B) => (A -> C) =
f => p => dimap[A, B, A, C](x => x)(f)(p)
// convenient for certain implementations
def mfst[A, B, C](p: A -> B)(f: C => A): C -> B = mapfst(f)(p)
def msnd[A, B, C](p: A -> B)(f: B => C): (A -> C) = mapsnd(f)(p)
}
abstract class Rec[F[_, _], A, B] {
def runRec[R]: (B => R) => (F[A, R] => R) => R
}
object Rec {
abstract class RecProfunctor[F[_, _]](implicit F: ProfunctorStr[F])
extends ProfunctorStr[({type l[x, y] = Rec[F, x, y] })#l] {
def dimap[A, B, C, D] = { f =>
g => rab =>
def P = function1Profunctor
new Rec[F, C, D] {
def runRec[R] = { ??? }
}
}
}
}
reading that article I feel like I get the gist but I'm having trouble implementing in scala, particularly how to transform that Rec[F, C, D] { runRec[R] = { ?!?!?! } } I really want to get this so if you can explain how to transform that
(B => R) => (F[A, R] => R) => R
into
(D => R) => (F[C, R] => R) => R
I think...
Any way any and all help is very much appreciated, and detail as deeply loved. thank you
Given that there is a functionfoo[A, B, C]( func: (a: A, b: B, c: C) => B) and I want to pass in this function def secondOfThree[A, B, C](a: A, b: B, c: C): B = b
I can call foo with foo(secondOfThree) which is ugly, but works fine.. However, I would expect to be able to call foo with something along the lines of foo(case (_, b, _) => b) however this doesn't work.
So what's the clean idiomatic scala way of creating a simple unnamed extracting function?
You don't need the case keyword, but Scala does need to know the types:
scala> def foo[A, B, C](func: (A, B, C) => B) = ...
foo: [A, B, C](func: (A, B, C) => B)Nothing
scala> foo[Symbol, Int, Char]((_, b, _) => b)
If the types are known to foo, then the call doesn't need to specify them:
scala> def foo(func: (Symbol, Int, Char) => Int) = func('a, 2, 'c') + 5
foo: (func: (Symbol, Int, Char) => Int)Int
scala> foo((_, b, _) => b)
res3: Int = 7
So if types could be inferred, you can just the simplest:
class Trio[A, B, C](a: A, b: B, c: C) {
def foo(func: (A, B, C) => B): B = func(a, b, c)
}
println(new Trio(1, "string", 'Symbol).foo((_, b, _) => b))