Scheme pattern matching with match-lambda - scheme

I am writing a function called annotate that uses match-lambda, often with recursive calls to annotate. Here is one of the pattern matches:
(`(lambda (,<param1> . ,<params>) ,<stmts>)
`(CLOSURE ENV (,<param1> . ,<params>) `(lambda (ENV) ,(map annotate ,(list-append `(,<param1> . ,<params>) `(,<stmts>))))))
list-append just makes new lists out of its two arguments. The problem is that when this pattern matches it returns something like:
'(CLOSURE
ENV
(x)
`(lambda (ENV)
,(map
annotate
(<results of list-append>))))
Specifically, ",(map annotate" prints literally rather than being evaluated -- even though it is being unquoted. Other patterns within the function appear to use the exact same syntax without this issue. Also, the unquoted function list-append executes with no problems.
Any advice is appreciated.

You have nested backquotes: you have one in front of CLOSURE and then a second one in front of the second lambda without a comma in between: notice the literal backquote in the middle of your output. I think removing the backquote before the second lambda will fix the problem.

Related

Regex not matching string in scheme but works on other platform

I am running string-match using the pattern [ \[\]a-zA-Z0-9_:.,/-]+ to match a sample text Text [a,b]. Although the pattern works on regex101, when I run it on scheme it returns #f. Here is the regex101 link.
This is the function I am running
(string-match "[ \\[\\]a-zA-Z0-9_:.,/-]+" "Text [a,b]")
Why isn't it working on scheme but works eleswhere? Am I missing something?
After discussing the issue on the guile gnu mailing list, I found out that Guile's (ice-9 regex) library uses POSIX extended regular expressions. And this flavor of regular expression doesn't support escaping in character classes [..], hence that's why it wasn't matching the strings.
However, I used the following function as a workaround and it works:
(string-match "[][a-zA-Z]+" "Text[ab]")
I don't see anything wrong with your regular expression syntax as it is quoted correctly so I assume there must be a bug in Guile, or the regexp library it uses, where \] just isn't interpreted the correct way inside brackets. I found a workaround by using the octal code point values instead:
(string-match "[A-Za-z\\[\\0135]+" "Text [a,b]")
; ==> #("Text [a,b]" (0 . 4))
Your regular expression isn't very good. It matches any combination of those chars so "]/Te,3.xt[2" also matches. If you are expecting a string like "Something [something, something]" I would rather have made /[A-Z][a-z0-9]+ [[a-z0-9]+,[a-z0-9]+]/ instead. eg.
(define pattern "[A-Z][a-z0-9]+ \\[[a-z0-9]+,[a-z0-9]+\\]")
(string-match pattern "Test [q,w]") ; ==> #("Test [q,w]" (0 . 10))
(string-match pattern "Be100 [sub,45]") ; ==> #("Be100 [sub,45]" (0 . 14))

Bash pattern matching 'or' using shell parameter expansion

hashrate=${line//*:/}
hashrate=${hashrate//H\/s/}
I'm trying to unify this regex replace into a single command, something like:
hashrate=${line//*:\+/H\/s/}
However, this last option doesn't work. I also tried with \|, but it doesn't seem to work and I haven't found anything useful in bash manuals and documentation. I need to use ${} instead of sed, even if using it solves my problem.
The alternation for shell patterns (assuming extended globbing, shopt -s extglob is enabled), is #(pattern|pattern...). For your case:
${line//#(*:|H\/s)}
The trailing / is optional if you just remove a pattern instead of replacing it.
Notice that because of the double slash, //, all occurrences of the patterns will be removed, one at a time. If you used *(...) (see randomir's answer), consecutive patterns would be removed all in one go. Unless you have giant string, the difference should be negligible. (If you have giant strings, you don't want to use globbing anyway, as it's not optimized for this kind of thing.)
If you enable extended globbing (extglob via shopt), you can use the *(pattern1|pattern2|...) operator to match zero or more glob patterns:
hashrate="${line//*(*:|H\/s)/}"

Weird issue when running grep with the --include option

Here is the code at the bash shell. How is the file mask supposed to be specified, if not this way? I expected both commands to find the search expression, but it's not happening. In this example, I know in advance that I prefer to restrict the search to python source code files only, because unqualified searches are silly time wasters.
So, this works as expected:
grep -rni '/home/ga/projects' -e 'def Pr(x,u,v)'
/home/ga/projects/anom/anom.py:27:def Pr(x,u,v): blah, blah, ...
but this won't work:
grep --include=\*.{py} -rni '/home/ga/projects' -e 'def Pr(x,u,v)'
I'm using GNU grep version 2.16.
--include=\*.{py} looks like a broken attempt to use brace expansion (an unquoted {...} expression).
However, for brace expansion
to occur in bash (and ksh and zsh), you must either have:
a list of at least 2 items, separated with ,; e.g. {py,txt}, which expands to 2 arguments, py and txt.
or, a range of items formed from two end points, separated with ..; e.g., {1..3}, which expands to 3 arguments, 1, 2, and 3.
Thus, with a single item, simply do not use brace expansion:
--include=\*.py
If you did have multiple extensions to consider, e.g., *.py as well as *.pyc files, here's a robust form that illustrates the underlying shell features:
'--include=*.'{py,pyc}
Here:
Brace expansion is applied, because {...} contains a 2-item list.
Since the {...} directly follows the literal (single-quoted) string --include=*., the results of the brace expansion include the literal part.
Therefore, 2 arguments are ultimately passed to grep, with the following literal content:
--include=*.py
--include=*.pyc
Your command fails because of the braces '{}'. It will search for it in the file name. You can create a file such as 'myscript.{py}' to convince yourself. You'll see it will appear in the results.
The correct option parameter would be '*.py' or the equivalent \*.py. Either way will protect it from being (mis)interpreted by the shell.
On the other side, I can only advise to use the command find for such jobs :
find /home/ga/projects -regex '.*\.py$' -exec grep -e "def Pr(x,u,v)" {} +
That will protect you from hard to understand shell behaviour.
Try like this (using quotes to be safe; also better readability than backslash escaping IMHO):
grep --include='*.py' ...
your \*.{py} brace expansion usage isn't supported at all by grep. Please see the comments below for the full investigation regarding this. For the record, blame this answer for the resulting brace wars ;)
By the way, the brace expansion works generally fine in Bash. See mklement0 answer for more details.
Ack. As an alternative, you might consider switching to ack instead from now on. It's a tool just like grep, but fully optimized for programmers.
It's a great fit for what you are doing. A nice quote about it:
Every once in a while something comes along that improves an idea so much, you can't ignore it. Such a thing is ack, the grep replacement.

scheme chicken regex logical grouping

have
(use extras format posix posix-extras regex regex-literals utils srfi-1)
have regex with logical groupings 1 and 2
/^(\\W+)\\s+(\\W+)/
but am having trouble with the syntax to actually -use- 1 and 2 .
Should I be using $1 $2 , or \1 and \2 , or something else? I'll be using
1 and 2 on the same LOC as the regex itself.
Thanks in advance,
Still-learning Steve
This question is old and it isn't particularly clear: you don't explain how you've tried to use the regex. I'll attempt to answer it anyway.
First off, there are no "special" variables $1 or $2 like in Perl or Ruby. With that out of the way, it becomes a simple matter of how to use the various procedures.
For example, with string-match, you simply receive a list of matches:
#;1> (use regex regex-literals)
#;2> (string-match #/b(a)(r)/ "bar")
("bar" "a" "r")
So, to refer to the Nth submatch you'd use (list-ref the-match N) (where 0 equals the complete matched string).
With string-substitute and when using back references within the regex, you'd use "\\1" (you have to use two backslashes to escape the backslash in string context):
#;1> (use regex regex-literal)
#;2> (string-substitute #/f(o)(\1)/ "lala\\2xyz" "foo")
"lalaoxyz"
This works in general, but there's an undocumented feature (or perhaps a bug) that if you use a backslash in front of an escape sequence in the replacement, it will be escaped. See this bugreport on how that works, and how to use irregex instead of the regex egg to aovid this.

Pattern matching error in Scheme

I have written a function match-rewriter that is just match-lambda except that it returns its argument if no match is found. match-rewriter is part of a larger function. Here is a portion of the code:
((match-rewriter
(`(PARAMS: (,<arg>))
`(Success))
(`(,<func> . ,<args>)
`(Failure))
)ls)
This function call:
(annotate '(PARAMS: (y))
returns Failure
In another post someone pointed out that this works:
#lang racket
(match `(PARAMS: (y))
[`(PARAMS: (,var)) 'yep]
[otherise 'nope])
returning yep
I verified that it works but I can't figure out why the same pattern isn't being matched in match-rewriter.
Strangely, if I just run this code manually substituting '(PARAMS: (y)) for "ls" it works. Which really confuses me.
Any advice is appreciated.

Resources