0
votes

I just curious.

I try to do pattern matching strings in Scala with Haskell way (as list of chars)

As an example, this function that remove first "/" character in string:

import scala.language.implicitConversions

implicit def stringToChars(s: String): List[Char] = s.toCharArray.toList

implicit def charsToString(a: List[Char]): String = a.mkString

def filterFirstSlash: Function[List[Char], String] = {
  case Nil => ""
  case '/' :: Nil => ""
  case '/' :: xs => xs
  case xs => xs
}

usage:

println(filterFirstSlash("/test"))

Can I remove the leading slash using patter-matching? Is this good to do it in this way?

upd

this will remove all entries in head and tail:

def removeAllSlashes: Function[List[Char], String] = {
    case Nil => ""
    case '/' :: xs => removeAllSlashes(xs)
    case xs :+ '/' => removeAllSlashes(xs)
    case xs => xs
}

this will remove first entries only:

def removeFirstSlash: Function[List[Char], String] = {
    case Nil => ""
    case ('/' :: xs) :+ '/' => xs
    case '/' :: xs => xs
    case xs :+ '/' => xs
    case xs => xs
}

p.s. Do not take it so seriously. This is just for fun. Thanks to everyone involved in the discussion.

2
maybe you can use replaceFirst and pass regex ^\\/..Also look here stackoverflow.com/questions/21545933/… - Raj Parekh
@WiktorStribiżew I rolled it back, sorry. I maybe would agree if you added [regex] tag, because this seems like one appropriate solution in this case. But I'm against removing pattern-matching, since "Why doesn't pattern matching work here" seems to be an important part of the question. - Andrey Tyukin
I know about regex. This is not about it. My curiosity was - is it possible do in haskell way? :) - HoTicE

2 Answers

3
votes

No, that's not a good way to do it. Strings are not list of chars. On the JVM, Strings are rather immutable arrays of UTF-16 code units. They have nothing to do with linked lists. Your filterFirstSlash will always ignore the first three cases, and always return the input unchanged.

To drop the slash, you could do something like this:

"////abcd".dropWhile(_ == '/')  // returns `"abcd"`

or

"/abcd".replaceAll("^/", "")

or

((s: String) => if (s startsWith "/") s.tail else s )("/abcd")

or maybe, if you really insist on pattern-matching, then you can use precompiled regex-patterns to match the leading slash and the rest of the string:

val Rgx = "^/(.*)$".r
"/abcd" match { case Rgx(s) => s; case s => s }      // evaluates to `"abcd"`
2
votes

It is possible, technically:

def filterFirstSlash(s: String) = {
  case '/' +: xs => xs
  case xs => xs
}

Of course, isn't as efficient as the same code for a linked list, since +: copies the whole string every time, so you wouldn't want to use this to recursively pick apart strings.