I'm trying to create operators similar to (&&) and (||), and with the same precedence.
My code is:
let (&&.) = (&&)
let (||.) = (||)
printf $"{true ||. true &&. false} = {true || true && false}"
This prints "False = True".
As I understand it, in F# the precedence of custom operators is defined by their first characters.
Why do I get this output, and how do I fix it?
I think this is working as intended. According to this table && has a higher precedence than ||, but &&. and ||. have the same precedence (as instances of &op and |op).
To fix it, you could choose an operator with higher precedence for your custom "and" function, like this:
let (^^.) = (&&)
let (||.) = (||)
printf $"{true ||. true ^^. false} = {true || true && false}" // "true = true"
Related
I try to skip any whitespace or comment while parsing a programming language.
There are two types of comment I want to skip:
Line comment: ;; skip rest of line
Block comment: (; skip anything between ;)
Example code to parse with comments and whitespaces:
(type (; block comment ;) (func))
(import "env" "g" (global $g (mut i32)))
(func (type 0) ;; line comment
i32.const 100
global.set $g)
(export "f" (func 0))
I tried multiple approaches but the parser always breaks somewhere. My idea goes like this:
let comment : Parser<unit, Ctx> =
let lineComment = skipString ";;" >>. skipRestOfLine true
let blockComment = between (skipString "(;") (skipString ";)") (skipMany anyChar)
spaces >>. lineComment <|> blockComment
let wsOrComment = attempt comment <|> spaces
I would like the comments to be ignored completely like the spaces are. Any ideas how to accomplish that? (It's my first project with FParsec)
Based on the suggestion by Koenig Lear, I filtered all comments with an regex before running the text through the parser. This is maybe not the nicest option, but it does the job reliable with only two lines of code.
let removeComments s =
let regex = Regex(#"\(;.*;\)|;;.*")
regex.Replace(s, String.Empty)
let input = """
(type (; block comment ;) (func))
(import "env" "g" (global $g (mut i32)))
(func (type 0) ;; line comment
i32.const 100
global.set $g)
(export "f" (func 0))
"""
let filtered = removeComments input
// parse "filtered" with FParsec
I've got a hs file, trying to overload && operator
(&&)::Bool->Bool->Bool
True && x = x
False && _ = False
and' :: (Bool)->Bool
and' xs=foldr (&&) True xs
When imported in Prelude, there's error:
Ambiguous occurrence ‘&&’
It could refer to either ‘Main.&&’, defined at D:\baby.hs:2:6
or ‘Prelude.&&’,
imported from ‘Prelude’ at D:\baby.hs:1:1
(and originally defined in ‘GHC.Classes’)
So I changed the last line to be
and' xs=foldr (Main.&&) True xs
Now it prints new error message:
Couldn't match expected type ‘t0 Bool’ with actual type ‘Bool’
In the third argument of ‘foldr’, namely ‘xs’
In the expression: foldr (Main.&&) True xs
How can I resolve this issue? Thanks.
As #zakyggaps said in his comment, (Bool) is the same as Bool. You clearly mean [Bool]. Also, you aren't really "overloading" this function so much as defining a similarly named one in a different module. "Shadowing" at best, but not even that really.
There is no overloading in Haskell. Identifiers can be shared using typeclasses, but && is not a member of a typeclass and thus cannot be shared. When you define your own && operator, it conflicts with the one automatically imported in the Prelude. To use your && without qualification, you must hide Prelude.&& as follows:
import Prelude hiding ((&&))
(&&) :: Bool -> Bool -> Bool
True && b = b
False && _ = False
The second error is a mistake or typo in the type of and', which should be and' :: [Bool] -> Bool rather than and' :: (Bool) -> Bool.
I'm new to the area of grammars and parsing.
I'm trying to write a recursive descent parser that evaluates strings like this:
((3 == 5 AND 4 == 5) OR (6 == 6 ))
Everything works fine for me until I start to deal with nested parentheses. Essentially I find that I'm reaching the end of my target string too early.
I think the problem is due to the fact when I encounter a token like the "6" or the second-to-last parenthesis, I evaluate it and then move to the next token. I'd remove the code for advancing to the next token, but then I'm not sure how I move forward.
My grammar, such as it is, looks like this (the "=>" signs are my own notation for the "translation" of a rule):
Test: If CompoundSentence Then CompoundSentence | CompoundSentence
CompoundSentence : ( CompoundSentence ) PCSopt |CompoundSentence Conjunction Sentence |
Sentence =>
CompoundSentence = ( CompoundSentence ) PCSopt | Sentence CSOpt
PCSOpt = ParenConjunction CompoundSentence PCSOpt| Epsilon
CSOpt = Conjunction Sentence CSOpt| Epsilon
ParenConjunction: And|Or
Conjunction: And|Or
Sentence : Subject Verb Prefix
Subject: Subject Infix Value | Value =>
Subject = Value SubjectOpt
SubjectOpt = Infix Value SubjectOpt | Epsilon
Verb: ==|!=|>|<
Predicate: Predicate Infix Value | Value =>
Predicate= Value PredicateOpt
PredicateOpt = Infix Value PredicateOpt | Epsilon
Infix: +, -, *, /
My code for a compound sentence is as follows:
private string CompoundSentence(IEnumerator<Token> ts)
{
// CompoundSentence = ( CompoundSentence ) PCSopt | Sentence CSOpt
string sReturnValue = "";
switch(ts.Current.Category) {
case "OPENPAREN":
{
//Skip past the open parenthesis
ts.MoveNext();
string sCSValue = CompoundSentence(ts);
if(ts.Current.Category != "CLOSEPAREN") {
sReturnValue = "Missing parenthesis at " + ts.Current.OriginalString;
return sError;
}
else {
//Skip past the close parenthesis
ts.MoveNext();
}
sReturnValue = PCSOpt(sCSValue, ts);
break;
}
default:
{
string sSentenceVal = Sentence(ts);
//sSentenceVal is the truth value -- "TRUE" or "FALSE"
//of the initial Sentence component
//CSOpt will use that value, along with the particular conjunction
//and the value of the current token,
//to generate a new truth value.
sReturnValue = CSOpt(sSentenceVal, ts);
break;
}
}
return sReturnValue;
}
As I say, I'm new to this area, so I'm probably not understanding something quite fundamental.
If anyone could steer me in the right direction, I'd greatly appreciate it.
For expressions, a hand-coded recursive descent parser is a pretty easy thing to code.
See my SO answer for how to write recursive descent parsers.
Once you have the structure of the parser, it is pretty easy to evaluate an expression as-you-parse.
The basic convention to follow for parsing is:
At the start of a rule, the current token should be the first token that the rule covers.
A rule should consume all of the tokens it covers.
I thought it was incredibly subtle, but it turns out to have been quite simple: my scanner wasn't catching the second (and probably higher) close parentheses. Ouch.
Thanks everyone for your help.
Ira, I'll accept your answer for the detailed help it provides on RDP's.
Is there anyway to use inline conditions in Lua?
Such as:
print("blah: " .. (a == true ? "blah" : "nahblah"))
Sure:
print("blah: " .. (a and "blah" or "nahblah"))
If the a and t or f doesn't work for you, you can always just create a function:
function ternary ( cond , T , F )
if cond then return T else return F end
end
print("blah: " .. ternary(a == true ,"blah" ,"nahblah"))
of course, then you have the draw back that T and F are always evaluated....
to get around that you need to provide functions to your ternary function, and that can get unwieldy:
function ternary ( cond , T , F , ...)
if cond then return T(...) else return F(...) end
end
print("blah: " .. ternary(a == true ,function() return "blah" end ,function() return "nahblah" end))
You can usually do:
condition and ifTrue or ifFalse
but this isn't necessarily the best way to do it. The major reason why is because if ifTrue is a falsy value (some of the time), ifFalse will evaluate even if condition is a truthy value. One way to do it simply without much extra work is:
(condition and {ifTrue} or {ifFalse})[1]
which has the advantage of not only being an expression and not being subject to the problem of ifTrue being falsy which means it can handle all cases, but also has the advantage of short-circuiting (not evaluating the other expression). No need for extra functions or messing with complex aspects of Lua.
Although this question is fairly very old, I thought it would be fair to suggest another alternative that syntactically appears very similar to that of the ternary operator.
Add this:
function register(...)
local args = {...}
for i = 1, select('#', ...) do
debug.setmetatable(args[i], {
__call = function(condition, valueOnTrue, valueOnFalse)
if condition then
return valueOnTrue
else
return valueOnFalse
end
end
})
end
end
-- Register the required types (nil, boolean, number, string)
register(nil, true, 0, '')
And then use it like this:
print((true) (false, true)) -- Prints 'false'
print((false) (false, true)) -- Prints 'true'
print((nil) (true, false)) -- Prints 'false'
print((0) (true, false)) -- Prints 'true'
print(('') (true, false)) -- Prints 'true'
Note: For tables, however, you cannot use them directly with the above method. This is because each and every table has it's own independent metatable and Lua does not allow you to modify all tables at once.
In our case, an easy solution would be to convert the table into a boolean using the not not trick:
print((not not {}) (true, false)) -- Prints 'true'
You could just write the if statement in one line, it is no shorthand, inline or ternary operator stuff tho.
if (dummy) then
print("dummy is true")
end
is equal too
if (dummy) then print("dummy is true") end
Have fun
:D
local n = 12
do
local x = (n>15)
and print(">15")
or n>13
and print(">13")
or n>5
and print(">5")
end
In an effort to understand the capabilities of functional programming I put together a few basic functions that you can compose together to build complex regular expressions. Now after some testing I have found this works but you can write some horrible code in any language that will work. Is this the kind of code you would find a professional F# programmer writing or am I abusing the feature?
Note: test is specifically what I am referring to.
type State = { input:string; index:int; succeeded:bool }
type Matcher = State -> State
let term (cs:char Set) =
fun s ->
if s.succeeded && s.index < s.input.Length && cs.Contains s.input.[s.index] then
{ input = s.input; index = s.index + 1; succeeded = true }
else
{ input = s.input; index = s.index; succeeded = false }
let quantify (term, min, max) =
let rec inner (s:State, count) =
if s.succeeded && s.index < s.input.Length && count <= max then
inner (term { input = s.input; index = s.index + 1; succeeded = true }, count + 1)
elif count >= min && count <= max then
{ input = s.input; index = s.index - 1; succeeded = true }
else
s
fun s -> inner (s, 0)
let disjunction leftTerm rightTerm =
fun s ->
let left = leftTerm s
if not left.succeeded then
let right = rightTerm s
if not right.succeeded then
{ input = s.input; index = s.index; succeeded = false }
else
right
else
left
let matcher input terms =
let r = terms { input = input; index = 0; succeeded = true }
if r.succeeded then r.input.Substring (0, r.index) else null
let test = // (abc|xyz)a{2,3}bc
disjunction // (abc|xyz)
(term (set "a") >> term (set "b") >> term (set "c"))
(term (set "x") >> term (set "y") >> term (set "z"))
>> quantify (term (set "a"), 2, 3) // (a{2,3})
>> term (set "b") // b
>> term (set "c") // c
let main () : unit =
printfn "%s" (matcher "xyzaabc" test)
System.Console.ReadKey true |> ignore
main()
The code looks pretty good to me.
I'm not sure if this was your intention or a coincidence, but you're implementing something quite similar to "parser combinators", which is a topic of many academic papers :-). I think that Monadic Parser Combinators is quite readable (it has examples in Haskell, but you should be able to translate them to F#).
Regarding the function composition operator. I'm generally not a big fan of using the operator too much, because it often obfuscates the code. However, in your example it makes a good sense because you can easily imagine that >> means "this group should be followed by that group", which is easy to interpret.
The only minor change that I would do is to choose some nice custom operator for the disjunction operation and define a few more primitive operations, so that you can write for example this:
// Test against several terms in sequence
let sequence terms = (fun state -> terms |> Seq.fold (>>) state)
// Test for a substring
let substring s = sequence [ for c in s -> term (set [c]) ]
let test = // (abc|xyz)a{2,3}bc
( substring "abc" <|> substring "xyz" )
>> quantify 2 3 (term (set "a")) // (a{2,3})
>> substring "bc" // bc
This is more higher-level description, so it removes some of the >> operators in favor of functions that are more descriptive (and encapsulate >>). I also changed quantify to take multiple arguments instead of a tripple (which is a minor change)
If you want to play with this further, then you can take a look at the article and try to write F# computation expression builder that would allow you to use parser { .. } syntax.
This is generally good style but you're missing some tricks and still have quite a bit of redundancy. Maybe more like this:
let valid (s: State) = s.succeeded && s.index < s.input.Length
...
let disjunction leftTerm rightTerm s =
let left = leftTerm s
if left.succeeded then left else
let right = rightTerm s
if right.succeeded then right else
{ s with succeeded = false }
...
let test =
let f s = set s |> term
let (++) s t = f s >> f t
disjunction ("a" ++ "b" ++ "c") ("x" ++ "y" ++ "z")
>> quantify (f "a", 2, 3)
>> "b" ++ "c"
You might prefer to accumulate a value representing a computation rather than closures because it makes debugging much easier.