I have created MyList abstract class to implement the list, the reason for not using already present list implementation is I am learning Scala and this was exercise for the same course. I am writing a zipWith function to create a new list with concatenation of individual items for example:
list 1: list = [1,2,3]
list 2: listOfStrings = ["Hello", "This is", "Scala"]
and I am expecting output like: [1-Hello, 2-This is, 3-Scala]
I wrote zipWith function as mentioned below:
override def zipWith[B, C](list: MyList[B], zip: (A, B) => C): MyList[C] = {
if(list.isEmpty) throw new RuntimeException("Lists do not have the same length")
else new Cons(zip(h, list.head), t.zipWith(list.tail, zip))
}
And I am trying to call this function using this statement:
println(list.zipWith[String, String](listOfStrings, (Int,String)=>_+"-"+_))
But I am getting an error:
I could not infer the type of the parameter $3 of expanded function:
($3, _$4) => _$3 + "-" + _$4.
Type for this variable is clearly mentioned as Int still I am getting this error. This could be solved using:
println(list.zipWith[String, String](listOfStrings, _+"-"+_))
I am not able to understand why earlier statement fails, even after giving the type for the required variable
The syntax (Int,String)=>_+"-"+_ doesn't mean what you think.
It represents a function taking two parameters with some name but unknown type: (Int: ???, String: ???) => _+"-"+_.
Thus the compiler is raising an error because it indeed have no clue about the types.
You should either:
write it with explicit variable names: (i: Int, s: String) => s"$i-$s". (Notice the usage of interpolation which is recommended over adding int and string),
or declare the function separately like this: val f: (Int, String) => String = _+"-"+_.
I think the compiler is confused on which variable to match each underscore. This explicit expression works for me:
println(list.zipWith[String, String](listOfStrings, (a:Int, b:String) => a+"-"+b))
Related
I have a function unlist taking as first argument a list of any type:
def unlist(xs: List[Any], ys: List[Any]): List[Any] = ...
and I call this function on the first element of an external list, which may or may not be a list of lists. Thus, I first need to check if this head element is itself a list, in which case I can call my unlist function.
I do it with InsintanceOf method, like so:
...
if (xs.head.isInstanceOf[List[Any]]) unlist(xs.head, ys)
However, this does not compile because of a type mismatch on xs.head:
Error: type mismatch;
found : Any
required: List[Any]
What am I doing wrong?
P.S.: since many of you have suggested to avoid type Any , I have to specify that this is part of a coding exercise aiming at having a function as general as possible
To illustrate Mateusz's comment
isInstanceOf is not being remembered
it is meant we would have to follow up with asInstanceOf like so
if (list.head.isInstanceOf[List[_]]) unlist(list.head.asInstanceOf[List[_]])
Pattern matching, as demonstrated by Tim, implicitly performs isInstanceOf/asInstanceOf combination. Also consider related answer.
If you are unable to refactor out Any, which is the weakest of types, maybe try to recover as much typing information as early as possible, perhaps like so
val lists: List[List[_]] = list.collect { case xs: List[_] => xs }
val ints: List[Int] = list.collect { case i: Int => i }
val strings: List[String] = list.collect { case s: String => s }
Note due to type erasure we cannot easily do much better than List[List[_]], for example, the following assertion passes
val list: List[Any] = List(List("woo", "hoo"), 42, "kerfuffle")
assert(list.head.isInstanceOf[List[Double]])
In this last case, a compiler warning will tell you that type argument Double in type List[Double] (the underlying of List[Double]) is unchecked since it is eliminated by erasure. It is usually not a good idea to ignore such warnings.
As mentioned in the comments, using Any like this is the sign of some bad design choices. But for the specific problem you have, you can change your if to a match like this:
def unlist(xs: List[Any], ys: List[Any]): List[Any] = ???
val xs: List[Any] = ???
xs.head match {
case l: List[Any] => unlist(l, ???)
case _ =>
}
The match checks that the head value is List[Any] then assigns the value to a variable l which has type List[Any] and can therefore be used in the unlist call.
Note: This only works because you are testing for List[Any]. You cannot test for a list of a specific type (e.g. List[Int]) because a process called type erasure removes the runtime information that would be required for this to work. The compiler will warn you when it can't implement a match for this reason.
The real solution to this question is to fix the design to use specific types rather than Any.
I just tried to write the simplest maybe function I could imagine in Haskell, and got this error message. And magically it only appears, when I try to evaluate myHead for an empty list. What did I do wrong?
module Main
where
myHead :: [a] -> Maybe a
myHead [] = Nothing
myHead (x:_) = Just x
main = do
print (myHead [])
When I run it from a file, I get this output :
main.hs:15:1: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
... plus 22 others
...plus 12 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of a 'do' block: print (myHead [])
In the expression: do { print (myHead []) }
In an equation for ‘main’: main = do { print (myHead []) }
<interactive>:3:1: error:
• Variable not in scope: main
• Perhaps you meant ‘min’ (imported from Prelude)
There's nothing wrong with myHead, you would have the same issue if you used:
main = do
print Nothing
The issue here is that Nothing and myHead [] have a polymorphic type Maybe a, for any a. Then, print is called to write that value. For that, print has to require that Maybe a is convertible to string: it does that by requiring Show (Maybe a), which in turn it requires Show a.
However, there is no universal instance of Show a: the compiler now needs to know what a is before it can convert that to string.
Note this
print (Just 3 :: Maybe Int) -- OK
print (Just id :: Maybe (Int->Int)) -- Not OK! Functions can not be printed
The solution is to use a concrete type for your code
main = do
print (myHead [] :: Maybe Int) -- or any other showable type
Datatype events = enter of string * real | exit of string *real;
So i have this Datatype and i have to write a function that takes a list of events as input and return that list sorted by the real part of events.
I tried to write some functions but didnt come up with anything good, any ideas?
this is the code i tried:
val rec ordina = fn
[] => []
|v1::v2::l => if (#2(v2)) > (#2(v1))
then ordina (v1::l)
else oridna (v2::1);
Errors i got:
poly: error: Can't find a fixed record type. Found near #2
poly: error: Can't find a fixed record type. Found near #2
Some feedback,
The datatype declaration should probably be
datatype event = Enter of string * real
| Exit of string * real
A single value contains a single event.
The plural is achieved by having a value of e.g. type event list.
Value constructors are usually written with an uppercase start letter.
In SML/NJ you have a generic sort function called ListMergeSort.sort. It takes a function with the type 'a * 'a -> bool where 'a = event in this case. You could then write a function,
fun cmp_event (event_a, event_b) = ...
that returns whether event_a should be ordered before event_b based on their real parts. Hint: First, make a helper function that extracts the real part. (Come up with a better name that reflects the purpose of the real part.)
fun get_real_part (Enter (_, r)) = ...
| get_real_part ... = ...
If you're not allowed to use ListMergeSort.sort, then make your own sort.
I am trying to implement the following:
let list = [1;2;3;4];;
if ((List.exists 3 list) = true)
print_string "element exists in list\n"
But it is giving me the error: This expression has type int list
but an expression was expected of type 'a -> bool
I am not sure what this means.
List.exists takes a function and a list, not a value and a list. For testing whether a value is in a list, use List.mem.
Your if looks like C syntax. In OCaml you need to use then (but you don't need the parentheses).
As a side comment, if e = true then ... is the same as if e then .... If you use good names for things, the latter is usually clearer.
How to declare a function suffixsen : string list -> string list ?
After declaring types inside the parens, declare the function's return type on the outside with :return-type. At least in SMLnj. I found this through trial and error, can't find documentation for it.
fun suffixson (xs: string list ): string list =
map (fn x => x ^ "son") xs
The syntax to define a function with one argument in sml is:
fun functionName argumentName = functionBody
or
fun functionName (argumentName : argumentType) = functionBody
if you want to specify the type explicitly. So to define a function named suffixsen of type string list -> string list, you can do:
fun suffixsen (strings : string list) = someExpressionThatReturnsAStringList
Edit in response to you comment:
In order to append "son" to each string in the list, you should look at the ^ operator[1], which concatenates string, and the map function which performs an operation for each element in a list.
[1] http://www.standardml.org/Basis/string.html#SIG:STRING.^:VAL (copy and paste this link in your browser - for some reason I can't get this to be clickable)