What's wrong with this OCaml code? - ocaml

What's wrong with this code?
let vm_run vm =
let guard = ref true in
while !guard do
if vm.cur_pc = -1 && not (Stack.empty vm.call_stack) then vm_pop_ar vm
else if vm.cur_pc = -1 then guard := false
else if vm.cur_pc < Array.length vm.cur_code then
execute vm Array.get vm.cur_code vm.cur_pc;
vm.cur_pc <- vm.cur_pc + 1
else vm_pop_ar vm
done
Error is Error: Syntax error related to the last else keyword.
I reached good confidence with OCaml but an if/else chain still gives me some troubles.. that's not the first time (last time I exploited flow to avoid using the else keyword).
I think it's something small but have no clues, according to syntax specification it should be ok

The semicolon has lower precedence than if-else, so when you need to have a block of two or more statements separated by semicolons inside an if, you need to enclose them in parentheses or a begin...end block (the two are equivalent):
else if vm.cur_pc < Array.length vm.cur_code then begin
execute vm Array.get vm.cur_code vm.cur_pc;
vm.cur_pc <- vm.cur_pc + 1
end
else vm_pop_ar vm

Related

If/else-like behaviour

I'm actually having a huge problem debugging one of a script i'm programming on tradingview.
To make it simple, on the image below you'll find that at line 54, i'm calculating the value of "a" which firstly return 22.19.
After that i'm trying an if / else on which i'm basically doing the same calculation whether if my if/else is true or false and i'm not understanding why this return me a different result then the first time i'm calculating the "a" value.
Is there something obvious i'm missing there because this is actually driving me crazy ^^"
Edit 1 (with the value of Price and Price 1 ) :
Complete code :
Pastebin link : Nw2dWMi7
Let's simplify your example:
//#version=5
indicator("Dominant Cycle Tuned Rsi - V5")
var globalScope = 0.0
var localScope1 = 0.0
var localScope2 = 0.0
globalScope := ta.change(close)
if close > close[1]
// this ta.change has it's own set of values for cases when close > close[1]
localScope1 := ta.change(close)
localScope2 := na
else
localScope1 := na
// this ta.change has it's own set of values for other cases
localScope2 := ta.change(close)
plot (globalScope, color=color.red)
plot (localScope1, color=color.black)
plot (localScope2, color=color.black)
Firs of all, you're getting warning
The function 'ta.change' should be called on each calculation for consistency. It is recommended to extract the call from this scope.
From the manual: (https://www.tradingview.com/pine-script-docs/en/v4/language/Functions_and_annotations.html#execution-of-pine-functions-and-historical-context-inside-function-blocks)
The history of series variables used inside Pine functions is created
through each successive call to the function. If the function is not
called on each bar the script runs on, this will result in disparities
between the historic values of series inside vs outside the function’s
local block. Hence, series referenced inside and outside the function
using the same index value will not refer to the same point in history
if the function is not called on each bar.
The reason why you're getting different results because that when you're calling ta.change in a local scope.
if close > close[1]
// this ta.change has it's own set of values for cases when close > close[1]
localScope1 := ta.change(close)
here we comparing close and close[1] ONLY FOR cases when close > close[1].
And here
else
localScope1 := na
// this ta.change has it's own set of values for other cases
localScope2 := ta.change(close)
for the cases ONLY when close < close[1].
So results of two conditional statements and global scope will be different.

If Statements in Lua

In all other programming languages I've encountered, if statements always require a boolean to work, however in Lua the following code does not contain any errors. What is being checked in this if statement if both true and false statements can't be made? How can you only check "if (variable) then"? I am new to programming and currently working with Roblox Studio, any help would be very appreciated.
function onTouched(Obj)
local h = Obj.Parent:FindFirstChild("Humanoid")
if h then
h.Health = 0
end
end
script.Parent.Touched:Connect(onTouched)
Most languages have their own rules for how values are interpreted in if statements.
In Lua, false and nil are treated as false. All other values are treated as true.
if h == nil (null)
So if it couldn't find a humanoid in the object that touched the script's parent, it will be false (null), otherwise true (not null).
So
if [ObjectName] then
equals to if [ObjectName] != null then
*Only valid for objects (non primitive values)
It's like that in script languages.
if h then end
is basically equivalent to
if h ~= nil and h ~= false then end
In Lua all values that are not nil or false are considered to be logically true.
if h then end is usually used to check wether h is not nil. So if code depends on wether h has been defined you put it in a condition like that.
In your example h is being index. indexing nil values is not allowed. So befor you index it you should make sure it isn't nil to avoid errors.
Checking return values of functions is good practice.

Macro Vim - expand multiple Verilog Bus

I'm trying to implement Macro to expand Verilog Bus as Vim - Macro to expand verilog bus and this is really working good for one variable.
But I've got the problem because I want to implement multiple bus as the below
Source:
{test[13:10],thisistest[3:0],BUS[2:1]}
Result:
test[13]
test[12]
test[11]
test[10]
thisistest[3]
thisistest[2]
thisistest[1]
thisistest[0]
BUS[2]
BUS[1]
What I tried to do :
I made similar function as
fun! split()
let line = getline('.')
let result = []
let list = split(line, ",")
let length = len(list)
for i in length
call ExpandIt(list[length])
endfor
endf
fun! ExpandIt()
let pat = '^\(.*\)\[\(\d\+\):\(\d\+\)\]\s*$'
let line = getline('.')
let lnr = line('.')
if line !~ pat
return
endif
let exestr = substitute(line,pat,'range(\2,\3,-1)','g')
let text = substitute(line,pat,'\1','g')
exec 'let range='.exestr
let result = []
for i in range
call add(result, text.'['.i.']')
endfor
call append(lnr, result)
exec lnr'.d'
endf
nnoremap <F6> :call split()<cr>
Could you please let me know what am I supposed to do to go with right way?
Based on the obvious errors in your added split() function (the function name must be capitalized to avoid E128, you pass an argument to ExpandIt(), but it doesn't take any, length is not iterable by :for), you seem to have a limited understanding of Vimscript, and just try to "make it work" through brute-force attempts. Therefore it was good to ask here on Stack Overflow, but please be aware that just relying on helpful strangers to fix things for you is a lopsided approach, so please use this and future questions to slowly but steadily learn about Vim, to become a master of it yourself!
The following seems to do what you're asking for, by doing the following modifications:
fixing the obvious errors listed above
collecting the result List in Split() is the right idea, but the actual insertion (:call append()) and deletion of the original line has to be moved there as well, and ExpandIt() has to return the result
likewise, ExpandIt() needs to be passed the extracted element instead of directly getting the current line
the split() of the line into comma-separated elements needs to drop the surrounding { and }; substitute() can do this.
fun! Split()
let line = getline('.')
let result = []
for l in split(substitute(line, '[{}]', '', 'g'), ",")
let result += ExpandIt(l)
endfor
let lnr = line('.')
call append(lnr, result)
exec lnr'.d'
endf
fun! ExpandIt(line)
let pat = '^\(.*\)\[\(\d\+\):\(\d\+\)\]\s*$'
if a:line !~ pat
return
endif
let exestr = substitute(a:line,pat,'range(\2,\3,-1)','g')
let text = substitute(a:line,pat,'\1','g')
exec 'let range='.exestr
let result = []
for i in range
call add(result, text.'['.i.']')
endfor
return result
endf
nnoremap <F6> :call Split()<cr>

why the use of _ prevent having warnings

I have the following code (it's a test so it does nothing interesting)
let test k =
let rec aux = function
|0 -> 0
|z when z = 2 -> raise Exit
|_ -> aux (k-1)
in try let _ = aux k in true
with Exit -> false
At the end there is the use of the syntax : let _, to me it's just a syntax when you don't have an idea of a name you can use to define your function.
Yet if I do the following :
let test k =
let rec aux = function
|0 -> 0
|z when z = 2 -> raise Exit
|_ -> aux (k-1)
in try let b = aux k in true
with Exit -> false
I get a warning like : "variable b is unused", I don't understand why there is a difference between let _ and let b ?
For example I know that when dealing with unit type it's common to use the syntax : let (). Yet I don't have any warning when doing :
let b = print_int 2
even if I am not using :
let () = print_int 2
So what is particular with let _ ?
Thank you !
This is a convention, recognized by the compiler, to indicate that you're not going to use the result of a computation, e.g.,
let a = 5 + 6 in
()
will (or will not, depending on your warning settings) trigger the unused variable warning, since you clearly bound the result to a variable a, but not using it in the rest of your computation. In imperative languages it is quite common, to compute expressions for their side effects and ignore produced values if any. Since OCaml is a functional language, in which values are used to produce values, it usually an indicator of an error, when you forgot to use a bound variable.
Therefore, to explicitly tell the compiler that you're ignoring the value, you may start your variable with the underscore, e.g.,
let _unusued = 5 + 6 in
()
You can just use a wild pattern _ (which also starts with the underscore).
You have a warning with your second code because you define the variable b containing a value and you do not use it after.
The best use if you do not want to use the result of any expression is to discard its result using the 'let _ =' construct (it tells you want the expression to be evaluated, for potential side effects, but do not care to keep its result).
For the second part of your question, I think there are different rules related to the top loop, so the behaviours may not be comparable. In the first part, you define b inside a function and in the second part, you define b inside the top loop. In the top loop, you may define variables you will not use without getting a warning.

XQuery get Random Text from a List

Suppose I have a list of 100 String Element and I want to get 50 of these random Text string to be returned Randomly.
I try to do this:
let $list := ("a","b",..."element number 100")
return xdmp:random(100)
This query return one string, I want to return back 50 strings that are distinct from each other.
Easiest to order by xdmp:random() and limit to the first 50:
(for $x in (1 to 100)
order by xdmp:random()
return $x
)[1 to 50]
xdmp:random() (as well as xdmp:elapsed-time()) return different values at each call. It would be rather impractical if it wouldn't. This opposed to for instance fn:current-dateTime() which gives the same value throughout one execution run.
Ghislain is making a good first attempt, but as also pointed out by BenW, even though xdmp:random() does return different results each time, it is not said they are unique throughout one execution run. Collisions on its 64-bit max scale are rare (though still possible), but on small scale like 10's or 100's it is likely to have some accidental repetition. It is wise to eliminate the texts from the list once chosen.
BenW beat me to posting an alternative to Ghislain, and it looks similar, but uses less lines. Posting it anyhow, in the hope someone finds it useful:
declare function local:getRandomTexts($list, $count) {
if ($count > 0 and exists($list)) then
let $random := xdmp:random(count($list) - 1) + 1
let $text := $list[$random]
return ($text, local:getRandomTexts($list[. != $text], $count - 1))
else ()
};
let $list :=
for $i in (1 to 26)
return fn:codepoints-to-string(64 + $i)
for $t in local:getRandomTexts($list, 100)
order by $t
return $t
HTH!
If you are saying the 50 strings must be distinct from one another, as in, no repeats allowed, then even if xdmp:random() does return different values when called repeatedly in the same query, getting 50 random positions in the same list is not sufficient, because there may be repeats. You need to get random positions from 50 different lists.
declare function local:pickSomeFromList($some as xs:integer, $listIn as xs:string*, $listOut as xs:string*) as xs:string* {
if($some = 0 or not($listIn)) then $listOut
else
let $random := xdmp:random(count($listIn) - 1) + 1
return local:pickSomeFromList(
$some - 1,
($listIn[fn:position() lt $random],$listIn[fn:position() gt $random]),
($listOut, $listIn[$random])
)
};
let $list := ("a","b","c","d","e","f","g","h","i","element number 10")
return local:pickSomeFromList(5, $list, ())
Assuming it returns a different result at every call (but I cannot tell from the documentation of xdmp:random whether it is the case), the following code returns 50 strings from the list picked at random (but not necessarily distinct):
let $list := ("a","b",..."element number 100")
for $i in 1 to 50
let $position = 1 + xdmp:random(99)
return $list[$position]
However, the exact behavior of xdmp:random, that is, whether it returns identical results across calls, depends on how the MarkLogic engine supports or treats nondeterministic behavior, which is outside of the scope of the XQuery specification. Strict adherence to the specification would actually return 50 times the same result with the above query.
XQuery 3.1 provides a random number generator with which you can control the seed. This allows you to generate as many numbers as you want by chaining calls, while only using interoperable behavior and staying within a fully deterministic realm.
Edit: here is a query (still assuming calls to xdmp:random are made each time) that should make sure that 50 distinct strings from the list are taken following grtjn's remark. It uses a group by clause and relies on a lazy evaluation for taking the first 50.
let $list := ("a","b",..."element number 100")
let $positions := (
for $i in 1 to 100000 (: can be adjusted to make sure we get 50 distinct :)
group by $position = 1 + xdmp:random(count($list) - 1)
return $position
)[position() le 50]
return $list[position() = $positions]
I think hunterhacker's proposal for computing the $positions is even better though.