Convert string to code in Scheme - lisp

How do I convert a string into the corresponding code in PLT Scheme (which does not contain the string->input-port method)? For example, I want to convert this string:
"(1 (0) 1 (0) 0)"
into this list:
'(1 (0) 1 (0) 0)
Is it possible to do this without opening a file?

Scheme has procedure read for reading s-expressions from input port and you can convert a string to input stream with string->input-port. So, you can read a Scheme object from a string with
(read (string->input-port "(1 (0) 1 (0) 0)"))
I don't have Scheme installed, so I only read it from reference and didn't actually test it.

From PLT Scheme manual:
(open-input-string string [name-v]) creates an input port that reads bytes from the UTF-8 encoding (see section 1.2.3) of string. The optional name-v argument is used as the name for the returned port; the default is 'string.

From this similar question on comp.lang.scheme you can save the string to a file then read from it.
That might go something like this example code:
(let ((my-port (open-output-file "Foo")))
(display "(1 (0) 1 (0) 0)" my-port)
(close-output-port my-port))
(let* ((my-port (open-input-file "Foo"))
(answer (read my-port)))
(close-input-port my-port)
answer)

Many schemes have with-input-from-string str thunk that executes thunk in a context where str is the standard input port. For example in gambit scheme:
(with-input-from-string "(foo bar)"
(lambda () (read)))
evaluates to:
(foo bar)
The lambda is necessary because a thunk should be a procedure taking no arguments.

Related

How can I use Lisp subseq using colon (or other non-alphanumeric characters)?

