I'm looking for some clarification on the compiler error message The value of xyz is undefined here, so reference is not allowed., together with the do-notation. I did not manage to generalize the example enough, all I can give is the concrete example where I stumbled upon this behaviour. Sorry for that.
Using purescript-parsing, I want to write a parser which accepts nested multiline-comments. To simplify the example, each comment starts with (, ends with ) and can contain either an a, or another comment. Some examples: (a) and ((a)) accepted, (), (a or foo get rejected.
The following code results in the error The value of comment is undefined here, so reference is not allowed. on the line content <- string "a" <|> comment:
comment :: Parser String String
comment = do
open <- string "("
content <- commentContent
close <- string ")"
return $ open ++ content ++ close
commentContent :: Parser String String
commentContent = do
content <- string "a" <|> comment
return content
I can get rid of the error by inserting a line above content <- string "a" <|> comment which as far as I understand it does not change the resulting parser at all:
commentContent :: Parser String String
commentContent = do
optional (fail "")
content <- string "a" <|> comment
return content
The questions are:
What is happening here? Why does the extra line help?
What is a non-hacky way to get the code to compile?
The reason the second case works becomes more apparent if you desugar the do manually:
commentContent :: Parser String String
commentContent =
optional (fail "") >>= \_ ->
string "a" <|> comment >>= \content ->
return content
When defined this way, the comment reference is inside a lambda, so therefore is not evaluated during the definition of commentContent.
As for the non-hacky solution, it would involve some use of fix I imagine. fix allows you to define recursive parsers like:
myParser = fix \p -> do
... parser definition ....
Where p is a reference to myParser that you can use within itself. As for the case here where you have mutually recursive parsers, I'm not exactly sure how best to solve it with fix, there are a few options I can think of, but none are particularly elegant. Perhaps something like this:
parens :: Parser String String -> Parser String String
parens p = do
open <- string "("
content <- p
close <- string ")"
return $ open ++ content ++ close
comment :: Parser String String
comment = parens commentContent
commentContent :: Parser String String
commentContent = fix \p -> do
content <- string "a" <|> parens p
return content
It might be easier to use a trick similar to the strange do case and insert a Unit -> in front of one of the parsers, so you can delay the recursive reference until the Unit value is provided, something like:
comment :: Parser String String
comment = do
open <- string "("
content <- commentContent unit
close <- string ")"
return $ open ++ content ++ close
commentContent :: Unit -> Parser String String
commentContent _ = do
content <- string "a" <|> comment
return content
Related
I am using the .editorconfig file in order to configure my IntellijIDEA IDE to reformat Scala code in a specific way.
I specified a right margin, and specified for it not to be exceeded, however, this has a bad impact on long lines that have an Infix expression, which breaks the code.
Everything else is reformatted correctly.
Specific editorconfig configuration :
max_line_length = 100
ij_scala_call_parameters_wrap = normal
ij_scala_method_call_chain_wrap = normal
ij_scala_variable_annotation_wrap = normal
ij_scala_wrap_long_lines = true
The line i am trying to reformat :
override val fooBarJognDoeLongVar: List[fooBarJognDoeLongVarType] = DoThisDoThat() :: DoThisDoThatAgain() :: DoThisDoThatAgainOneMoreTime() :: DoThisDoThatAgainOneMoreTimeOnceAgain() :: Nil
When it's reformatted, it looks like this :
override val fooBarJognDoeLongVar: List[fooBarJognDoeLongVarType] = DoThisDoThat() :: DoThisDoThatAgain() :: DoThisDoThatAgainOneMoreTime()
:: DoThisDoThatAgainOneMoreTimeOnceAgain() :: Nil
And that breaks the expression apparently. This line should be broken like this :
override val fooBarJognDoeLongVar: List[fooBarJognDoeLongVarType] = DoThisDoThat() :: DoThisDoThatAgain() :: DoThisDoThatAgainOneMoreTime() ::
DoThisDoThatAgainOneMoreTimeOnceAgain() :: Nil
With the :: kept on the first line, before the line return.
Any ideas on how to do this please ? Of course, using the editorconfig file.
I have a String and a Seq like :
Array[String] = Array(a, the, an)
String = "This is a sentence that includes articles a, an and the"
I want to replace each element of the Seq within the String with ""
Currently, I'm doing something like :
val a = Array("a" , "the", "an" )
var str = "This is a sentence that includes articles a, an and the"
a.foldLeft( "" ){ (x,y) => str=str.replaceAll(s"\\b${x}\\b", ""); str }
It seems to be working but doesn't look very Scala-ish mostly because of the re-assignment of the string for each iteration.
Is there any other way to do this?
This seems to be the correct variant:
a.foldLeft(str){ case (acc,item) => acc.replaceAll(s"\\b${item}\\b", "")}
It's just
a.foldLeft(str) { (x,y) => x.replaceAll(s"\\b${y}\\b", "") }
For foldLeft, x is already the intermediate result you want, no need to store it in a var.
(As a side note, your original code doesn't work correctly in general: if a is empty, it'll return "" instead of str.)
In the following DSL, I'm successfully parsing "foo", followed by 0 or more repititions of conj ~ noun.
object Foo extends JavaTokenParsers {
def word(x: String) = s"\\b$x\\b".r
lazy val expr = word("foo") ~ rep(conj ~ noun)
val noun = word("noun")
val conj = word("and") | err("not a conjunction!")
}
credit: Thanks to Travis Brown for explaining the need for the word function here.
It looks good when testing out an invalid conjunction.
scala> Foo.parseAll(Foo.expr, "foo an3 noun")
res29: Foo.ParseResult[Foo.~[String,List[Foo.~[java.io.Serializable,String]]]] =
[1.5] error: not a conjunction!
foo an3 noun
^
But, another test shows that it's not working - foo and noun should succeed.
scala> Foo.parseAll(Foo.expr, "foo and noun")
res31: Foo.ParseResult[Foo.~[String,List[Foo.~[java.io.Serializable,String]]]] =
[1.13] error: not a conjunction!
foo and noun
^
Since this passed-in String consists only of foo and noun, I'm not sure what other characters/tokens are being read.
I had replaced the above err with failure, but that's no good either:
scala> Foo.parseAll(Foo.expr, "foo a3nd noun")
res32: Foo.ParseResult[Foo.~[String,List[Foo.~[java.io.Serializable,String]]]] =
[1.5] failure: string matching regex `\z' expected but `a' found
foo a3nd noun
^
I believe that Parsers#rep explains the last failure message:
def rep[T](p: => Parser[T]): Parser[List[T]] = rep1(p) | success(List())
Based on this excellent answer, my understanding is that rep1(p) (where p is conj ~ noun) will fail, resulting in success(List()) (since failure allows back-tracking). However, I'm not entirely sure why success(List()) is not returned - the failure message says: failure: string matching regex '\z' expected but 'a'' found - it expected end of line.
Let's go step by step through what happens when foo and noun is getting parsed:
word("foo") is tried, it matches and consumes foo from input,
rep is tried,
conj is tried,
word("and") is tried, it matches and consumes and from input,
so the second branch (err) isn't even tested,
word("noun") is tried, it matches and consumes noun from input,
rep starts looping:
word("and") is tried, it doesn't match,
so err is tried, and by its very definition, it returns an error, ending the parse here.
You don't actually want err to be tested as soon as word("and") doesn't match, because it could not-match for a very good reason: that we have reached EOF.
So let's detect EOF and only try to parse conj if we have more input. Let's write a parser that does that:
def notEOF: Parser[Unit] = Parser { in =>
if (in.atEnd) Failure("EOF", in) else Success((), in)
}
And then:
val conj = notEOF ~> (word("and") | " *".r ~> err("not a conjunction!"))
On EOF, this returns a failure, so rep can stop looping and return with whatever it has. Otherwise, it tries to parse and and errs if not. Note that I use the " *".r trick to make sure err always win.
I am trying to build a simple external DSL in Scala that would be able to parse strings like:
value = "john${tom}peter${greg}${sue}meg"
In general, a substring within quotation marks contains interlaced names and names put between ${ and }.
My grammar is as following:
class Grammar extends JavaTokenParsers {
def workflow = "value" ~> "=" ~> "\"" ~> pair <~ "\""
def pair = rep(str | token)
def str = rep(char)
def char: Parser[String] = """[a-z]""".r
def token = "$" ~> "{" ~> str <~ "}"
}
and executed by:
var res = parseAll(workflow, str)
println(res)
I thought that a method def pair = rep(str | token) would make it possible to parse it properly. Not only it doesn't work but also it leads to an infinite loop within parseAll method.
How can I parse such a string then? It seems that an alternative repetition (rep) is not the right approach.
You should replace rep with rep1.
rep is always successful (unless it is an Error), so in rep(char) | token right part (token) is useless - you'll get an empty successful result of rep(char).
Also, you could either replace """[a-z]""".r with accept('a' to 'z') or define str as def str: Parser[String] = """[a-z]+""".r. Usage of Regex to match a single Char is an overkill.
I have a form in which the user can either select from a pre-existing list of values, or create a new (Text) value.
What will be the most elegant way to code that?
My best (and IMO not so elegant) way of doing so was by defining:
data MyInput = MyInput {createNew :: Bool, newVal :: Maybe Text, existingVal :: Maybe Text}
myForm :: [(Text,Text)] -> Html -> MForm MySite MySite (FormResult MyInput,Widget)
myForm exisingVals = renderTable $ MyInput
<$> areq boolField "Create new" (Just False)
<*> aopt textField "New val" Nothing
<*> aopt (selectField existingVals) "Existing values" Nothing
And once the form is received, pass the result through something like:
getMyValue :: MyInput -> Either ErrorMsg Text
getMyValue i = if createNew i
then if newVal i == Nothing || existingVal i /= Nothing
then Left "Missing new value or illegal input"
else Right . fromJust . newVal $ i
else if existingVal i == Nothing || newVal i /= Nothing
then Left "Missing selection or illegal input"
else Right . fromJust . existingVal $ i
And have the handler decide whether to re-send the form, or proceed according to the result.
Any better/shorter suggestions?
My real form has two such select/create fields, which makes the data structure and processing even more tedious.
Thanks,
You can factor out the common code, use pattern matching and guards, and generalize with a higher-order-function that accepts the accessor functions:
import Control.Arrow ((&&&))
getVal isNew newVal oldVal i | isNew i = checkVal "new value" $ (newVal &&& oldVal) i
| otherwise = checkVal "selection" $ (oldVal &&& newVal) i
where checkVal _ (Just val, Nothing) = Right val
checkVal name _ = Left $ "Missing " ++ name ++ " or illegal input"
getMyVal = getVal createNew newVal existingVal