Parse Error on input 'appendString' Haskell - haskell

Hey guys so this is a strange little error I'm getting and I'm not understand why it's giving it to me.
It says Parse Error in input 'appendString' yet I see nothing wrong with it...
I call it from an if,then else statement as follows:
createShow currentIndex (Grid {delta = d, middle = (x,y), points = g}) dir counter =
if currentIndex ==0 || dir == 2
then (appendString d (x,y) g currentIndex) ++ (createShow currentIndex+1 (Grid {delta = d, middle = (x,y), points = g}) 2 (counter+1))
else if counter == (2*d+1)
then (appendString d (x,y) g currentIndex) ++ (appendX x)
else if dir == 1
then (appendString d (x,y) g currentIndex) ++ (createShow currentIndex-1 (Grid {delta = d, middle = (x,y), points = g}) 1 (counter+1))
where createShow returns a string and so does appendString
appendString gives the error in the constructor:
appendString d (x,y) g currentIndex =
(if currentIndex == y
then "y "
else
" " ) ++ (show currentIndex) ++(rowFunction g x d 0 (x+d) 1)++ "\n"
do you see where I could have gone wrong with it?
Edit: Added entire area

Haskell if's are not like other if's in say Java or python. The biggest difference is that they are expressions unlike java or python where they are statements.
They are much closer to the condition ? res1 : res2 from C.
The correct way to write nested if's is like this:
if condition
then foo
else if condition2
then bar
else ...
You'll notice that this is horribly ugly.
That's why haskell has guards:
foo args | condition = foo
| condition2= bar
| otherwise = meh
Here we declare a function foo and if condition is true then we execute foo otherwise we proceed to condition2 and otherwise is always true. For you
createShow currentIndex (Grid {delta = d, middle = (x,y), points = g}) dir counter
| currentIndex == 0 || dir == 2 = appendString d ....
| counter == (2 * d + 1) = appendString d ....
| dir == 1 = appendString d ....
which looks much more readable.

Here's a refactoring::
createShow currentIndex grid#(Grid {delta = d, middle = (x,y), points = g}) dir counter =
prefix ++ show currentIndex ++ row ++ "\n" ++ nextLine
where
prefix = if currentIndex == y then "y " else " "
row = rowFunction g x d 0 (x+d) 1
nextLine | currentIndex == 0 || dir == 2 = createShow (currentIndex+1) grid 2 (counter+1)
nextLine | counter == (2*d+1) = appendX x
nextLine | dir == 1 = createShow (currentIndex-1) grid 1 (counter+1)
appendX x = ...
Things to notice:
Using a where clause often lets you avoid repeating parameters
The common call to appendString has been factored out, and moved to the top, and then in-lined, since it is only called once.
Use of guards in nextLine to handle a cascaded if more clearly.
The guards and form of nextLine make it clear it isn't a total function. What happens when it falls off the end?
The use of grid# to name a pattern. This way you don't need to "reconstruct" the Grid value when making the recursive calls.
One can go further. Noticing that Grid {...} and dir never change throughout the function suggests factoring those out:
createShow currentIndex (Grid {delta = d, middle = (x,y), points = g}) dir counter =
line currentIndex counter
where
line currentIndex counter =
prefix ++ show currentIndex ++ row ++ "\n" ++ nextLine currentIndex counter
prefix = if currentIndex == y then "y " else " "
row = rowFunction g x d 0 (x+d) 1
nextLine currentIndex counter
| currentIndex == 0 || dir == 2 = line (currentIndex+1) (counter+1)
| counter == (2*d+1) = appendX x
| dir == 1 = line (currentIndex-1) (counter+1)
appendX x = ...
Here, line plays the part of "carrying" around the only values that differ as the function recurses. It would be a common idiom to place those arguments at the end of what createShow takes, and thus even factor them out:
createShow :: Grid -> Int -> Int -> Int -> String
createShow (Grid {delta = d, middle = (x,y), points = g}) dir = line
where
line currentIndex counter =
prefix ++ show currentIndex ++ row ++ "\n" ++ nextLine currentIndex counter
prefix = if currentIndex == y then "y " else " "
row = rowFunction g x d 0 (x+d) 1
nextLine currentIndex counter
| currentIndex == 0 || dir == 2 = line (currentIndex+1) (counter+1)
| counter == (2*d+1) = appendX x
| dir == 1 = line (currentIndex-1) (counter+1)
appendX x = ...