I need to extract a substring from a string; the substring is enclosed by ":" and ";". E.g.
:substring;
But with Lisp (SBCL), I'm having trouble extracting the substring. When I run:
(subseq "8.I:123;" : ;)
I get:
#<THREAD "main thread" RUNNING {1000510083}>:
illegal terminating character after a colon: #\
Stream: #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDIN* {1000025923}>
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-IMPL::READ-TOKEN #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDIN* {1000025923}> #\:)
I've tried preceding the colon and semicolon with \ but that throws a different error. Can anyone advise? Thanks in advance for the help!
As you can see in docs for subseq, start and end are bounding index designators and they can be either integer or nil.
#\: and #\; are characters, so you can't use them, but you can use the function position to find the first index of each character and use these indices as arguments for subseq. You have to check that both indices exist and the second one is bigger than the first one:
(let* ((string "8.I:123;")
(pos1 (position #\: string))
(pos2 (position #\; string)))
(when (and pos1 pos2 (> pos2 pos1))
(subseq string
(1+ pos1)
pos2)))
=> "123"
This is a little bit cumbersome, so I suggest you to use some regex library. The following example was created with CL-PPCRE:
(load "~/quicklisp/setup.lisp")
(ql:quickload :cl-ppcre)
> (cl-ppcre:all-matches-as-strings "(?<=:)([^;]*)(?=;)" "8.I:123;:aa;")
("123" "aa")

Convert binary string to number

Pretty straightforward, but I can't seem to find an answer. I have a string of 1s and 0s such as "01001010" - how would I parse that into a number?
Use string-to-number, which optionally accepts the base:
(string-to-number "01001010" 2)
;; 74
As explained by #sds in a comment, string-to-number returns 0 if the conversion fails. This is unfortunate, since a return value of 0 could also means that the parsing succeeded.
I'd rather use the Common Lisp version of this function, cl-parse-integer. The standard function is described in the Hyperspec, whereas the one in Emacs Lisp is slightly different (in particular, there is no secondary return value):
(cl-parse-integer STRING &key START END RADIX JUNK-ALLOWED)
Parse integer from the substring of STRING from START to END. STRING
may be surrounded by whitespace chars (chars with syntax ‘ ’). Other
non-digit chars are considered junk. RADIX is an integer between 2 and
36, the default is 10. Signal an error if the substring between START
and END cannot be parsed as an integer unless JUNK-ALLOWED is non-nil.
(cl-parse-integer "001010" :radix 2)
=> 10
(cl-parse-integer "0" :radix 2)
=> 0
;; exception on parse error
(cl-parse-integer "no" :radix 2)
=> Debugger: (error "Not an integer string: ‘no’")
;; no exception, but nil in case of errors
(cl-parse-integer "no" :radix 2 :junk-allowed t)
=> nil
;; no exception, parse as much as possible
(cl-parse-integer "010no" :radix 2 :junk-allowed t)
=> 2
This thread has an elisp tag. Because it also has a lisp tag, I would like to show standard Common Lisp versions of two solutions. I checked these on LispWorks only. If my solutions are not standard Common Lisp, maybe someone will correct and improve my solutions.
For solutions
(string-to-number "01001010" 2)
and
(cl-parse-integer "001010" :radix 2)
LispWorks does not have string-to-number and does not have cl-parse-integer.
In LispWorks, you can use:
(parse-integer "01001010" :radix 2)
For the solution
(read (concat "#2r" STRING))
LispWorks does not have concat. You can use concatenate instead. read won't work on strings in LispWorks. You have to give read a stream.
In LispWorks, you can do this:
(read (make-string-input-stream (concatenate 'string "#2r" "01001010")))
You can also use format like this:
(read (make-string-input-stream (format nil "#2r~a" "01001010")))
This seems hacky by comparison, but FWIW you could also do this:
(read (concat "#2r" STRING))
i.e. read a single expression from STRING as a binary number.
This method will signal an error if the expression isn't valid.

When do variables output properly in skeletons functions?

I'm trying to write a skeleton-function to output expressions in a loop. Out of a loop I can do,
(define-skeleton test
""
> "a")
When I evaluate this function it outputs "a" into the working buffer as desired. However, I'm having issues when inserting this into a loop. I now have,
(define-skeleton test
"A test skeleton"
(let ((i 1))
(while (< i 5)
>"a"
(setq i (1+ i)))))
I would expect this to output "aaaaa". However, instead nothing is outputted into the working buffer in this case. What is happening when I insert the loop?
The > somestring skeleton dsl does not work inside lisp forms.
You can however concatenate the string inside a loop:
(define-skeleton barbaz
""
""
(let ((s ""))
(dotimes (i 5)
(setq s (concat s "a")))
s)
)
My understanding is that code such as
> "a"
only works at the first nesting level inside a skeleton.
[EDIT] Regarding your question
What is happening when I insert the loop?
The return value of the let form (that is, the return value of the while form)is inserted. I do not know why it does not raise an error when evaluating > "a", but the return value of a while form is nil, so nothing is inserted.
I do agree that there's not much point using define-skeleton if you're going to need an (insert function within the skeleton.
This is also a rather trivial example to be using define-skeleton.
That said, they are often easier to read than a defun and useful when you want to create a function that inserts text (and optionally, takes input).
For example you may wish to have a different character repeated a set no. of times... Below, str refers to the argument supplied with the function (usually a string) and v1, v2 are the default names for local variables in a skeleton. Thus:
(define-skeleton s2 ""
nil ; don't prompt for value of 'str'
'(set 'v1 (make-string 5 (string-to-char str)))
\n v1 \n \n)
Below, calling the function leads to a newline, the string, then leaves the cursor at the position indicated by the square brackets [].
(s2 "a")
aaaaa
[]

Emacs byte-to-position function is not consistent with document?

Emacs 24.3.1, Windows 2003
I found the 'byte-to-position' function is a little strange.
According to the document:
-- Function: byte-to-position byte-position
Return the buffer position, in character units, corresponding to
given BYTE-POSITION in the current buffer. If BYTE-POSITION is
out of range, the value is `nil'. **In a multibyte buffer, an
arbitrary value of BYTE-POSITION can be not at character boundary,
but inside a multibyte sequence representing a single character;
in this case, this function returns the buffer position of the
character whose multibyte sequence includes BYTE-POSITION.** In
other words, the value does not change for all byte positions that
belong to the same character.
We can make a simple experiment:
Create a buffer, eval this expression: (insert "a" (- (max-char) 128) "b")
Since the max bytes number in Emacs' internal coding system is 5, the character between 'a' and 'b' is 5 bytes. (Note that the last 128 characters is used for 8 bits raw bytes, their size is only 2 bytes.)
Then define and eval this test function:
(defun test ()
(interactive)
(let ((max-bytes (1- (position-bytes (point-max)))))
(message "%s"
(loop for i from 1 to max-bytes collect (byte-to-position i)))))
What I get is "(1 2 3 2 2 2 3)".
The number in the list represents the character position in the buffer. Because there is a 5 bytes big character, there should be five '2' between '1' and '3', but how to explain the magic '3' in the '2's ?
This was a bug. I no longer see this behavior in 26.x. You can read more about it here (which actually references this SO question).
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=20783

What's the corresponding standard function of atoi in clisp?

In visual lisp, you can use (atoi "123") to convert "123" to 123. It seems there is no "atoi" like function in clisp ?
any suggestion is appreciated !
Now i want to convert '(1 2 3 20 30) to "1 2 3 20 30", then what's the best way to do it ?
parse-interger can convert string to integer, and how to convert integer to string ? Do i need to use format function ?
(map 'list #'(lambda (x) (format nil "~D" x)) '(1 2 3)) => ("1" "2" "3")
But i donot know how to cnovert it to "1 2 3" as haskell does:
concat $ intersperse " " ["1","2","3","4","5"] => "1 2 3 4 5"
Sincerely!
In Common Lisp, you can use the read-from-string function for this purpose:
> (read-from-string "123")
123 ;
3
As you can see, the primary return value is the object read, which in this case happens to be an integer. The second value—the position—is harder to explain, but here it indicates the next would-be character in the string that would need to be read next on a subsequent call to a reading function consuming the same input.
Note that read-from-string is obviously not tailored just for reading integers. For that, you can turn to the parse-integer function. Its interface is similar to read-from-string:
> (parse-integer "123")
123 ;
3
Given that you were asking for an analogue to atoi, the parse-integer function is the more appropriate choice.
Addressing the second part of your question, post-editing, you can interleave (or "intersperse") a string with the format function. This example hard-codes a single space character as the separating string, using the format iteration control directives ~{ (start), ~} (end), and ~^ (terminate if remaining input is empty):
> (format nil "Interleaved: ~{~S~^ ~}." '(1 2 3))
"Interleaved: 1 2 3."
Loosely translated, the format string says,
For each item in the input list (~{), print the item by its normal conversion (~S). If no items remain, stop the iteration (~^). Otherwise, print a space, and then repeat the process with the next item (~}).
If you want to avoid hard-coding the single space there, and accept the separator string as a separately-supplied value, there are a few ways to do that. It's not clear whether you require that much flexibility here.