1

I have been using Text.Regex.Posix in a file, everything works fine so far. Now, I would like to use OverloadedStrings for something else but in the same file. The problem is when I activate OverloadedString all the code related to regex doesn't compile because the strings becomes ambiguous.

Is there a way to deal with this without having to add type signature to every strings or deactivate OverloadedStrings ?

mb14
  • 22,276
  • 7
  • 60
  • 102
  • 2
    You could create your own aliases for the regex functions you use that force whichever input to be `String`s, i.e. `(=~) :: RegexContext Regex String target => String -> String -> target; (=~) = (Text.Regex.Posix.=~)` – bheklilr Apr 23 '15 at 20:14
  • Done this way you can basically just override the too-polymorphic `=~` from `Text.Regex.Posix` with one that only accepts strings (but still returns any type of target), you won't have to change the code in the rest of your file if you do your imports right, and `OverloadedStrings` won't get in the way. – bheklilr Apr 23 '15 at 20:17
  • Brilliant ! I was expecting more a way to specify *real* string (a bit like `r"..."` in python. But this works really well. The only drawback is I have to add `FlexibleContexts` which is not a problem, but I don't like to have to *pull* and unnecessary extension into my own file. – mb14 Apr 23 '15 at 20:43
  • 3
    `FlexibleContexts` is such an uncontroversial extension that I wouldn't worry about it. Sure, it's annoying to have to do but you do it once and you're done. If you want the `r"..."` syntax, you could instead do `r :: String -> String; r = id`, then just `r"test"` works as you'd expect. The `r` in `r"..."` gets parsed as a function called `r` being called on a string, so you can write `r`, `u`, and `b` functions that would emulate Python's functionality. – bheklilr Apr 23 '15 at 20:53
  • Of course. Seeing it, I prefer your initial solution (overriding `=~`) but I'll keep in mind the `r".."` trick. Many thanks (can you post your solution as an answer ?) – mb14 Apr 23 '15 at 21:00

1 Answers1

3

I see two approaches here. You can do some import shuffling and just alias the functions you need to have less general types, such as

import qualified Text.Regex.Posix as P
import Text.Regex.Posix hiding ((=~))

(=~) :: RegexContext Regex String target => String -> String -> target
(=~) = (P.=~)

Then you don't have to change the code throughout your file. This can lead to confusion though, and it requires FlexibleContexts to work (not a big deal).

Alternatively you can create your own Python-like syntax for specifying the type:

r :: String -> String
r = id

u :: Text -> Text
u = id

b :: ByteString -> ByteString
b = id

example :: Bool
example = r"test" =~ r"te.t"

splitComma :: Text -> Text
splitComma = Data.Text.splitOn (u",")

But this will require you to edit more of your code. It doesn't use any extra language extensions and the code to implement it is very simple, even in comparison to the first method. It Also means that you'll have to use parentheses or $ signs more carefully, but you can also use the r, u, and b functions as, well, functions.

bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • I just realized that this technique (non-polymorphic `id`) can be used in many different context , to avoid (simplify) type signature. Is it generally used and if so does it has a name ? – mb14 Apr 23 '15 at 21:21
  • @mb14 I've used it before, and the more general form of doing something like `map (read :: String - Int) "12345"`. I don't know if this has a name, but I usually refer to it in my head as "concretification" or "concretifying", or sometimes just "specializing". – bheklilr Apr 23 '15 at 21:23
  • 1
    You could also consider turning on `PartialTypeSignatures` so that the type you give `(=~)` more clearly states the concern being addressed: `(=~) :: _ => String -> _` shouts loudly to me that we want a `String`-specific version of `(=~)` in a way that the longer type signature doesn't. And in some future version of GHC, perhaps we'll even be able to give no signature and [just write `(=~) = (P.=~) @String`](https://ghc.haskell.org/trac/ghc/wiki/TypeApplication)... – Daniel Wagner Apr 24 '15 at 01:19