Filter usage in shapeless, Scala - list

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).

Related

SML: Error: non-constructor applied to argument in pattern: -

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))

How to substitute ::: in scala

I have written a flatten function from scratch that takes a nested list as input and outputs another.
def flatten[A] (list:List[List[A]]):List[A]
I used scala's ':::' to bind the two lists and it worked fine. However, my exercise prohibits me from using that or any built in method ( exercise from a personal scala book).
Now, i have written a helper method that merges those two list called merge.
How would merge fit in a new version of the function flatten?
If you have method merge you could use foldLeft for flattening the list of lists:
list.foldLeft(List[A]())(merge)
def merge1[T](l1: List[T], l2: List[T]): List[T] =
l1.reverse.foldLeft(l2)((acc, e) => e :: acc)
/** for large lists will throws Stackoverflow */
def merge2[T](l1: List[T], l2: List[T]): List[T] =
l1.foldRight(l2)((e, acc) => e :: acc)
def flatten[A](list: List[List[A]]): List[A] =
list.foldLeft(Nil: List[A])(merge1)
If you want to add your merge method to List type, you can write:
implicit class ListExt[T](l: List[T]) {
def merge(l2: List[T]): List[T] = merge1(l, l2)
}
def flatten2[A](list: List[List[A]]): List[A] =
list.foldLeft(Nil: List[A])((acc, e) => acc merge e)

Zipping two lists into a single list of objects rather than a list of tuples?

val l1 = List(1, 2, 3)
val l2 = List('a', 'b', 'c')
val tupleList = l1.zip(l2)
// List((1,a), (2,b), (3,c))
val objectList = l1.zip(l2).map(tuple => new MyObject(tuple._1, tuple._2))
// List(MyObject#7e1a1da6, MyObject#5f7f2382, MyObject#407cf41)
After writing this code, I feel like the map(tuple => new MyObject(tuple._1, tuple._2)) part looks a little dirty for two reasons:
I shouldn't be creating the tuples just to discard them in favor of MyObject. Why not just zip l1 and l2 into a list of MyObject in the first place?
tuple._1 and tuple._2 don't have any semantics. It can take some mental gymnastics to make sure I'm giving the Int as the first parameter and the Char as the second.
Is it possible to zip two Lists into my own object?
How can I make the MyObject construction above more semantically clear?
scala> case class Foo(i: Int, c: Char)
defined class Foo
scala> val f = Foo.apply _
f: (Int, Char) => Foo = <function2>
scala> (l1, l2).zipped map f
res12: List[Foo] = List(Foo(1,a), Foo(2,b), Foo(3,c))
More info, since someone didn't get what I meant, here's what this map looks like:
https://github.com/scala/scala/blob/2.11.x/src/library/scala/runtime/Tuple2Zipped.scala#L35
If you want a self made implementation for your problem, you can do something similar to what I did below. (wasted my time with)
There is already one implemented method to do that, which is described in #som-snytt 's answer.
An example implementation for your problem, which does not create intermediate tuples.
def createObjects[A,B,C](func: (A,B) => C)(l1: List[A], l2: List[B]) = {
val resultBuffer = new ListBuffer[C]
#tailrec
def loop(l1: List[A], l2: List[B]): Unit = l1 match {
case head :: tail if l2.headOption.isDefined => {
resultBuffer += func(l1.head, l2.head)
loop(l1.tail, l2.tail)
}
case Nil =>
}
loop(l1, l2)
resultBuffer.result
}
You can then use it like this:
createObjects(MyObject)(l1, l2)
createObjects(MyObject)(l1, l2) only works if MyObject is a case class or has an apply method.
In the other case you can do one of the following:
createObjects[Int, Char, MyObject](new MyObject(_,_))(l1, l2)
createObjects((i: Int, c: Char) => new MyObject(i,c))(l1, l2)
A slightly cleaner version using pattern matching would help with #2:
val objectList = (l1 zip l2).map { case (a, b) => new MyObject(a,b) }
A more extreme version would be to use a factory method on a companion class that turned the tuple into an instance of MyClass.
object MyClass {
def make(t: (Int, Char)) = new MyClass(t._1, t._2)
}
val objs = (l1 zip l2).map(MyClass.make)
You could even get fancier by making the companion object a function to further reduce the clutter:
object MyClass extends (Tuple2[Int, Char] => MyClass) {
def apply(t: (Int, Char)) = new MyClass(t._1, t._2)
}
val objs = (l1 zip l2).map(MyClass)

Heterogeneous arguments in a Scala function

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

How should I remove the first occurrence of an object from a list in Scala?

What is the best way to remove the first occurrence of an object from a list in Scala?
Coming from Java, I'm accustomed to having a List.remove(Object o) method that removes the first occurrence of an element from a list. Now that I'm working in Scala, I would expect the method to return a new immutable List instead of mutating a given list. I might also expect the remove() method to take a predicate instead of an object. Taken together, I would expect to find a method like this:
/**
* Removes the first element of the given list that matches the given
* predicate, if any. To remove a specific object <code>x</code> from
* the list, use <code>(_ == x)</code> as the predicate.
*
* #param toRemove
* a predicate indicating which element to remove
* #return a new list with the selected object removed, or the same
* list if no objects satisfy the given predicate
*/
def removeFirst(toRemove: E => Boolean): List[E]
Of course, I can implement this method myself several different ways, but none of them jump out at me as being obviously the best. I would rather not convert my list to a Java list (or even to a Scala mutable list) and back again, although that would certainly work. I could use List.indexWhere(p: (A) ⇒ Boolean):
def removeFirst[E](list: List[E], toRemove: (E) => Boolean): List[E] = {
val i = list.indexWhere(toRemove)
if (i == -1)
list
else
list.slice(0, i) ++ list.slice(i+1, list.size)
}
However, using indices with linked lists is usually not the most efficient way to go.
I can write a more efficient method like this:
def removeFirst[T](list: List[T], toRemove: (T) => Boolean): List[T] = {
def search(toProcess: List[T], processed: List[T]): List[T] =
toProcess match {
case Nil => list
case head :: tail =>
if (toRemove(head))
processed.reverse ++ tail
else
search(tail, head :: processed)
}
search(list, Nil)
}
Still, that's not exactly succinct. It seems strange that there's not an existing method that would let me do this efficiently and succinctly. So, am I missing something, or is my last solution really as good as it gets?
You can clean up the code a bit with span.
scala> def removeFirst[T](list: List[T])(pred: (T) => Boolean): List[T] = {
| val (before, atAndAfter) = list span (x => !pred(x))
| before ::: atAndAfter.drop(1)
| }
removeFirst: [T](list: List[T])(pred: T => Boolean)List[T]
scala> removeFirst(List(1, 2, 3, 4, 3, 4)) { _ == 3 }
res1: List[Int] = List(1, 2, 4, 3, 4)
The Scala Collections API overview is a great place to learn about some of the lesser known methods.
This is a case where a little bit of mutability goes a long way:
def withoutFirst[A](xs: List[A])(p: A => Boolean) = {
var found = false
xs.filter(x => found || !p(x) || { found=true; false })
}
This is easily generalized to dropping the first n items matching the predicate. (i<1 || { i = i-1; false })
You can also write the filter yourself, though at this point you're almost certainly better off using span since this version will overflow the stack if the list is long:
def withoutFirst[A](xs: List[A])(p: A => Boolean): List[A] = xs match {
case x :: rest => if (p(x)) rest else x :: withoutFirst(rest)(p)
case _ => Nil
}
and anything else is more complicated than span without any clear benefits.