Error when combining "skip" with other patterns

74 Views Asked by At

I want to create a turtle pattern that is the equivalent of a "lookbefore" in Regex. From the docs, it looks like this can work, using the skip pattern e.g like this:

match (skip "key:" <> chars) "key:value" -- "value"

But I get a type error

<interactive>:34:24: error:
    • Couldn't match type ‘Text’ with ‘()’
      Expected: Pattern ()
        Actual: Pattern Text
    • In the second argument of ‘(<>)’, namely ‘chars’
      In the first argument of ‘match’, namely ‘(skip "key: " <> chars)’
      In the expression: match (skip "key: " <> chars) "key:value"

How can I make this work, and if not, is there another way to achieve the desired behavior?

2

There are 2 best solutions below

2
On

You can do this by first running the skip parser, and then return the value for chars, so:

match (skip "key: " *> chars) "key:value"
0
On

<> is the wrong combining operator to use for this case.

skip "key: " is a Pattern (). chars is a Pattern Text.

<> comes from the Semigroup class, where we can see that <> has type a -> a -> a (for some type a with a Semigroup instance, which Pattern has); it combines two things of the same type. So specialised to turtle's Pattern type, the <> operator is Pattern a -> Pattern a -> Pattern a1. You could use it to combine two Pattern () values (to get a Pattern ()), or you could use it to combine two Pattern Text values (to get a Pattern Text). It doesn't know how to combine two different Pattern types.

Thinking about it more intuitively (rather than looking at the types), <> combines two patterns into one larger pattern by combining their matched results (also by using the <> operator). But here you don't want to combine the results of your patterns, you want to ignore the result of the skip "key: " pattern and have the result of the combined pattern just be the result of the chars pattern. So we come to the same conclusion: <> isn't an operator that does what you want.

Willem's answer suggested the *> operator. That comes from Applicative, and has type f a -> f b -> f b (for some type constructor f with an Applicative instance, which Pattern has). Specialised to Pattern this is Pattern a -> Pattern b -> Pattern b; it combines two patterns but the result type a from the first pattern doesn't appear in the final resulting type Pattern b. Specialised to the types of your two patterns, it would end up being Pattern () -> Pattern Text -> Pattern Text, which is what you need.


1 Provided whatever type is chosen for a is also a Semigroup.