I want the last value in list of SML.
for example, 1::2::3 => 3
I tried use "last", but it didn't work.
I tried to implement it, like this:
val rec last =
fn (h::list) => last (list)
| (h::nil) => h
| (nil) => nil;
But it gives me problem: match redundant.
Thank you for your help.
I doubt that the case of (h::nil) is redundant because it is a special case of (h::list). I think you should reorder your match cases:
exception Empty
val rec last =
fn (h::nil) => h
|(h::list) => last (list)
| (nil) => raise Empty;
By the way, List.last should work because it's a part of SML Basis Library.
Could also be done as easy as that:
exception Empty
fun lastinList [] = raise Empty
| lastinList l = hd(rev(l));
Related
SML is a challenging language for me to learn. I'm trying to find a way to screen an undetermined list and return a boolean based on whether two elements adjacent on a list are the same value or not. What I've tried and think is close to correct is below.
fun repeatE nil = false
| repeatE (first::last) = first = last orelse repeatsE(last);
Obviously, this results in an error. I based my answer on this code, which tells me if a value is an element in the list.
fun member (e, nil) = false
| member (e, first::last) = e = first orelse member(e, last);
Why does the first one not work, but the last one does? It tells me that the operator and the operand don't agree, and maybe I'm thick-headed, but I don't quite understand why they don't?
Thank you in advance!
first=last tries to compare the first element of a list with the tail of that list, and you can only compare things of the same (comparable) type.
The working code works because it doesn't try to compare a list element to an entire list.
You need to compare the first element to the second element, and you need to handle the case of a singleton list.
Something like this:
fun repeats nil = false
| repeats (first::rest) = case rest of
(x::xs) => first = x orelse repeats rest
| _ => false
or
fun repeats nil = false
| repeats (first::rest) = not (null rest)
andalso (first = (hd rest) orelse repeats rest)
It's actually possible to use as to clean up #molbdnilo's answer a fair bit.
Ask yourself: An empty list is false, but so is a list with a single element, right?
fun repeats([]) = false
| repeats([_]) = false
Now, we need to match a list with at least two elements, and compare those. If they're not equal, we'll check everything but the first element.
fun repeats([]) = false
| repeats([_]) = false
| repeats(a::b::tail) =
a = b orelse repeats(b::tail)
But we don't need to use b::tail.
fun repeats([]) = false
| repeats([_]) = false
| repeats(a::(tail as b::_)) =
a = b orelse repeats(tail)
If we want, we can recognize that the empty list and the single element list are just the "other" when the last pattern doesn't match, and we'll rewrite it to reflect that.
fun repeats(a::(tail as b::_)) =
a = b orelse repeats(tail)
| repeats(_) = false
Consider the following example of a list in SML: [[("foo",~10.0)],[("goo",~8.0)]].
I would link to write a function which will delete the main brackets meaning the output will be:
[("foo", ~10.0), ("goo, ~8.0)]
The function I wrote:
fun inner_list [[]] = [] | inner_list [] = []
| inner_list ((((x:(string*real))::xt)::xs)) = x :: inner_list xs;
It works for most cases but I know that I didn't check one of the cases. I think this case is:
[[],("foo", ~10.0)]
I know that I didn't handle one of the cases because the compiler alerts:
stdIn:1.6-2.68 Warning: match nonexhaustive
nil :: nil => ...
nil => ...
(x :: xt) :: xs => ...
I read other articles related with the Warning: match nonexhaustive warning, but I didn't understand how to solve it with my program.
How to handle the other case?
EDIT I know that my list contains only one list. this is why I don't use xt
How about the built-in List.concat?
List.concat [[("foo",~10.0)], [("goo",~8.0)]] =
[("foo",~10.0), ("goo",~8.0)]
I have questions regarding pattern matching of list prefixes (i.e. the first couple of elements of a list).
This compiles, but it does not work as expected:
val l = List(1,2,3)
val test = { m: List[Int] =>
m match {
case l :: tail => println("tail: "+tail.mkString(","))
case _ => println("no match")
}
}
test(List(1,2,3,4,5))
Output is tail: 2,3,4,5. I'd expect it to say either tail: 4,5, or to fail to match, or to fail at compile time. What makes this work as it does?
My second question is: How can I match a list prefix using a list? I know that this works as I expect:
case 1 :: 2 :: 3 :: tail => println("tail: "+tail.mkString(","))
I have, however, my prefixes as lists, and cannot hard-code them. Is pattern matching even the right thing here?
I know I could do something like
if (m startsWith l) {
val tail = m drop l.size
}
But a long list of these seems rather inelegant, especially in Scala.
Regarding the output of your first code snippet, the l inside of the match is actually a new value that shadows the outer scoped l and captures 1 during execution.
The problem you are encountering is that :: is the unapply for List to break it into exactly a single head value and the tail, deconstructing the linked list.
While there is a ::: operation to go along with ::: to concatenate two lists, it does not have a corresponding unapply which would let you use it in a pattern match in the way you desire.
I don't think this is possible. Closest syntax i could propose based on this workaround:
import collection.SeqLike
implicit class PrefixMatcher[T](prefix: Seq[T]) {
object then {
def unapply[S <: SeqLike[T,S]](seq: S): Option[S] =
if (seq startsWith prefix) Some(seq drop prefix.length) else None
}
}
Then you could use it as
val test: List[Int] => Unit = {
case l.then(tail) => println("tail: " + tail.mkString(","))
case _ => println("no match")
}
Addresing the first part of your question: As #Arne mentions, case l is not being matched against your list, but captures a new list. For the former you'd need to enclose it on backticks, but even then I don't see how you can achieve what you want, the closes I can think of is:
case `l` :+ x => println(s"tail is $s") //but this just works when the tail is just one element long.
For the final part of your question, maybe pattern matching is not the right thing to do here, how about:
val prefixes = List (List (1,2,3), List(4,5,6)...)
def findTail(li:List[Int]) = prefixes.collectFirst{ case p if li.startsWith(p) => li.drop(p.size) } //Option[List[Int]]
This will find the tail for the first prefix that matches the testList or None if there was no match.You can easily generalize it to work with more than just Ints.
I have a problem here from 99 scala problems (http://aperiodic.net/phil/scala/s-99/p03.scala) that I am trying to figure out how it works. I'm fairly new to Scala. I was able to complete this challenge with a similar solution using pattern matching and recursion however mine did not consider the list in the matching. My code is below:
def nth[A](k: Int, l: List[A]): A = k match {
case 0 => l.head
case _ => nth(k-1, l.drop(1))
}
and this seemed to do the job. However, there's no error checking if the list is Nil. The solution 99 scala problems provides is:
def nthRecursive[A](n: Int, ls: List[A]): A = (n, ls) match {
case (0, h :: _ ) => h
case (n, _ :: tail) => nthRecursive(n - 1, tail)
case (_, Nil ) => throw new NoSuchElementException
}
What I dont understand is
case(0, h:: _ )
and
case(n, _ :: tail)
What is the author doing here? I understand :: appends whatever is on the left to the beginning of whats on the right but I'm not sure exactly what is happening. Can anyone enlighten me?
Thank you!
The :: operator is used to extract the head and the rest of the list (the tail).
Here:
case(0, h :: _ )
only the head is relevant so the tail doesn't get a reference.
And Here:
case(n, _ :: tail)
only the tail is relevant so the head doesn't get a reference.
You can also use:
case(0, head :: tail)
case(n, head :: tail)
(i.e. giving both parts a reference) and get exactly the same result.
Basically, it is pattern matching expression. That is why Scala pattern matching is so powerful, so we can drop some heavy visitor pattern like Java (out of this topic).
A simple example:
case class User(name: String, age: Int)
def doStuff(user: User) = user match {
case User(_, age) if age > 100 => println("Impossible!")
case User(name, _) => println("hello " + name)
}
In this case, _ :: tail just means I want to get the reference of the tail.
I'm a little confused regarding pattern matching on a list in Scala.
For example.
val simplelist: List[Char] = List('a', 'b', 'c', 'd')
//> simplelist : List[Char] = List(a, b, c, d)
def simple_fun(list: List[Char]) = list match {
case (x:Char) :: (y:List[Char]) => println(x)
case _ => Nil
}
//> simple_fun: (list: List[Char])Any
simple_fun(simplelist)
//> a
//| res0: Any = ()
This currently prints only one line of output. Should it not run/pattern match on each element of the List ?
EDIT: I fixed the compile errors and copied the output from the REPL.
Unless you are repeatedly calling simple_fun in some way, what you have there will pattern match the first element and nothing more. To get it to match the whole list, you can get simple_fun to call itself recursively, like this:
val simplelist: List[Char] = List('a', 'b', 'c', 'd')
def simple_fun(list: List[Char]): List[Nothing] = list match {
case x :: xs => {
println(x)
simple_fun(xs)
}
case _ => Nil
}
Note I've also left out some of the types as the Scala compiler can infer them, leaving you with less cluttered, more readable code.
As a small side-note, calling println repeatedly inside the function like that is not particularly functional - as it is all about side effects. A more idiomatic approach would be to have the function construct a string describing the list, which is then output with a single call to println - so the side-effects are kept in a single well-defined place. Something like this would be one approach:
def simple_fun(list: List[Char]):String = list match {
case x :: xs => x.toString + simple_fun(xs)
case Nil => ""
}
println(simple_fun(simple_list))
I would also like to mention that the case for lists can be divided not only the head and tail, as well as any N number of list elements:
def anyFunction(list: List[Int]): Unit =
list match {
// ...methods that have already been shown
case first :: second :: Nil => println(s"List has only 2 elements: $first and $second")
case first :: second :: tail => println(s"First: $first \nSecond: $second \nTail: $tail")
}
Hope it will be useful to someone.
I think the following should work:
def flatten(l: List[_]): List[Any] = l match {
case Nil => Nil
case (head: List[_]) :: tail => flatten(head) ::: flatten(tail)
case head :: tail => head :: flatten(tail)
}
The first line is a match for Nil, so if we don't find anything return nothing.
The second line will identify List of Lists and recall the flatten method and flatten the list of lists.