Related

Getting all strings in a lua script

I'm trying to encode some strings in my lua script, and since that I have a lua script with over 200k characters, encrypting each string query in the script with a function such as this example below
local string = "stackoverflow"
local string = [[stackoverflow]]
local string = [==[stackoverflow]==]
local string = 'stackoverflow'
to
local string=decode("jkrtbfmviwcfn",519211)
Trying to provide all above results to thread through a gsub and have the gsub encode the string text with a random offset number.
So far, I was only capable of gsubbing full quotation marks through.
function encode(x,offset,a)
for char in string.gmatch(x, "%a") do
local encrypted = string.byte(char) + offset
while encrypted > 122 do
encrypted = encrypted - 26
end
while encrypted < 97 do
encrypted = encrypted + 26
end
a[#a+1] = string.char(encrypted)
end
return table.concat(a)
end
luacode=[==[thatstring.Value="Encryptme!" testvalue.Value=[[string with
a linebreak]] string.Text="STOP!"]==]
luacode=luacode:gsub([=["(.-)"]=],function(s)
print("Caught "..s)
local offset=math.random(1,4)
local encoded=encode(s,offset,{})
return [[decode("]]..encoded..[[",]]..offset..[[)]]
end)
print("\n"..luacode)
With its output being
Caught Encryptme!
Caught STOP!
thatstring.Value=decode("crgvctxqi",4) testvalue.Value=[[string with
a linebreak]] string.Text=decode("opkl",2)
Any better solutions?
local function strings_and_comments(lua_code, callback)
-- lua_code must be valid Lua code (an error may be raised on syntax error)
-- callback will be invoked as callback(object_type, value, start_pos, end_pos)
-- callback("comment", comment_text, start_pos, end_pos) -- for comments
-- callback("string", string_value, start_pos, end_pos) -- for string literals
local objects = {} -- possible comments and string literals in the code
-- search for all start positions of comments (with false positives)
for pos, br1, eq, br2 in lua_code:gmatch"()%-%-(%-*%[?)(=*)(%[?)" do
table.insert(objects, {start_pos = pos,
terminator = br1 == "[" and br2 == "[" and "]"..eq.."]" or "\n"})
end
-- search for all start positions of string literals (with false positives)
for pos, eq in lua_code:gmatch"()%[(=*)%[[%[=]*" do
table.insert(objects, {is_string = true, start_pos = pos,
terminator = "]"..eq.."]"})
end
for pos, quote in lua_code:gmatch"()(['\"])" do
table.insert(objects, {is_string = true, start_pos = pos, quote = quote})
end
table.sort(objects, function(a, b) return a.start_pos < b.start_pos end)
local end_pos = 0
for _, object in ipairs(objects) do
local start_pos, ok, symbol = object.start_pos
if start_pos > end_pos then
if object.terminator == "\n" then
end_pos = lua_code:find("\n", start_pos + 1, true) or #lua_code
-- exclude last spaces and newline
while lua_code:sub(end_pos, end_pos):match"%s" do
end_pos = end_pos - 1
end
elseif object.terminator then
ok, end_pos = lua_code:find(object.terminator, start_pos + 1, true)
assert(ok, "Not a valid Lua code")
else
end_pos = start_pos
repeat
ok, end_pos, symbol = lua_code:find("(\\?.)", end_pos + 1)
assert(ok, "Not a valid Lua code")
until symbol == object.quote
end
local value = lua_code:sub(start_pos, end_pos):gsub("^%-*%s*", "")
if object.terminator ~= "\n" then
value = assert((loadstring or load)("return "..value))()
end
callback(object.is_string and "string" or "comment", value, start_pos, end_pos)
end
end
end
local inv256
local function encode(str)
local seed = math.random(0x7FFFFFFF)
local result = '",'..seed..'))'
if not inv256 then
inv256 = {}
for M = 0, 127 do
local inv = -1
repeat inv = inv + 2
until inv * (2*M + 1) % 256 == 1
inv256[M] = inv
end
end
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
result = '(decode("'..str:gsub('.',
function(m)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
m = m:byte()
local c = (m * inv256[M] - (H - M) / 128) % 256
K = L * 21271 + H + c + m
return ('%02x'):format(c)
end
)..result
return result
end
function hide_strings_in_lua_code(lua_code)
local text = { [[
local function decode(str, seed)
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
return (str:gsub('%x%x',
function(c)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
c = tonumber(c, 16)
local m = (c + (H - M) / 128) * (2*M + 1) % 256
K = L * 21271 + H + c + m
return string.char(m)
end
))
end
]] }
local pos = 1
strings_and_comments(lua_code,
function (object_type, value, start_pos, end_pos)
if object_type == "string" then
table.insert(text, lua_code:sub(pos, start_pos - 1))
table.insert(text, encode(value))
pos = end_pos + 1
end
end)
table.insert(text, lua_code:sub(pos))
return table.concat(text)
end
Usage:
math.randomseed(os.time())
-- This is the program to be converted
local luacode = [===[
print"Hello world!"
print[[string with
a linebreak]]
local str1 = "stackoverflow"
local str2 = [[stackoverflow]]
local str3 = [==[stackoverflow]==]
local str4 = 'stackoverflow'
print(str1)
print(str2)
print(str3)
print(str4)
]===]
-- Conversion
print(hide_strings_in_lua_code(luacode))
Output (converted program)
local function decode(str, seed)
repeat
seed = seed * 3
until seed > 2^43
local K = 8186484168865098 + seed
return (str:gsub('%x%x',
function(c)
local L = K % 274877906944 -- 2^38
local H = (K - L) / 274877906944
local M = H % 128
c = tonumber(c, 16)
local m = (c + (H - M) / 128) * (2*M + 1) % 256
K = L * 21271 + H + c + m
return string.char(m)
end
))
end
print(decode("ef869b23b69b7fbc7f89bbe7",2686976))
print(decode("c2dc20f7061c452db49302f8a1d9317aad1009711e0984",1210253312))
local str1 = (decode("84854df4599affe9c894060431",415105024))
local str2 = (decode("a5d7db792f0b514417827f34e3",1736704000))
local str3 = (decode("6a61bcf9fd6f403ed1b4846e58",1256259584))
local str4 = (decode("cad56d9dea239514aca9c8b8e0",1030488064))
print(str1)
print(str2)
print(str3)
print(str4)
Output of output (output produced by the converted program)
Hello world!
string with
a linebreak
stackoverflow
stackoverflow
stackoverflow
stackoverflow

Compare to string of names

I am trying to compare the names of two strings, and trying to pick out the name that are not included in the other string.
h = 1;
for i = 1:name_size_main
checker = 0;
main_name = main(i);
for j = 1:name_size_image
image_name = image(j);
temp = strcmpi(image_name, main_name);
if temp == 1;
checker = temp;
end
end
if checker == 0
result(h) = main_name;
h = h+1;
end
end
but it keeps returning the entire string as result, the main string contain roughly 1000 names, the images name contain about 300 names, so it should return about 700 names in result but it keep returning all 1000 names.
I tried your code with small vectors:
main = ['aaa' 'bbb' 'ccc' 'ddd'];
image = ['bbb' 'ddd'];
name_size_main = size(main,2);
name_size_image = size(image,2);
h = 1;
for i = 1:name_size_main
checker = 0;
main_name = main(i);
for j = 1:name_size_image
image_name = image(j);
temp = strcmpi(image_name, main_name);
if temp == 1;
checker = temp;
end
end
if checker == 0
result(h) = main_name;
h = h+1;
end
end
I get result = 'aaaccc', is it not what you want to get?
EDIT:
If you are using cell arrays, you should change the line result(h) = main_name; to result{h} = main_name; like that:
main = {'aaa' 'bbb' 'ccc' 'ddd'};
image = {'bbb' 'ddd'};
name_size_main = size(main,2);
name_size_image = size(image,2);
result = cell(0);
h = 1;
for i = 1:name_size_main
checker = 0;
main_name = main(i);
for j = 1:name_size_image
image_name = image(j);
temp = strcmpi(image_name, main_name);
if temp == 1;
checker = temp;
end
end
if checker == 0
result{h} = main_name;
h = h+1;
end
end
You can use cells of string along with setdiff or setxor.
A = cellstr(('a':'t')') % a cell of string, 'a' to 't'
B = cellstr(('f':'z')') % 'f' to 'z'
C1 = setdiff(A,B,'rows') % gives 'a' to 'e'
C2 = setdiff(B,A,'rows') % gives 'u' to 'z'
C3 = setxor(A,B,'rows') % gives 'a' to 'e' and 'u' to 'z'

Find the last index of a character in a string

I want to have ability to use a lastIndexOf method for the strings in my Lua (Luvit) project. Unfortunately there's no such method built-in and I'm bit stuck now.
In Javascript it looks like:
'my.string.here.'.lastIndexOf('.') // returns 14
function findLast(haystack, needle)
local i=haystack:match(".*"..needle.."()")
if i==nil then return nil else return i-1 end
end
s='my.string.here.'
print(findLast(s,"%."))
print(findLast(s,"e"))
Note that to find . you need to escape it.
If you have performance concerns, then this might be a bit faster if you're using Luvit which uses LuaJIT.
local find = string.find
local function lastIndexOf(haystack, needle)
local i, j
local k = 0
repeat
i = j
j, k = find(haystack, needle, k + 1, true)
until j == nil
return i
end
local s = 'my.string.here.'
print(lastIndexOf(s, '.')) -- This will be 15.
Keep in mind that Lua strings begin at 1 instead of 0 as in JavaScript.
Here’s a solution using
LPeg’s position capture.
local lpeg = require "lpeg"
local Cp, P = lpeg.Cp, lpeg.P
local lpegmatch = lpeg.match
local cache = { }
local find_last = function (str, substr)
if not (str and substr)
or str == "" or substr == ""
then
return nil
end
local pat = cache [substr]
if not pat then
local p_substr = P (substr)
local last = Cp() * p_substr * Cp() * (1 - p_substr)^0 * -1
pat = (1 - last)^0 * last
cache [substr] = pat
end
return lpegmatch (pat, str)
end
find_last() finds the last occurence of substr in the string
str, where substr can be a string of any length.
The first return value is the position of the first character of
substr in str, the second return value is the position of the
first character following substr (i.e. it equals the length of the
match plus the first return value).
Usage:
local tests = {
A = [[fooA]], --> 4, 5
[""] = [[foo]], --> nil
FOO = [[]], --> nil
K = [[foo]], --> nil
X = [[X foo X bar X baz]], --> 13, 14
XX = [[foo XX X XY bar XX baz X]], --> 17, 19
Y = [[YYYYYYYYYYYYYYYYYY]], --> 18, 19
ZZZ = [[ZZZZZZZZZZZZZZZZZZ]], --> 14, 17
--- Accepts patterns as well!
[P"X" * lpeg.R"09"^1] = [[fooX42barXxbazX]], --> 4, 7
}
for substr, str in next, tests do
print (">>", substr, str, "->", find_last (str, substr))
end
To search for the last instance of string needle in haystack:
function findLast(haystack, needle)
--Set the third arg to false to allow pattern matching
local found = haystack:reverse():find(needle:reverse(), nil, true)
if found then
return haystack:len() - needle:len() - found + 2
else
return found
end
end
print(findLast("my.string.here.", ".")) -- 15, because Lua strings are 1-indexed
print(findLast("my.string.here.", "here")) -- 11
print(findLast("my.string.here.", "there")) -- nil
If you want to search for the last instance of a pattern instead, change the last argument to find to false (or remove it).
Can be optimized but simple and does the work.
function lastIndexOf(haystack, needle)
local last_index = 0
while haystack:sub(last_index+1, haystack:len()):find(needle) ~= nil do
last_index = last_index + haystack:sub(last_index+1, haystack:len()):find(needle)
end
return last_index
end
local s = 'my.string.here.'
print(lastIndexOf(s, '%.')) -- 15

My recursion hang

It compiles correctly, but doesn't work.
It works for [] but if its anything else it just hang forever. test1 - ok, test 2 hang.
--Tests pour 'effectuerAchat'.
test1 = effectuerAchat achat1_1 [] == ([],achat1_1)
test2 = effectuerAchat achat1_1 [offre1_1_1_100] == ([(Commande "fournisseur1" "article1" 1 100)],Achat "article1" 0)
here is the code...
effectuerAchat a os = rfred a (offresPour a os) (achatQuantite(a)) []
where rfred a os n lc =
if os == []|| n==0
then (lc,(Achat (achatArticle(a)) n))
else
if n>=(offreQuantite(head(os)))
then let c= (Commande (offreFournisseur(head(os))) (achatArticle(a)) (offreQuantite(head(os))) (offrePrix(head(os))))
n= n-(offreQuantite(head(os)))
xs = tail(os)
in rfred a xs n (c:lc)
else let c= (Commande (offreFournisseur(head(os))) (achatArticle(a)) n (offrePrix(head(os))))
n= 0
xs = tail(os)
in rfred a xs n (c:lc)
You have an infinite loop in
let c= (Commande (offreFournisseur(head(os))) (achatArticle(a)) (offreQuantite(head(os))) (offrePrix(head(os))))
n= n-(offreQuantite(head(os)))
^^^^^
The n on the right hand side is not the n from the test above, but the n introduced on the left hand side of the binding (which shadows the one from the outer scope). If os (= offresPour achat1_1 [offre1_1_1_100]) contains more than one item, n is needed in the test
if os == []|| n==0
in the recursive call, and evaluation hangs.
Name the variable differently,
let c = ...
n' = n - ...
in rfred ... n' ...

Use character string as function argument

I'm sure this is simple, but I cannot find a solution ...
I would like to use a variable containing a character string as argument for a function.
x <- c(1:10)
myoptions <- "trim=0, na.rm=FALSE"
Now, something like
foo <- mean(x, myoptions)
should be the same as
foo <- mean(x, trim=0, na.rm=FALSE)
Thanks in advance!
You can use eval and parse:
foo <- eval(parse(text = paste("mean(x,", myoptions, ")")))
A more natural way to do what you want is to use do.call. For example,
R> l[["trim"]] = 0
R> l[["na.rm"]] = FALSE
R> l[["x"]] = 1:10
##Or l <- list(trim = 0, na.rm = FALSE, x = 1:10)
R> do.call(mean, l)
[1] 5.5
If for some reason you really want to use a myoptions string, you could always use strsplit to coarce it into a list form. For example,
R> y = "trim=0, na.rm=FALSE"
R> strsplit(y, ", ")
[[1]]
[1] "trim=0" "na.rm=FALSE"
R> strsplit(y, ", ")[[1]][1]
[1] "trim=0"
Here's a third answer that both uses parse, alist and do.call. My motivation for this new answer, is in the case where arguments are passed interactively from a client-side as chars. Then I guess, there is no good way around not using parse. Suggested solution with strsplit, cannot understand the context whether a comma , means next argument or next argument within an argument. strsplit does not understand context as strsplit is not a parser.
here arguments can be passed as "a=c(2,4), b=3,5" or list("c(a=(2,4)","b=3","5")
#' convert and evaluate a list of char args to a list of arguments
#'
#' #param listOfCharArgs a list of chars
#'
#' #return
#' #export
#'
#' #examples
#' myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
#' myArgs = callMeMaybe(myCharArgs)
#' do.call(mean,myArgs)
callMeMaybe2 = function(listOfCharArgs) {
CharArgs = unlist(listOfCharArgs)
if(is.null(CharArgs)) return(alist())
.out = eval(parse(text = paste0("alist(",
paste(parse(text=CharArgs),collapse = ","),")")))
}
myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
myArgs = callMeMaybe2(myCharArgs)
do.call(mean,myArgs)
[1] 2
Using all of do.call, eval and parse (combining kohske's and csgillespie's answers, and also WoDoSc's answer to 'Pass a comma separated string as a list'):
x <- c(1:10)
myoptions <- "trim = 0, na.rm = FALSE"
do.call(
what = mean,
args = append(list(x = x), eval(parse(text = paste0("list(", myoptions, ")"))))
)
This solution can be quite resilient in a more complex case, such as shown below.
myfn <- function(x, y = 0, z = 0, ...) {
print(paste("x:", x))
print(paste("y:", y))
print(paste("z:", z))
if (length(list(...)) > 0) {
print("other:")
print(list(...))
}
}
myextraargs <- paste(
"y = c(11, 14), z = 47,",
"t = data.frame(p = c('apple', 'plum'), j = c(7, 2), k = c(3, 21))"
)
do.call(
what = myfn,
args = append(
list(x = 7),
eval(parse(text = paste0("list(", myextraargs, ")")))
)
)
results in:
[1] "x: 7"
[1] "y: 11" "y: 14"
[1] "z: 47"
[1] "other:"
$t
p j k
1 apple 7 3
2 plum 2 21
...and...
myextraargs <- NULL
do.call(
what = myfn,
args = append(
list(x = 7),
eval(parse(text = paste0("list(", myextraargs, ")")))
)
)
results in
[1] "x: 7"
[1] "y: 0"
[1] "z: 0"

Resources