How can I pass some HList as an argument? So I can make in a such way:
def HFunc[F, S, T](hlist: F :: S :: T :: HNil) {
// here is some code
}
HFunc(HList(1, true, "String")) // it works perfect
But if I have a long list, and I dunno nothing about it, how can I make some operations on it?
How can I pass argument and not to loose its type?
It depends on your use-case.
HList is useful for type-level code, so you should pass to your method not only HList, but also all necessary information like this:
def hFunc[L <: HList](hlist: L)(implicit h1: Helper1[L], h2: Helper2[L]) {
// here is some code
}
For instance if you want to reverse your Hlist and map over result you should use Mapper and Reverse like this:
import shapeless._, shapeless.ops.hlist.{Reverse, Mapper}
object negate extends Poly1 {
implicit def caseInt = at[Int]{i => -i}
implicit def caseBool = at[Boolean]{b => !b}
implicit def caseString = at[String]{s => "not " + s}
}
def hFunc[L <: HList, Rev <: HList](hlist: L)(
implicit rev: Reverse[L]{ type Out = Rev },
map: Mapper[negate.type, Rev]): map.Out =
map(rev(hlist)) // or hlist.reverse.map(negate)
Usage:
hFunc(HList(1, true, "String"))
//String :: Boolean :: Int :: HNil = not String :: false :: -1 :: HNil
Related
I'am writing this function for a MOOC. It's job is to remove a string from the list and return that list without the string as a SOME or return NONE is the string is not there.
I wrote the code below but whenever I try to run it I get the following error: Error: non-constructor applied to argument in pattern: -.
exception NotFound
fun all_except_option (str : string, strs : string list) =
let
fun remove_str (strs : string list) =
case strs of
[] => raise NotFound
| str'::strs' => if same_string(str, str') then strs' else str'::remove_str strs'
in
SOME (remove_str strs) handle NotFound => NONE
end
And where's one test to run it:
val test01-01 = all_except_option ("string", ["string"]) = SOME []
edit
forgot to include the same_string function that was provided to us to simplify types
fun same_string(s1 : string, s2 : string) =
s1 = s2
Figured out the problem. Seems like SML doesn't like hyphens, like the one I had in the test:
val test01-01 = all_except_option ("string", ["string"]) = SOME []
I changed to underscore instead and now it works.
val test01_01 = all_except_option ("string", ["string"]) = SOME []
Since you've already solved this task, here's a way to write it without using exceptions:
fun all_except_option (_, []) = NONE
| all_except_option (t, s :: ss) =
if s = t
then SOME ss (* don't include s in result, and don't recurse further *)
else case all_except_option (t, ss) of
SOME ss' => SOME (s :: ss')
| NONE => NONE
Having a recursive function return t option rather than t makes it more difficult to deal with, since upon every recursive call, you must inspect if it returned SOME ... or NONE. This can mean a lot of case ... of ... s!
They can be abstracted away using the library function Option.map. The definition is found in the standard library and translates into:
fun (*Option.*)map f opt =
case opt of
SOME v => SOME (f v)
| NONE => NONE
This bit resembles the case ... of ... in all_except_option; rewriting it would look like:
fun all_except_option (_, []) = NONE
| all_except_option (t, s :: ss) =
if s = t
then SOME ss (* don't include s in result, and don't recurse further *)
else Option.map (fn ss' => s :: ss') (all_except_option (t, ss))
def combinations(list: List[(Char, Int)]) : List[List[(Char,Int)]]= {
val t = List.range(0, 1)
list match {
case List() => List()
case (c,i) :: xs => val res = for {
o <- List.range(1, i + 1)
} yield List((c, o)) :: combinations(xs)
List()
}
}
I have the following function which won't compile if I try to return res instead of List(). It's a type mismatch of List(List(List[(Char,Int)]]] However this code:
List(('a',10)) :: combinations(List())
compiles perfectly and as expected. Why is it that inside the function it won't compile? Isn't it the exact same thing? How could I tackle this?
Your for-comprehension yields an element of type List[List[(Char,Int)]].
For-comprehensions will generate lists of the elements they're yielding, so in this case that will be a List[List[List[(Char,Int)]]].
I'm not entirely sure what you're trying to achieve, but I think it'll be something like this:
def combinations(list: List[(Char, Int)]) : List[List[(Char,Int)]]= {
val t = List.range(0, 1)
list match {
case Nil => List()
case (c,i) :: xs =>
(for {
o <- List.range(1, i + 1)
} yield (c, o)) :: combinations(xs)
}
}
The for-comprehension generates a List[(Char, Int)] which is added at the head of the list generated by your combinations method.
It is easy to filter HList in shapeless by type:
val hlist = 1 :: 2 :: "3" :: true :: false :: HNil
hlist.filter[Int]
But how can I make my custom type filter? I want smth like that: for example I got list of some functions:
def function1(s: String) = s.toInt
def function2(s: String) = s.toDouble
def function3(i: Int) = i.toDouble
val hflist = function1 _ :: function3 _ :: function2 _ :: HNil
hflist customFilter[String] //> function1 _ :: function2 _ :: HNil
So after usage of this filter, list of functions from type String to some other type will be constructed.
I had an idea to use map for this, but it was not successfull.
EDITION
More information about my comment:
I tried to test this ideas in map:
So if i got some lists (lets operate with hlist & hflist):
object allFunction extends Poly1 {
implicit def default[T, M] =
at[T => M](t => {
object grabStringFunc extends skip {
implicit def stringFunc[A] = at[T => A](_ :: HNil)
}
println(hflist flatMap grabStringFunc) //> here we should see result, list of functions
})
hlist map allFunction
//> result of this should be smth like (types)
//> shapeless.::[Int => Double,shapeless.HNil]]
//> shapeless.::[Int => Double,shapeless.HNil]]
//> shapeless.::[String => Int,shapeless.::[String => Double,shapeless.HNil]]
//> shapeless.HNil
//> shapeless.HNil
Very interesting, why it compiles and works incorrect? As I think it is not works, cause object cant take type prameters in such a way...
The easiest way is to use a fold. First we need a polymorphic function that will add each item to the accumulator if it has the desired type (String => A for some A), and ignore it otherwise:
trait ignore extends Poly2 {
implicit def default[A, L <: HList] = at[A, L]((_, l) => l)
}
object keepStringFunc extends ignore {
implicit def stringFunc[A, L <: HList] = at[String => A, L](_ :: _)
}
Now the following will give the result you want in both 1.2.4 and 2.0.0-M1:
val filtered = hflist.foldRight(HNil)(keepStringFunc)
You could also write your own type class on the model of Filter, FilterAux (or Filter.Aux), etc.—and doing so would be a good exercise if you're trying to get the hang of Shapeless—but foldRight is a lot simpler.
Update: actually, for what it's worth, there's a slightly more concise way to do this with flatMap:
trait skip extends Poly1 {
implicit def default[A] = at[A](_ => HNil)
}
object grabStringFunc extends skip {
implicit def stringFunc[A] = at[String => A](_ :: HNil)
}
val filtered = hflist flatMap grabStringFunc
I personally find the foldRight version a little more obvious, but this one's also pretty elegant.
In response to your comment: you can make the solution a little more generic like this:
trait skip extends Poly1 {
implicit def default[A] = at[A](_ => HNil)
}
trait grabFuncFrom[T] extends skip {
implicit def stringFunc[A] = at[T => A](_ :: HNil)
}
object grabStringFunc extends grabFuncFrom[String]
val filtered = hflist flatMap grabStringFunc
But you're still going to need that last step where you create the higher rank function as an object (see e.g. this answer and Miles's comment there for some discussion of this issue).
I'd like to reverse a list of lists, recursively, in Scala.
I've written deep list reverses in Python like this:
def deepReverse(items):
if type(items) == list:
return [deepReverse(item) for item in reversed(items)]
else:
return items
How would I do the equivalent in Scala? The problem isn't the algorithm - it's the type stuff, which I'm newer on.
I need the function to take a list of [T], or a List[List[T]], or a list of T's and lists of Ts, to any arbitrary depth. I tried making a case class to do that based on an example I'd seen elsewhere. I don't want a function that just returns Any and accepts Any; that feels like cheating.
case class NL[+T](val v : Either[List[NL[T]],T])
Still, I couldn't quite get my types to balance out. I'm new to Scala, but I figured it'd be a perfect opportunity to mess with recursion and typing.
It's actually not too hard to write a version of the type class approach that sschaef proposes that will work for arbitrarily nested lists:
trait Reverser[C] {
def reverse(xs: C): C
}
implicit def rev[A](implicit ev: Reverser[A] = null) = new Reverser[List[A]] {
def reverse(xs: List[A]) =
Option(ev).map(r => xs map r.reverse).getOrElse(xs).reverse
}
def deepReverse[A](xs: A)(implicit ev: Reverser[A]): A = ev.reverse(xs)
The implicit argument ev in our rev method is evidence that A itself is reversable, and if ev is null that means it's not. If we have this evidence that A is reversable, we use it to reverse the elements of our List[A] (this is what the map is doing), and then we reverse the list itself. If we don't have this evidence (the getOrElse case), we can just reverse the list.
We could write rev a little less concisely (but possibly more performantly) like this:
implicit def rev[A](implicit ev: Reverser[A] = null) = if (ev == null) {
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
} else {
new Reverser[List[A]] {
def reverse(xs: List[A]) = (xs map ev.reverse).reverse
}
}
To test either of these two versions, we can write the following:
scala> deepReverse(List.tabulate(3)(identity))
res0: List[Int] = List(2, 1, 0)
scala> deepReverse(List.tabulate(2,3) { case (a, b) => a + b })
res1: List[List[Int]] = List(List(3, 2, 1), List(2, 1, 0))
scala> deepReverse(List.tabulate(2, 3, 4, 5, 6) {
| case (a, b, c, d, e) => a + b + c + d + e
| }).head.head.head.head
res2: List[Int] = List(15, 14, 13, 12, 11, 10)
As expected.
I should add that the following is a more common idiom for getting the implicits right in a case like this:
trait ReverserLow {
implicit def listReverser[A] = new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
}
object ReverserHigh extends ReverserLow {
implicit def nestedListReverser[A](implicit ev: Reverser[A]) =
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.map(ev.reverse).reverse
}
}
import ReverserHigh._
If we'd just written listReverser and nestedListReverser at the same level, we'd get the following error when we try to reverse a list of lists:
scala> deepReverse(List.tabulate(2, 3)(_ + _))
<console>:12: error: ambiguous implicit values:
both method listReverser...
and method nestedListReverser...
match expected type Reverser[List[List[Int]]]
deepReverse(List.tabulate(2, 3)(_ + _))
The standard approach to prioritizing the two is to put the lower priority implicit in a trait (WhateverLow) and the other in an object (WhateverHigh) that extends that trait. In a fairly simple case like this, though, it's more concise (and clearer, to my eye) to use the default argument trick in my rev method above. But you're more likely to see the other version in other people's code.
If you wanna have this really typesafe then the typeclass pattern is your friend:
object Reverse extends App {
trait Reverser[C] {
def reverse(xs: C): C
}
implicit def List1Reverser[A] = new Reverser[List[A]] {
def reverse(xs: List[A]) =
xs.reverse
}
implicit def List2Reverser[A] = new Reverser[List[List[A]]] {
def reverse(xs: List[List[A]]) =
xs.map(_.reverse).reverse
}
implicit def List3Reverser[A] = new Reverser[List[List[List[A]]]] {
def reverse(xs: List[List[List[A]]]) =
xs.map(_.map(_.reverse).reverse).reverse
}
def deepReverse[A](xs: A)(implicit rev: Reverser[A]): A =
rev.reverse(xs)
val xs = List(1,2)
val xxs = List(List(1,2),List(1,2),List(1,2))
val xxxs = List(List(List(1,2),List(1,2)),List(List(1,2),List(1,2)),List(List(1,2),List(1,2)))
println(deepReverse(xs))
println(deepReverse(xxs))
println(deepReverse(xxxs))
}
The only problem with this is that you need a typeclass for each nested list type.
Im attempting to create a new operator :? on lists, which operates the same as :: except if the value if null, then the original list is returned. I have written the following, however it soon dawned that I didn't really know what I was doing....
object ImplicitList {
implicit def extendIterator[T](i : List[T]) = new ListExtension(i)
}
class ListExtension[T <: Any](i : List[T]) {
def :?[B >: T] (x: B): List[B] = if (x != null) x :: i else i
}
final case class :?[B](private val hd: B, private val tl: ListExtension[B]) extends ListExtension[B](tl.:?(hd))
What you want is the enhance-my-library pattern. With this you can add a new method to List. Here's how that would look:
class EnhancedList[T](self: List[T]) {
def ?:(t: T) =
t match {
case null => self
case _ => t :: self
}
}
implicit def enhanceList[T](self: List[T]) = new EnhancedList(self)
So there's a class EnhancedList that wraps List where the new method ?: is defined, and an implicit function that converts List to EnhancedList when ?: is called. Note that you have to use ?: instead of :? because Scala's rules are such that an operator is right-associative if and only if it ends in a :.
Here's how it gets used:
scala> val l = List("a","b","c")
l: List[java.lang.String] = List(a, b, c)
scala> null ?: l
res136: List[java.lang.String] = List(a, b, c)
scala> "d" ?: l
res137: List[java.lang.String] = List(d, a, b, c)