8

This works:

{-# LANGUAGE OverloadedStrings #-}
myFunc :: Text -> String
myFunc ""    = "nothing"
myFunc other = "something!"

Without the OverloadedStrings extension however, "" is of type String so it doesn't compile. Using a function like myFunc (pack "") is not allowed in patterns.

Haskell Bytestrings: How to pattern match? contains some suggestions that should work, however in this case I'm wondering if there is something special about the fact that it works with OverloadedStrings that would allow a better way?

Community
  • 1
  • 1
Xavier Shay
  • 4,067
  • 1
  • 30
  • 54
  • 2
    Why avoid `OverloadedStrings`? That is exactly one of the two purposes of that extension (the other is construction of `String`-like things with nice syntax). – David Young Sep 04 '16 at 17:40
  • I'll probably end up using it, I'm just trying to understand how everything works! – Xavier Shay Sep 04 '16 at 17:44
  • You can use guards: `myFunc s | s == pack "" = "nothing" | otherwise = "something!"`. – melpomene Sep 04 '16 at 17:44
  • My first version used guards. The actual case is more complicated though and is much clearer with patterns, so I'm trying to use them instead. – Xavier Shay Sep 04 '16 at 17:47
  • @melpomene One possible issue with that is that you might end up without a warning for incomplete patterns (as in the `f n | even n = ... | odd n = ...` case). – Bakuriu Sep 05 '16 at 20:00

2 Answers2

14

The most direct translation is with ViewPatterns

{-# LANGUAGE ViewPatterns #-}
import qualified Data.Text as Txt
myFunc (Txt.unpack->"") = "nothing"
myFunc _other = "something!"

The best translation, albeit probably too specific for your actual use case, is of course

myFunc txt | Txt.null txt  = "nothing"
           | otherwise     = "something!"

You could also go nuts and make up a pattern synonym:

{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
pattern T :: String -> Txt.Text
pattern T str <- (Txt.unpack -> str)
 where T = Txt.pack

and then

myFunc (T"") = "nothing"
myFunc _other = "something"

Arguably, OverloadedStrings is a more sane extension than ViewPatterns, and certainly saner than PatternSynonyms.

Graham
  • 7,431
  • 18
  • 59
  • 84
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • I did think of `ViewPatterns` but dismissed them because I assumed the OP wanted to have an answer w\o `LANGUAGE`-extensions. But nice explanation of `ViewPatterns` and `PatternSynonyms` nevertheless (+1) – epsilonhalbe Sep 04 '16 at 20:16
  • agree, though I learned about `PatternSynonyms` so accepting. Thanks! – Xavier Shay Sep 04 '16 at 21:08
  • Would it be more efficient to write `myFunc ((==) Txt.empty -> True) = "nothing"`? since I assume checking if two `Text`s are the same is faster than converting this to a `String` (especially for non-empty string). – Willem Van Onsem Jan 10 '20 at 17:39
  • @WillemVanOnsem hm might well be faster. Is `Txt.unpack` lazy? – leftaroundabout Jan 10 '20 at 18:22
9

The easiest way to solve this is to use either guards as @melpomene suggests or case expressions.

testfunc :: Text -> String
testfunc s | s == pack "" = "nothing"
           | otherwise    = "someting"

testfunc' :: Text -> String
testfunc' s = case unpack s of
                "" -> "nothing"
                _  -> "something"

The inner workings of LANGUAGE OverloadedStrings uses the IsString typeclass, if I remember correctly, and I guess it also relies on INLINING to make this efficient.

epsilonhalbe
  • 15,637
  • 5
  • 46
  • 74