I am new in haskell trying to do a small task
get1th ( a , _, _ , _) = a
foo input =
where input = (a:_,b:_,c:_,d:_)
if ( length (get1th input) == 2 )
then permutations[2]
else permutations[3]
I am getting error saying
parse error on input `where'
please give me a hint
where clause must be written at the end:
foo input =
if ( length (get1th input) == 2 )
then permutations[2]
else permutations[3]
where (a:_,b:_,c:_,d:_) = input
UPDATED
It is also require to swap to (a:_,b:_,c:_,d:_) = input, reason - we want to extract values, but not to redefine input
As #wit has pointed out, where should be used in the end of expression. Why? Because:
it is not a let;
because it is related with all the previous context (block) of the function.
If you want to define an alias fronthand, you should use the let expression.
For more information about the differences and advantages of them, see the Let vs. Where.
Related
I need to evaluate a dynamic logical expression and I know that in ABAP it is not possible.
I found the class cl_java_script and with this class I could achieve my requeriment. I've try something like this:
result = cl_java_script=>create( )->evaluate( `( 1 + 2 + 3 ) == 6 ;` ).
After the method evaluate execution result = true as espected. But my happiness is over when I look into the class documentation that says This class is obsolete.
My question is, there is another way to achieve this?
Using any turing complete language to parse a "dynamic logical expression" is a terrible idea, as an attacker might be able to run any program inside your expression, i.e. while(true) { } will crash your variant using cl_java_script. Also although I don't know the details of cl_java_script, I assume it launches a separate JS runtime in a separate thread somewhere, this does not seem to be the most efficient choice to calculate such a small dynamic expression.
Instead you could implement your own small parser. This has the advantage that you can limit what it supports to the bare minimum whilst being able to extend it to everything you need in your usecase. Here's a small example using reverse polish notation which is able to correctly evaluate the expression you've shown (using RPN simplifies parsing a lot, though for sure one can also build a full fledged expression parser):
REPORT z_expr_parser.
TYPES:
BEGIN OF multi_value,
integer TYPE REF TO i,
boolean TYPE REF TO bool,
END OF multi_value.
CLASS lcl_rpn_parser DEFINITION.
PUBLIC SECTION.
METHODS:
constructor
IMPORTING
text TYPE string,
parse
RETURNING VALUE(result) TYPE multi_value.
PRIVATE SECTION.
DATA:
tokens TYPE STANDARD TABLE OF string,
stack TYPE STANDARD TABLE OF multi_value.
METHODS pop_int
RETURNING VALUE(result) TYPE i.
METHODS pop_bool
RETURNING VALUE(result) TYPE abap_bool.
ENDCLASS.
CLASS lcl_rpn_parser IMPLEMENTATION.
METHOD constructor.
" a most simple lexer:
SPLIT text AT ' ' INTO TABLE tokens.
ASSERT lines( tokens ) > 0.
ENDMETHOD.
METHOD pop_int.
DATA(peek) = stack[ lines( stack ) ].
ASSERT peek-integer IS BOUND.
result = peek-integer->*.
DELETE stack INDEX lines( stack ).
ENDMETHOD.
METHOD pop_bool.
DATA(peek) = stack[ lines( stack ) ].
ASSERT peek-boolean IS BOUND.
result = peek-boolean->*.
DELETE stack INDEX lines( stack ).
ENDMETHOD.
METHOD parse.
LOOP AT tokens INTO DATA(token).
IF token = '='.
DATA(comparison) = xsdbool( pop_int( ) = pop_int( ) ).
APPEND VALUE #( boolean = NEW #( comparison ) ) TO stack.
ELSEIF token = '+'.
DATA(addition) = pop_int( ) + pop_int( ).
APPEND VALUE #( integer = NEW #( addition ) ) TO stack.
ELSE.
" assumption: token is integer
DATA value TYPE i.
value = token.
APPEND VALUE #( integer = NEW #( value ) ) TO stack.
ENDIF.
ENDLOOP.
ASSERT lines( stack ) = 1.
result = stack[ 1 ].
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
" 1 + 2 + 3 = 6 in RPN:
DATA(program) = |1 2 3 + + 6 =|.
DATA(parser) = NEW lcl_rpn_parser( program ).
DATA(result) = parser->parse( ).
ASSERT result-boolean IS BOUND.
ASSERT result-boolean->* = abap_true.
SAPs BRF is an option, but potentially massive overkill in your scenario.
Here is a blog on calling BRF from abap.
And here is how Rules/Expressions can be defined dynamically.
BUT, if you know enough about the source problem to generate
1 + 2 + 3 = 6
Then it is hard to imagine why a simple custom parser cant be used.
Just how complex should the expressions be ?
Id probably write my own parser before investing in calling BRF.
Since some/many BSPs use server side JAVAscript and not ABAP as the scripting language, i cant see SAP removing the Kernel routine anytime soon.
SYSTEM-CALL JAVA SCRIPT EVALUATE.
SO maybe consider Just calling the cl_java_script anyway until it is an issue.
Then worry about a parser if and when it is really no longer a valid call.
But definitely some movement in the obsolete space here.
SAP is pushing/forcing you to cloud with the SDK, to execute such things.
https://sap.github.io/cloud-sdk/docs/js/overview-cloud-sdk-for-javascript
I have started studying Haskell, and I am try to write a "reverse" function.
I created 2 functions for that, and they work, but now I want to define one locally within the second, but I get syntax errors. Here's what I'm doing:
let liste1 = [4,2,8,1,7,12]
-- I create a random list
test(x,y)= if x==[] then y else test(tail(x),head(x):y)
-- take a 2 list, with y=[] to have a list memory
inverse(x)=test(x,[])
-- and finally, to have only 1 parameter
and then, we have:
> inverse(liste1)
[12,7,1,8,2,4]
It's works! Amazing!
Now I want to have test as a LOCAL function. This is what I have tried so far:
inverse(x) = let test(x,[]) in if x==[] then y else test(tail(x),head(x):y)
and
inverse(x) = let if x==[] then y else test(tail(x),head(x):y) in test(x,[])
Both ways don't work, and I get the following error: parse error on input ìn'
I know it's basic question, and more basic solution, but I don't get it... Help me please!
When adding definitions using let, you want to put your definition between let and in.
inverse(x) =
let test(x,y) = if x==[] then y else test(tail(x),head(x):y)
in test(x,[])
You could instead use where to give the definition afterwards:
inverse(x) = test(x,[])
where test(x,y) = if x==[] then y else test(tail(x),head(x):y)
its my second Day learning and experiment with Julia. Although I read the Documantation concerning Metaprogramming carefully (but maybe not carefully enough) and several simular threads. I still can't figure out how I can use it inside a function.
I tryed to make following function for simulation of some data more flexible:
using Distributions
function gendata(N,NLATENT,NITEMS)
latent = repeat(rand(Normal(6,2),N,NLATENT), inner=(1,NITEMS))
errors = rand(Normal(0,1),N,NLATENT*NITEMS)
x = latent+errors
end
By doing this:
using Distributions
function gendata(N,NLATENT,NITEMS,LATENT_DIST="Normal(0,1)",ERRORS_DIST="Normal(0,1)")
to_eval_latent = parse("latent = repeat(rand($LATENT_DIST,N,NLATENT), inner=(1,NITEMS))")
eval(to_eval_latent)
to_eval_errors = parse("error = rand($ERRORS_DIST,N,NLATENT*NITEMS)")
eval(to_eval_errors)
x = latent+errors
end
But since eval don't work on the local scope it dont work. What can I do to work arround this?
Also the originally function, don't seem to be that fast, did I make any major mistakes concerning perfomance?
I really appriciate any recommandation.
Thanks in advance.
There is no need to use eval there, you can retain the same flexibility by passing the distribution types as keyword args (or named args with default values). Parsing and eval'ing "stringly-typed" arguments will often defeat optimizations and should be avoided.
function gendata(N,NLATENT,NITEMS; LATENT_DIST=Normal(0,1),ERRORS_DIST=Normal(0,1))
latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS))
errors = rand(ERRORS_DIST,N,NLATENT*NITEMS)
x = latent+errors
end
julia> gendata(10,2,3, LATENT_DIST=Pareto(.3))
...
julia> gendata(10,2,3, ERRORS_DIST=Gamma(.6))
...
etc.
You're not really supposed to use eval here (slower, won't produce type information, will interfere with compilation, etc) but in case you're trying to understand what went wrong, here's how you would do it:
Either separate it from the rest of the code:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
# Eval your expressions separately
LATENT_DIST = eval(parse(LDIST_EX))
ERRORS_DIST = eval(parse(EDIST_EX))
# Do your thing
latent = repeat(rand(LATENT_DIST,N,NLATENT), inner=(1,NITEMS))
errors = rand(ERROR_DIST,N,NLATENT*NITEMS)
x = latent+errors
end
Or use interpolation with quoted expressions:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
# Obtain expression objects
LATENT_DIST = parse(LDIST_EX)
ERRORS_DIST = parse(EDIST_EX)
# Eval but interpolate in everything that's local to the function
# And you can't introduce local variables with eval so keep them
# out of it.
latent = eval( :(repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS))) )
errors = eval( :(rand($ERRORS_DIST, $N, $NLATENT*$NITEMS)) )
x = latent+errors
end
You can also use a single eval with a let block to introduce a self-contained scope:
function gendata(N,NLATENT,NITEMS,LDIST_EX="Normal(0,1)",EDIST_EX="Normal(0,1)")
LATENT_DIST = parse(LDIST_EX)
ERRORS_DIST = parse(EDIST_EX)
x =
#eval let
latent = repeat(rand($LATENT_DIST,$N,$NLATENT), inner=(1,$NITEMS))
errors = (rand($ERRORS_DIST, $N, $NLATENT*$NITEMS))
latent+errors
end
end
((#eval x) == eval(:(x)))
Well, hope you understand the eval thing a little better. Day two I mean, you should be experimenting ;)
I've got a problem in OCaml, I'm currently learning it but I'm quite a newbie still. I would like to make a function which is returning true if the string is empty or contains only whitespace and in the same time remove any occurence of begin and end.
I tried already this:
let isEmptyString s =
let rec empty i =
if i < 0 then true
else
let c = String.get s i in
if c = ' ' || c = '\009' then empty (pred i)
else false
in
s = Str.global_replace( Str.regexp "begin") "" s;
s = Str.global_replace( Str.regexp "end") "" s;
empty (pred (String.length s))
But obviously, this function is not working as I would like it because I obtain still begin in Formula.importNrAgentsFormula after calling it... Here is my way to call it :
while true do
let input = read_line () in
if not (isEmptyString input) then
let (nr, f) = Formula.importNrAgentsFormula input in
incr counter;
flush stdout;
match choice with
| "graph" -> printRes (Graph.isSat ~verbose:verb nr f)
| _ -> printUsage ()
else ()
done
If someone with more experiences in OCaml could spot and explain to me the error, I would be glad :)
Thanks in advance,
Best Regards.
I suggest you let your function isEmptyString (isBlankString rather?) do what it is supposed to do (just check if it contains only whitespaces or nothing), it should not modify the original string. You can do this in your loop:
while true do
let input = read_line () in
let input = Str.global_replace( Str.regexp "begin") "" input in
let input = Str.global_replace( Str.regexp "end") "" input in
if not (isEmptyString input) then
...
Edit: Sorry for the late edit, here is some additional information on your error:
If you run your function in OCaml, you will see this warning:
Warning 10: this expression should have type unit.
on the line of s = Str.global_replace( Str.regexp "begin") "" s;. That is because the = operator in OCaml is not the assignment operator in this case but the equality operator, so on this line you simply compare your two values and return a boolean. Since OCaml expects e1 in e1;e2 to return unit, you get this warning.
In OCaml, values of variables are immutable, so you can:
Use another variable as #Jason suggests: let t = Str.global_replace( Str.regexp "begin") "" s
"shadow" the old value as I suggest above: let s = Str.global_replace( Str.regexp "begin") "" s
Use a reference (a pointer to a location in memory): let s = ref "before" in s := "after", you can then access the value pointed by the reference with the !operator: !s. However, if you are learning functional programming, I suggest you try not to use any imperative features of OCaml at the beginning to discover this new paradigm and its possibilities.
As I am at work I don't have utop with me, but just from first glance, in your first one, the documentation says:
val global_replace : regexp -> string -> string -> string
That means you don't need a ";" as that is for when functions return unit and is syntactic sugar for something like
let () = print_endline("foobar")
Additionally, you need to use a let statement as you cannot just reassign the value of s. I don't recommend shadowing the variable as that's generally bad practice in functional programming. Use something like:
let t = (Str.global_replace( Str.regexp "begin") "" s)
Also, your function does two different things. The helper recursive function you wrote returns true and false which is good (I'm assuming it works). What you ultimately use it for however is what you're returning. Therefore, for the first function are you aren't really returning the string if "begin" and "end"s have been replaced. Therefore you should have the end output of your function actually a tuple of type (bool,string). Then you can match on it when you call it (e.g.
let b,s = isEmptyString "foobar" in
if not b then:
rest of your code
I believe you have the right idea for your function though.
Also in your second function is there a way for you to not use any while loops and counters? (Also hopefully your counter is implemented with references otherwise you won't have anything global). I would suggest retrying the place where you call your first function as loops and counters are core to imperative programming and not functional (which is what makes OCaml so
fun
:). If not, it's fine sometimes there are just things you can't really do in OCaml without using its imperative features. Let me know if those suggestions don't work.
I'm running GHC version 7.8.3 on Windows 7.
Ok, this is not about fancy code snippets. I'm just trying not be a noob here and actually compile something in a way that vaguely resembles the structure of side-effect languages.
I have the following code:
main =
do {
let x = [0..10];
print x
}
I've learned here, that the keyword do is a fancy syntactic sugar for fancy monadic expressions. When I try to compile it, I get the following error:
main.hs:4:1: parse error on input 'print'
And I've learned in this other question, that tabs in Haskell are evil, so I've tried to omit them:
main =
do {
let x = [0..10];
print x
}
And I've failed miserably, because the parse error persists.
I've also learned here, that print is a syntactic sugar for the fancy equivalent:
main =
do {
let x = [0..10];
putStrLn $ show x
}
But then I get this error instead:
main.hs:4:9: parse error on input 'putStrLn'
Trying to face my despair, I've tried to omit the let keyword, after reading this answer:
main =
do {
x = [0..10];
print x
}
And then I get:
main.hs:4:1: parse error on input '='
And in a final useless attempt, I've even tried to omit the ';' like this:
main =
do {
let x = [0..10]
print x
}
And got:
main.hs:4:1: parse error on input 'print'
So,
How to properly use monadic expressions in Haskell without getting parse errors? Is there any hope?
It took me a while to see what was actually going on here:
main =
do {
let x = [0..10];
print x
}
The above looks as if we have a do with two statements, which is perfectly fine. Sure, it is not common practice to use explicit braces-and-semicolons when indentation implicitly inserts them. But they shouldn't hurt... why then the above fails parsing?
The real issue is that let opens a new block! The let block has no braces, so the indentation rule applies. The block starts with the definition x = [0..10]. Then a semicolon is found, which promises that another definition is following e.g.
let x = [0..10] ; y = ...
or even
let x = [0..10] ;
y = ... -- must be indented as the x above, or more indented
However, after the semicolon we find print, which is even indented less than x. According to the indentation rule, this is equivalent to inserting braces like:
main =
do {
let { x = [0..10]; }
print x
}
but the above does not parse. The error message does not refer to the implicitly inserted braces (which would be very confusing!), but only to the next line (nearly as confusing in this case, unfortunately).
The code can be fixed by e.g. providing explicit braces for let:
main = do { let { x = [0..10] };
print x }
Above, indentation is completely irrelevant: you can add line breaks and/or spaces without affecting the parsing (e.g. as in Java, C, etc.). Alternatively, we can move the semicolon below:
main = do { let x = [0..10]
; print x }
The above semicolon is on the next line and is less indented than x, implicitly inserting a } which closes the let block. Here indentation matters, since let uses the indentation rule. If we indent the semicolon more, we can cause the same parse error we found earlier.
Of course, the most idiomatic choice is using the indentation rule for the whole code:
main = do let x = [0..10]
print x
I was about to say, with no useful information, that
main = do
let x = [0..10]
print x
Was working for me, but I'm now off to read about the in within the braces.
As a slight aside, I found http://echo.rsmw.net/n00bfaq.html quite handy for reading about identation/formatting.
main = do let x = [0..10]
print x
works for me
and so does
main = do { let x = [0..10]
in print x }
I think you're trying to mix some different syntax options up.