views:

609

answers:

6

Let's say I want to make a special case for a function that matches strings that start with the character 'Z'. I could easily do it using pattern matching by doing something like the following:

myfunc ('Z' : restOfString) = -- do something special
myfunc s = -- do the default case here

But what if I want to match strings with a longer prefix? Say I want to have a special case for strings that start with the word "toaster". What's the best way to write a pattern to match such a string?

+1  A: 
myfunc ('t' : 'o' : 'a' : 's' : 't' : 'e' : 'r' : restOfString)

As far as I am aware, there is no more succinct syntax than that.

You can of course also just check whether the string starts with toaster in a guard-clause or an if inside the function body.

sepp2k
+8  A: 
myfunc ('t':'o':'a':'s':'t':'e':'r' : restOfString) = ...

Using a normal pattern match works, but gets bothersome as the prefix string gets longer.

{-# LANGUAGE PatternGuards #-}
import Data.List
myFunc string | Just restOfString <- stripPrefix "toaster" string =
    -- do something special
myFunc string = -- do the default case here

Using a library function instead of a pattern match is a bit easier to read and write.

{-# LANGUAGE ViewPatterns #-}
import Data.List
myFunc (stripPrefix "toaster" -> Just restOfString) = -- do something special
myFunc string = -- do the default case here

A GHC 6.10 syntax extension makes this usage even more natural.


Of course, the latter two are completely equivalent, and we can make do (messily) without any sugar at all.

import Data.List
myFunc string =
    if restIsJust
      then -- do something special
      else -- do the default case here
  where
    (restIsJust, restOfString) =
        case stripPrefix "toaster" string of
            Just something -> (True, something)
            Nothing -> (False, undefined)

Those syntax extensions are meant to make life easier for us, though.

ephemient
+5  A: 
import Data.List

myFunc str | "toaster" `isPrefixOf` str = something restOfString
           | otherwise = somethingElse
    where Just restOfString = stripPrefix "toaster" str
newacct
I was thinking of something like this first, but it seems silly to have to write `"toaster"` twice.
ephemient
+3  A: 

The Split library, http://hackage.haskell.org/packages/archive/split/0.1.1/doc/html/Data-List-Split.html has many functions for splitting strings with strings, including prefix matching. You might find something useful there.

Don Stewart
A: 

Offhand it looks pretty straightforward to write and invoke Template Haskell to achieve the desired effect. I'm not enough of a TH person to be sure, though.

Bart Massey
Unfortunately, GHC does not implement pattern splices (as far as I know, apparently it's really hard), so this isn't possible.
ephemient
A: 
myFunc str =
  case stripPrefix "toaster" str of
     Just restOfString -> something restOfString
     Nothing -> somethingElse

This is why stripPrefix returns a Maybe type.

PO8