Type Driven Development with Idris presents the following generic adder approach:
AdderType : (numArgs : Nat) -> Type
AdderType Z = Int
AdderType (S k) = (next : Int) -> AdderType k
adder : (n : Nat) -> (acc : Int) -> AdderType n
adder Z acc = acc
adder (S k) acc = \x => (adder k (x+acc))
Example:
-- expects 3 Int's to add, with a starting value of 0
*Work> :t (adder 3 0)
adder 3 0 : Int -> Int -> Int -> Int
-- 0 (initial) + 3 + 3 + 3 == 9
*Work> (adder 3 0) 3 3 3
9 : Int
I'm guessing that shapeless can handle the above generic adder function.
How can it be written in Scala with or without shapeless?
Update: I'll leave my original implementation below, but here's one that's a little more direct:
import shapeless._
trait AdderType[N <: Nat] extends DepFn1[Int]
object AdderType {
type Aux[N <: Nat, Out0] = AdderType[N] { type Out = Out0 }
def apply[N <: Nat](base: Int)(implicit at: AdderType[N]): at.Out = at(base)
implicit val adderTypeZero: Aux[Nat._0, Int] = new AdderType[Nat._0] {
type Out = Int
def apply(x: Int): Int = x
}
implicit def adderTypeSucc[N <: Nat](implicit
atN: AdderType[N]
): Aux[Succ[N], Int => atN.Out] = new AdderType[Succ[N]] {
type Out = Int => atN.Out
def apply(x: Int): Int => atN.Out = i => atN(x + i)
}
}
And then:
scala> val at3 = AdderType[Nat._3](0)
at3: Int => (Int => (Int => Int)) = <function1>
scala> at3(3)(3)(3)
res8: Int = 9
Original answer below.
Here's an off-the-cuff Scala translation:
import shapeless._
trait AdderType[N <: Nat] extends DepFn1[Int] {
protected def plus(x: Int): AdderType.Aux[N, Out]
}
object AdderType {
type Aux[N <: Nat, Out0] = AdderType[N] { type Out = Out0 }
def apply[N <: Nat](base: Int)(implicit at: AdderType[N]): Aux[N, at.Out] =
at.plus(base)
private[this] case class AdderTypeZero(acc: Int) extends AdderType[Nat._1] {
type Out = Int
def apply(x: Int): Int = acc + x
protected def plus(x: Int): Aux[Nat._1, Int] = copy(acc = acc + x)
}
private[this] case class AdderTypeSucc[N <: Nat, Out0](
atN: Aux[N, Out0],
acc: Int
) extends AdderType[Succ[N]] {
type Out = Aux[N, Out0]
def apply(x: Int): Aux[N, Out0] = atN.plus(acc + x)
protected def plus(x: Int): Aux[Succ[N], Aux[N, Out0]] = copy(acc = acc + x)
}
implicit val adderTypeZero: Aux[Nat._1, Int] = AdderTypeZero(0)
implicit def adderTypeSucc[N <: Nat](implicit
atN: AdderType[N]
): Aux[Succ[N], Aux[N, atN.Out]] = AdderTypeSucc(atN, 0)
}
And then:
scala> val at3 = AdderType[Nat._3](0)
at3: AdderType[shapeless.Succ[shapeless.Succ[shapeless.Succ[shapeless._0]]]] { ...
scala> at3(3)(3)(3)
res0: Int = 9
It's more verbose and the representation is a little different to get the Scala syntax to work out—our "base case" is essentially an Int => Int instead of an Int because otherwise I don't see a way to avoid needing to write apply or () everywhere—but the basic ideas are exactly the same.
In case you're on a long trip and don't have your shapeless on hands, here is how you can do this in pure Scala. It can be useful for those who are not familiar with shapeless and those who don't use it for some reason.
First of all, we'll need some way to iterate on types, i.e. represent natural numbers in types. You can use any nested type or just define a new one with some aliases for numbers:
sealed trait Nat
trait Zero extends Nat
trait Succ[N <: Nat] extends Nat
// enough for examples:
type _0 = Zero
type _1 = Succ[_0]
type _2 = Succ[_1]
type _3 = Succ[_2]
type _4 = Succ[_3]
// etc...
Of course, if you will often use types like _42 and _342923, it would be more convenient to take an existing Nat type with some macro-magic for constructing those from values, but for our examples it's enough.
Now, the AdderType dependent function type is quite straight forward:
// first we define the type which take a Nat type argument
trait AdderType[N <: Nat] {
type Out
def apply(i: Int): Out
}
// then we inductively construct its values using implicits
case object AdderType {
// base case: N = _0
implicit def zero:
AdderType[_0] { type Out = Int } =
new AdderType[_0] {
type Out = Int
def apply(i: Int): Out = i
}
// induction step: N -> Succ[N]
implicit def succ[N <: Nat, NOut](
implicit prev: AdderType[N] { type Out = NOut }
): AdderType[Succ[N]] { type Out = Int => NOut } =
new AdderType[Succ[N]] {
type Out = Int => NOut
def apply(i: Int): Out = k => prev(i + k)
}
}
Now, to construct an instance of AdderType and apply it, we write a function, which takes a N <: Nat as a type argument and implicitly constructs AdderType[N]:
def adder[N <: Nat](initial: Int)(
implicit adderFunction: AdderType[N]
): adderFunction.Out = adderFunction(initial)
That's it:
scala> val add3Numbers = adder_[_3](0)
add3Numbers: Int => (Int => (Int => Int)) = <function1>
scala> add3Numbers(1)(2)(3)
res0: Int = 6
You can see that the pure solution is not much bigger or more complicated than the one using shapeless (although the latter provides us ready-to-use Nat and DepFn types).
A little addition: if (in some more general case) you don't want to use adderFunction.Out, which sometimes leads to problems, I also have a solution without it. In this particular case it's not any better, but I'll show it anyway.
The key point is to add another type parameter for the out type: adder[N <: Nat, NOut], but then can't pass N as a type to adder, because we will need to write NOut, which want to be inferred (otherwise, what's the point). So we can pass an additional value argument, which will help to derive N type:
def adder[N <: Nat, NOut](n: NatVal[N])(initial: Int)(
implicit adderFunction: AdderType[N] { type Out = NOut }
): NOut = adderFunction(initial)
To construct NatVal[N] we don't need to create an instance of each Nat type, we can use a little trick:
// constructing "values" to derive its type arg
case class NatVal[N <: Nat]()
// just a convenience function
def nat[N <: Nat]: NatVal[N] = NatVal[N]()
Now here is how you use it:
scala> val add3Numbers = adder(nat[_3])(0)
add3Numbers: this.Out = <function1>
scala> add3Numbers(1)(2)(3)
res1: this.Out = 6
You can see that it works, but doesn't show us the actual types. Nevertheless, this approach can work better in cases when you have several implicits that depend others' type members. I mean
def foo[AOut]()(implicit
a: A { type Out = AOut},
b: B { type In = AOut }
) ...
instead of
def foo()(implicit
a: A,
b: B { type In = a.Out }
) ...
Because you cannot reffer to a.Out in the same argument list.
You can find full code in my repo on Github.
Related
I am aware that in Scala 3 it is now possible to convert between case class instances and tuples using Tuple.fromProductTyped and summon[Mirror.Of].fromProduct.
I would like to be able to define a typeclass that witnesses that a case class T can be converted to and from (A, B) using the aforementioned methods.
I've defined the typeclass like so:
trait IsPair[T, A, B]:
def toTuple(t: T): (A, B)
def fromTuple(ab: (A, B)): T
How can we derive IsPair for any conforming case class?
With the derivation in place, the following should compile and run without error:
case class Foo(a: Int, b: String)
val fooIsPair = summon[IsPair[Foo, Int, String]]
val foo = Foo(42, "qwerty")
val tuple = (42, "qwerty")
assert(fooIsPair.toTuple(foo) == tuple)
assert(fooIsPair.fromTuple(tuple) == foo)
You can just use a Mirror but restrict it to be for pair-like case classes:
import scala.deriving.Mirror
sealed trait IsPair[T]:
type A
type B
def toTuple(t: T): (A, B)
def fromTuple(ab: (A, B)): T
object IsPair:
type Aux[T, X, Y] = IsPair[T] { type A = X; type B = Y }
inline def apply[T](using ev: IsPair[T]): ev.type = ev
given instance[T <: Product, X, Y](using
ev: Mirror.Product { type MirroredType = T; type MirroredMonoType = T; type MirroredElemTypes = (X, Y) }
): IsPair[T] with
override final type A = X
override final type B = Y
override def toTuple(t: T): (X, Y) =
Tuple.fromProductTyped(t)
override def fromTuple(xy: (X, Y)): T =
ev.fromProduct(xy)
end IsPair
That way we can do this:
val foo = Foo(42, "qwerty")
val tuple = (42, "qwerty")
val fooIsPair = IsPair[Foo]
assert(fooIsPair.toTuple(foo) == tuple)
assert(fooIsPair.fromTuple(tuple) == foo)
You can see the code running here.
How can I make this work? My task at hand is a little bit more complicated but it boils down to this:
object Z {
class B extends Function1[Int, Int] {
def apply(i: Int): Int = i
}
def compose[T <: Function1[X, X], X](fcts: List[T]): Function1[X, X] = {
fcts.reduce(_ andThen _)
}
def test() = {
val fcts = List.empty[B]
// Unspecified type parameter X
val composed: Function1[Int, Int] = compose[B](fcts)
}
}
I don't know how to define the "compose" function to be able to receive some concrete class B and automatically infer the dependent types X
The Scala compiler does not do well when trying to infer multiple levels of type parameters like you have. Instead, it would be simpler to remove T <: Function1[X, X] and simply require a single type parameter that represents the argument and return type of the Function1.
def compose[A](fcts: List[Function1[A, A]]): Function1[A, A] = {
fcts.reduce(_ andThen _)
}
The compiler will have a much easier time simply inferring A, instead of trying to figure out what with T and X are, when X is part of type T.
val a: Int => Int = _ + 10
val b: Int => Int = _ * 2
val c: Int => Int = _ - 3
scala> val f = compose(List(a, b, c))
f: Int => Int = scala.Function1$$Lambda$1187/930987088#531ec2ca
scala> f(2)
res1: Int = 21
Note that reduce will throw an exception for an empty list of functions.
New to shapeless and I have a question on using polymorphic functions that need some dependencies. I basically have this code and want to pull somePoly object out of the run method:
import shapeless._
object SomeObject {
type SomeType = Int :+: String :+: (String, Int) :+: CNil
def run( someList: List[SomeType], someInt:Int, someWord:String ) = {
object somePoly extends Poly1 {
implicit def doIt = at[Int]( i => i + someInt + someWord.length)
implicit def doIt2 = at[String]( i => i.length + someWord.length)
implicit def doIt3 = at[(String, Int)]( i => i._1.length + someWord.length)
}
someList.map( _.map(somePoly) )
}
}
One way I thought of doing it was like this, but it seems messy:
object TypeContainer {
type SomeType = Int :+: String :+: (String, Int) :+: CNil
}
case class SomePolyWrapper( someList: List[TypeContainer.SomeType], someInt:Int, someWord:String ){
object somePoly extends Poly1 {
implicit def doIt = at[Int]( i => i + someInt + someWord.length)
implicit def doIt2 = at[String]( i => i.length + someWord.length)
implicit def doIt3 = at[(String, Int)]( i => i._1.length + someWord.length)
}
}
object SomeObject {
def run( someList: List[TypeContainer.SomeType], someInt:Int, someWord:String ) = {
val somePolyWrapper = SomePolyWrapper(someList, someInt, someWord)
someList.map( _.map(somePolyWrapper.somePoly) )
}
}
Anyone have any advice?
The limitations of Scala's implicit resolution system mean the Poly definition needs to be a stable identifier, which makes this kind of thing more painful than it should be. As I mentioned on Gitter, there are a couple of workarounds that I know of (there may be others).
One approach would be to make the Poly1 a PolyN, where the extra arguments are for the someInt and someWord values. If you were mapping over an HList, you'd then use mapConst and zip to make the input HList have the right shape. I've never done this for a coproduct, but something similar is likely to work.
Another approach is to use a custom type class. In your case that might look something like this:
import shapeless._
trait IntFolder[C <: Coproduct] {
def apply(i: Int, w: String)(c: C): Int
}
object IntFolder {
implicit val cnilIntFolder: IntFolder[CNil] = new IntFolder[CNil] {
def apply(i: Int, w: String)(c: CNil): Int = sys.error("Impossible")
}
def instance[H, T <: Coproduct](f: (H, Int, String) => Int)(implicit
tif: IntFolder[T]
): IntFolder[H :+: T] = new IntFolder[H :+: T] {
def apply(i: Int, w: String)(c: H :+: T): Int = c match {
case Inl(h) => f(h, i, w)
case Inr(t) => tif(i, w)(t)
}
}
implicit def iif[T <: Coproduct: IntFolder]: IntFolder[Int :+: T] =
instance((h, i, w) => h + i + w.length)
implicit def sif[T <: Coproduct: IntFolder]: IntFolder[String :+: T] =
instance((h, i, w) => h.length + i + w.length)
implicit def pif[T <: Coproduct: IntFolder]: IntFolder[(String, Int) :+: T] =
instance((h, i, w) => h._1.length + i + w.length)
}
And then you could write a more generic version of your run:
def run[C <: Coproduct](
someList: List[C],
someInt: Int,
someWord: String
)(implicit cif: IntFolder[C]): List[Int] = someList.map(cif(someInt, someWord))
And use it like this:
scala> run(List(Coproduct[SomeType](1)), 10, "foo")
res0: List[Int] = List(14)
scala> run(List(Coproduct[SomeType](("bar", 1))), 10, "foo")
res1: List[Int] = List(16)
The specificity of the operation makes this approach look a little weird, but if I really needed to do something like this for different coproducts, this is probably the solution I'd choose.
class P(name: String)
class E(_name: String, role: String) extends P(_name)
def testF[T <: P](x: List[T]): List[T] = x
val le = List(new E("Henry", "Boss"))
class Test[R <: E](l: List[R]) {
def r[O <: P] (): List[O] = testF(l)
}
I get:
Error:(8, 38) type mismatch;
found : List[R]
required: List[O]
def r[O <: P] (): List[O] = testF(l)
My intuition suggests that this should have worked because T has a tighter upper type bound than O.
**** EDIT ****
def findNN[A, B <: A, C <: A, T] (seq: Seq[B], n: Int, center: C, distance: (A, A) => T)
(implicit ord: Ordering[T]): Seq[B] = {
import ord._
val ds = seq map ( (a: A) => distance(a, center))
val uds = ds.distinct
//#TODO: replace quickSelect with median-of algorithm if necessary
val kel = quickSelect(uds, n)
val z = seq zip ds
val (left, _) = z partition Function.tupled((_, d: T) => d <= kel)
left map {t => t._1}
}
OK, let's have a look at the example above.
The superclass A provides the method distance.
I would like to use the function findNN on a seq[B] having a center in a class C. distance should work because it works on A
Based on feedback provided, there's no way to simplify the type signatures above.
You made misprinting, you need >: rather then :<
class P(name: String)
class E(_name: String, role: String) extends P(_name)
def testF[T >: P](): List[T] = List(new P("Henry"))
You are trying to limit the type of the result using a type parameter R (with an upper bound type E), while you are not using the type R in your function.
An example of a correct use of a type parameter (with an upper bound):
def testF[T <: P](list: List[T]): List[T] = list
testF(List(new P("Tom")))
// List[P] = List(P#43bc21f0)
testF(List(new E("Jerry", "Mouse")))
// List[E] = List(E#341c1e65)
An incorrect use of a type parameter:
// does not compile, what is A ??
def foo[A]: List[A] = List("bar")
The following Scala code works:
object ReducerTestMain extends App {
type MapOutput = KeyVal[String, Int]
def mapFun(s:String): MapOutput = KeyVal(s, 1)
val red = new ReducerComponent[String, Int]((a: Int, b: Int) => a + b)
val data = List[String]("a", "b", "c", "b", "c", "b")
data foreach {s => red(mapFun(s))}
println(red.mem)
// OUTPUT: Map(a -> 1, b -> 3, c -> 2)
}
class ReducerComponent[K, V](f: (V, V) => V) {
var mem = Map[K, V]()
def apply(kv: KeyVal[K, V]) = {
val KeyVal(k, v) = kv
mem += (k -> (if (mem contains k) f(mem(k), v) else v))
}
}
case class KeyVal[K, V](key: K, value:V)
My problem is I would like to instantiate ReducerComponent like this:
val red = new ReducerComponent[MapOutput, Int]((a: Int, b: Int) => a + b)
or even better:
val red = new ReducerComponent[MapOutput](_ + _)
That means a lot of things:
I would like to type-check that MapOutput is of the type KeyVal[K, C],
I want to type-check that C is the same type used in f,
I also need to "extract" K in order to instantiate mem, and type-check parameters from apply.
Is it a lot to ask? :) I wanted to write something like
class ReducerComponent[KeyVal[K,V]](f: (V, V) => V) {...}
By the time I will instantiate ReducerComponent all I have is f and MapOutput, so inferring V is OK. But then I only have KeyVal[K,V] as a type parameter from a class, which can be different from KeyVal[_,_].
I know what I'm asking is probably crazy if you understand how type inference works, but I don't! And I don't even know what would be a good way to proceed --- apart from making explicit type declarations all the way up in my high-level code. Should I just change all the architecture?
Just write a simple factory:
case class RC[M <: KeyVal[_, _]](){
def apply[K,V](f: (V,V) => V)(implicit ev: KeyVal[K,V] =:= M) = new ReducerComponent[K,V](f)
}
def plus(x: Double, y: Double) = x + y
scala> RC[KeyVal[Int, Double]].apply(plus)
res12: ReducerComponent[Int,Double] = ReducerComponent#7229d116
scala> RC[KeyVal[Int, Double]]()(plus)
res16: ReducerComponent[Int,Double] = ReducerComponent#389f65fe
As you can see, ReducerComponent has appropriate type. Implicit evidence is used here to catch K and V from your M <: KeyVal[_, _].
P.S. The version above requires to specify parameter types explicitly for your f, like (_: Double) + (_: Double). If you want to avoid this:
case class RC[M <: KeyVal[_, _]](){
def factory[K,V](implicit ev: KeyVal[K,V] =:= M) = new {
def apply(f: (V,V) => V) = new ReducerComponent[K,V](f)
}
}
scala> RC[KeyVal[Int, Double]].factory.apply(_ + _)
res5: ReducerComponent[Int,Double] = ReducerComponent#3dc04400
scala> val f = RC[KeyVal[Int, Double]].factory
f: AnyRef{def apply(f: (Double, Double) => Double): ReducerComponent[Int,Double]} = RC$$anon$1#19388ff6
scala> f(_ + _)
res13: ReducerComponent[Int,Double] = ReducerComponent#24d8ae83
Update. If you want to generelize keyval - use type function:
type KV[K,V] = KeyVal[K,V] //may be anything, may implement `type KV[K,V]` from some supertrait
case class RC[M <: KV[_, _]](){
def factory[K,V](implicit ev: KV[K,V] =:= M) = new {
def apply(f: (V,V) => V) = new ReducerComponent[K,V](f)
}
}
But keep in mind that apply from your question still takes KeyVal[K,V].
You can also pass KV into some class:
class Builder[KV[_,_]] {
case class RC[M <: KV[_, _]](){
def factory[K,V](implicit ev: KV[K,V] =:= M) = new {
def apply(f: (V,V) => V) = new ReducerComponent[K,V](f)
}
}
}
scala> val b = new Builder[KeyVal]
scala> val f = b.RC[KeyVal[Int, Double]].factory
scala> f(_ + _)
res2: ReducerComponent[Int,Double] = ReducerComponent#54d9c993
You will need path-dependent types for this. I recommend the following:
First, write a trait that has your relevant types as members, so you can access them within definitions:
trait KeyValAux {
type K
type V
type KV = KeyVal[K, V]
}
Now you can create a factory for ReducerComponent:
object ReducerComponent {
def apply[T <: KeyValAux](f: (T#V, T#V) => T#V) =
new ReducerComponent[T#K, T#V](f)
}
Note that here, we can simply access the members of the type. We can't do this for type parameters.
Now, define your MapOutput in terms of KeyValAux (maybe another name is more appropriate for your use case):
type MapOutput = KeyValAux { type K = String; type V = Int }
def mapFun(s:String): MapOutput#KV = KeyVal(s, 1)
val red = ReducerComponent[MapOutput](_ + _)
UPDATE
As #dk14 mentions in the comments, if you still want the type-parameter syntax, you could do the following:
trait OutputSpec[KK, VV] extends KeyValAux {
type K = KK
type V = VV
}
You can then write:
type MapOutput = OutputSpec[String, Int]
Alternatively, you can write OutputSpec as a type function:
type OutputSpec[KK, VV] = KeyValAux { type K = KK; type V = VV }
This will not generate an additional unused class.