Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1. Re:  Escaping special characters in text (Thomas Koster)
   2.  lens-aeson and error messages (Thomas Koster)


----------------------------------------------------------------------

Message: 1
Date: Thu, 11 Jun 2015 23:30:26 +1000
From: Thomas Koster <[email protected]>
To: [email protected],  The Haskell-Beginners Mailing List -
        Discussion of primarily beginner-level topics related to Haskell
        <[email protected]>
Subject: Re: [Haskell-beginners] Escaping special characters in text
Message-ID:
        <CAG1wH7D2=_-k3w93josctam8bzucjfsmrsacfevjzhg55rg...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8

Stefan,

On Thu, Jun 11, 2015 at 03:53:41PM +1000, Thomas Koster wrote:
> My program needs to escape and unescape "special characters" in text
> (Data.Text.Text), using my own definition of "special character"
> (isSpecial :: Char -> Bool). I am looking for a library that provides
> functions that implement or help me implement this functionality. I
> don't really care exactly how the special characters are escaped, but
> my preference is to prefix them with backslashes.

On 11 June 2015 at 16:55, Stefan H?ck <[email protected]> wrote:
> The answer to your question depends on whether your program needs
> additional functionality. If the only thing you need to do is taking
> special characters and escaping them with an escape character plus a
> substitute character, this can be done with very little code using
> functions from Data.Text:
>
>   import Data.Text (Text)
>   import qualified Data.Text as T
>
>   -- Character used for escaping
>   ec :: Char
>   ec = '$'
>
>   -- Replace a character to be escaped with its substitute
>   escapeChar :: Char -> Char
>   escapeChar = id
>
>   -- Inverse of escapeChar
>   unescapeChar :: Char -> Char
>   unescapeChar = id
>
>   -- True if given char needs to be escaped
>   isSpecial :: Char -> Bool
>   isSpecial = ('?' ==)
>
>   -- Escape chars in a given text
>   escape :: Text -> Text
>   escape = T.concatMap handleChar
>     where handleChar c | isSpecial c = T.pack [ec, escapeChar c]
>                        | otherwise   = T.singleton c
>
>   -- Unescape chars in a given text
>   unescape :: Text -> Text
>   unescape t = case T.break (ec ==) t of
>                  (a,b) | T.null b  -> a
>                        | otherwise -> let b' = T.tail b
>                                           e  = unescapeChar $ T.head b'
>                                       in T.append a $
>                                          T.cons e $ unescape (T.tail b')

Thank you for your response.

Yes, this is all I need to do. I had completed about two thirds of a
similar implementation before becoming concerned that I was spending
too much time reinventing this particular wheel and that there may be
much easier and/or shorter ways to do this using a library written by
a wheel surgeon.

The only substantial difference is that my own version uses and
returns a Data.Text.Lazy.Builder so that texts can be streamed and
spliced into larger texts without copying (I am also using Chris
Done's formatting library [1]), but only if I get it right, of course,
which is another reason why I started to look around for libraries by
Haskellers more experienced than I.

> If on the other hand you want to escape special characters with blocks of text
> (instead of single characters as in my code) you probably also need a
> second character to mark the end of an escape. Even then, the code
> should not get much more involved than the example above.

I don't need more functionality re the escaping itself; your
implementation is a valid example that provides the essence of what I
need.

[1] https://hackage.haskell.org/package/formatting

--
Thomas Koster


------------------------------

Message: 2
Date: Fri, 12 Jun 2015 14:11:21 +1000
From: Thomas Koster <[email protected]>
To: [email protected]
Subject: [Haskell-beginners] lens-aeson and error messages
Message-ID:
        <CAG1wH7APP9cVtXuSEW=olmrw-zp6d6v19pff6acjcbgxm7c...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8

Hi list,

tl;dr - I am using aeson and have an unusual JSON data structure to
parse, so I have implemented the parseJSON function using the prisms
and traversals in the lens-aeson package. Unfortunately, the only error
message I ever get from my parser is "mempty". How can my parser give
better error messages when using lens-aeson?

Consider a need to implement parseJSON for the following type.

  data Row = Row [Text] Int Text

The twist is that the values are in a JSON list, not an object.

  [["a","b","c"], 4, "a title"]

The JSON above should be decoded to the following Haskell value.

  Row ["a", "b", "c"] 4 "a title"

My first FromJSON instance was naive.

  instance FromJSON Row where
    parseJSON = withArray "Row" $ \ a ->
      case Vector.toList a of
        (x : y : z : []) ->
          Row <$> parseJSON x
              <*> parseJSON y
              <*> parseJSON z
        _ -> fail "Invalid Row."

Then I decided that pattern matching a vector like that via an
intermediate list was probably rookie stuff, so I tried lenses (this is
my first attempt at lenses, btw).

  instance FromJSON Row where
    parseJSON v =
      Row <$> (v ^. nth 0 . to parseJSON)
          <*> (v ^. nth 1 . to parseJSON)
          <*> (v ^. nth 2 . to parseJSON)

This looks like it works but now the only error message I get is
"mempty". I think this is because the lens operators are folding with
the Monoid Parser instance where mempty = fail "mempty".

Can I continue to use lenses but produce better error messages? If so,
how? The lens package haddocks baffle me.

Any suggestions to improve my use of lenses are also welcome (e.g. the
expression "to parseJSON" seems so useful that I thought it might be
named in the lens-aeson package. But it isn't, so its absence makes me
suspect that I'm using it incorrectly).

Alternative, non-lens-based suggestions for de-constructing a Vector,
pattern matching its elements, without too many intermediate lists or
tuples are also welcome.

Thanks in advance.

--
Thomas Koster


------------------------------

Subject: Digest Footer

_______________________________________________
Beginners mailing list
[email protected]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


------------------------------

End of Beginners Digest, Vol 84, Issue 20
*****************************************

Reply via email to