read words from a file into nested list in common lisp programming language - lisp

I have a file named test.txt, it contains
"hello this is a test file"
I want to read it from the file so that every word represents lists of character and every paragraph represents lists of words means that I want to store them into a nested list like:
(list(list (h e l l o)) (list(t h i s))(list(i s)) (list(a)) (list(t e s t)) (list(f i l e))))
I am totally new in lisp and have a lot of confusion about this problem.

Solution without any dependencies
(defun split (l &key (separators '(#\Space #\Tab #\Newline)) (acc '()) (tmp '()))
(cond ((null l) (nreverse (if tmp (cons (nreverse tmp) acc) acc)))
((member (car l) separators)
(split (cdr l) :separators separators
:acc (if tmp (cons (nreverse tmp) acc) acc)
:tmp '()))
(t
(split (cdr l) :separators separators
:acc acc
:tmp (cons (car l) tmp)))))
(defun read-file-lines (file-path)
(with-open-file (f file-path :direction :input)
(loop for line = (read-line f nil)
while line
collect line)))
(defun read-file-to-word-characters (file-path)
(mapcan (lambda (s) (split (coerce s 'list)))
(read-file-lines file-path)))
(read-file-to-word-characters "~/test.lisp.txt")
;; ((#\h #\e #\l #\l #\o) (#\t #\h #\i #\s) (#\i #\s) (#\a) (#\t #\e #\s #\t)
;; (#\f #\i #\l #\e))
Convert the characters to one-letter strings:
;; apply to elements of nested list (= a tree) the conversion function `string`
(defun map-tree (fn tree)
(cond ((null tree) '())
((atom tree) (funcall fn tree))
(t (mapcar (lambda (branch) (map-tree fn branch)) tree))))
(map-tree #'string (read-file-to-word-characters "~/test.lisp.txt"))
;; (("h" "e" "l" "l" "o") ("t" "h" "i" "s") ("i" "s") ("a") ("t" "e" "s" "t")
;; ("f" "i" "l" "e"))
Content of "~/test.lisp.txt":
hello this
is a test file
Solution using cl-ppcre (Edi Weitz's congenial regex package)
;; look here in an answer how to use cl-ppcre:split
;; https://stackoverflow.com/questions/15393797/lisp-splitting-input-into-separate-strings
(ql:quickload :cl-ppcre)
(defun read-file-lines (file-path)
(with-open-file (f file-path :direction :input)
(loop for line = (read-line f nil)
while line
collect line)))
(defun string-to-words (s) (cl-ppcre:split "\\s+" s))
(defun to-single-characters (s) (coerce s 'list))
(defun read-file-to-character-lists (file-path)
(mapcan (lambda (s)
(mapcar #'to-single-characters
(string-to-words s)))
(read-file-lines file-path)))
(read-file-to-character-lists "~/test.lisp.txt")
;; ((#\h #\e #\l #\l #\o) (#\t #\h #\i #\s) (#\i #\s) (#\a) (#\t #\e #\s #\t)
;; (#\f #\i #\l #\e))
;; or use above's function:
(map-tree #'string (read-file-to-character-lists "~/test.lisp.txt"))
;; (("h" "e" "l" "l" "o") ("t" "h" "i" "s") ("i" "s") ("a") ("t" "e" "s" "t")
;; ("f" "i" "l" "e"))
;; or:
(defun to-single-letter-strings (s) (cl-ppcre:split "\\s*" s))
(defun read-file-to-letter-lists (file-path)
(mapcan (lambda (s)
(mapcar #'to-single-letter-strings
(string-to-words s)))
(read-file-lines file-path)))
(read-file-to-letter-lists "~/test.lisp.txt")
;; (("h" "e" "l" "l" "o") ("t" "h" "i" "s") ("i" "s") ("a") ("t" "e" "s" "t")
;; ("f" "i" "l" "e"))

Related

Lisp lexical closure - function declaration

I have a function,format-ls:
(defun format-ls (ls)
(let (( acc ()))
(dolist (elt ls)
(push "(~A . " acc))
acc))
You can notice that there is a missing parenthesis in the closing line, acc)).
Yet my Lisp REPL(sbcl 2.1.1) interprets this expression without any errors:
format-ls, OK
But if I add the missing parenthesis, as shown below:
(defun format-ls (ls)
(let (( acc ()))
(dolist (elt ls)
(push "(~A . " acc)))
acc))
The REPL throws out the following error:
format-ls,error
Now this expression where all the parenthesis are matched, will be interpreted without any issues:
(b)
(defun post+ (ls)
(let (( acc ()))
(let ((i -1))
(dolist (elt ls)
(push (+ elt (setf i(+ i 1))) acc)))
(reverse acc)))
post+
What am I missing here?
(defun format-ls (ls)
(let ((acc ()))
(dolist (elt ls)
(push "(~A . " acc))
acc))
There are no unmatched parentheses in the s-expression. There is a single open parentheses inside a string, though.
It reads just fine:
CL-USER 40 > (read-from-string "(defun format-ls (ls)
(let ((acc ()))
(dolist (elt ls)
(push \"(~A . \" acc))
acc))")
(DEFUN FORMAT-LS (LS)
(LET ((ACC NIL))
(DOLIST (ELT LS) (PUSH "(~A . " ACC)) ACC))
221

How to do auto input in multiple read-lines?

How to do auto input in multiple read-line?
(let ((out (with-output-to-string (*standard-output*)
(let ((*standard-input* (make-string-input-stream "y y")))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "aaaaa"))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "bbbbbb"))
))))
out)
I try like this, and I get:
; Evaluation aborted on #<END-OF-FILE {10048FD503}>.
This code work with read, but I need with read-line.
Another possibility is to use the parameter of read-line that requires to return nil on end of file:
(let ((out (with-output-to-string (*standard-output*)
(let ((*standard-input* (make-string-input-stream "y y")))
(when (find (read-line *standard-input* nil) '("yes" "y" "t") :test #'string-equal)
(print "aaaaa"))
(when (find (read-line *standard-input* nil) '("yes" "y" "t") :test #'string-equal)
(print "bbbbbb"))))))
out)
I made it work like this:
(with-output-to-string (*standard-output*)
(with-input-from-string (*standard-input* (format nil "y~%y"))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "aaaaa"))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "bbbbbb"))))
The without-to-string is unnecessary for an example...
CL-USER 177 > (flet ((yes-p (input-string &aux (yes-words '("yes" "y" "t")))
"returns T when the input-string is one of yes, y or t."
(find input-string yes-words :test #'string-equal)))
(with-input-from-string (*standard-input* (format nil "y~%y"))
(when (yes-p (read-line))
(print "aaaaa"))
(when (yes-p (read-line))
(print "bbbbbb"))
(values)))
"aaaaa"
"bbbbbb"

drracket & How to detect a word in contact with the cursor

(define CHAR-CANVAS%
(class canvas%
(define/override (on-char evt)
(let ((c (send evt get-key-code)) (dc(send this get-dc)))
(send dc clear)
(print c)
(cond
((equal? c 'release)(void))
((member c '( #\a #\i #\u #\e #\o #\q #\é #\x))
(begin(set! tampon-key (cons c tampon-key)) (send dc draw-text (cadr (member (list->string (reverse tampon-key)) alphabet )) 30 30)
(send R-k-text insert (cadr (member (list->string (reverse tampon-key)) alphabet ))) (set! tampon-key '())))
((equal? c #\;)(begin(send R-k-text insert "。") (set! tampon-key '())))
((equal? c #\,)(begin(send R-k-text insert "、") (set! tampon-key '())))
((equal? c #\()(begin(send R-k-text insert "「") (set! tampon-key '())))
((equal? c #\))(begin(send R-k-text insert " 」") (set! tampon-key '())))
((equal? c #\&)(begin(send R-k-text insert "々") (set! tampon-key '())))
((not(member c '(#\b #\c #\d #\f #\g #\j #\k #\m #\n #\p #\r #\i #\h #\t #\s #\w #\y #\a #\e #\o #\z #\u)))(void))
((begin (set! tampon-key (cons c tampon-key))(print tampon-key))))
))
(super-new)))
It works very well (it is for writing in hiragana katakana and other characters)
I want to add to this same canvas
a feature which tells me the position of the cursor on a text
is it possible? if yes
what is the code to add?
(define/override (on-char evt)......
Or do I need a another canvas?
in this case what will be my code?
(define/override (on-char evt)......
this in order to do something similar to a "RIKAICHAN"
(define (transform-syll->mot L-romanji L-hiragana)
(let ((a '())(b'()))
(set! a (map list->string (reverse L-romanji)))
(set! b (map char->string (string->list "たべます")))
(list a b)))
(define (foo-w1 tw) ;transforme syllabe en fichier wav (if exist)
(let ((l '()))
(while (not (null? tw))
(set! l(cons (string-append (car tw )".wav")l))
(set! tw (cdr tw)))
(reverse l)))
(define (transform-mot->son L-romanji L-hiragana)
(let* ((x (transform-syll->mot L-romanji L-hiragana))
(a (car x)))
(current-directory "/Users/izuko/Desktop/japonais-new/jap-syll")
(rs-append* (map rs-read (foo-w1 a)))))
(define syllabe-R '())
(define syllabe-H '())
(define clip "")
(define Bt-dir
(new button%
(parent GP-1 )
(label "Direct")
(callback (lambda (obj evt)
(begin (set! alphabet hiragana)
(set! lecture-feld (send R-k-tex-rech get-text))
(set! LECT-HI* (cons lecture-feld LECT-HI*))
(set! LECT-ID* (cons lecture-feld LECT-ID*))
(send R-k-text insert lecture-feld)
(set! syllabe-R (transform-syll->mot tampon-wort lecture-feld))
(set! clip (transform-mot->son tampon-wort lecture-feld))
(play clip))))))

How to define function in LISP that recursively return back quoted list

I have problem with macros in my lisp interpreter writtein in JavaScript. the problem is in this code:
(define log (. console "log"))
(define (alist->object alist)
"(alist->object alist)
Function convert alist pairs to JavaScript object."
(if (pair? alist)
((. alist "toObject"))))
(define (klist->alist klist)
"(klist->alist klist)
Function convert klist in form (:foo 10 :bar 20) into alist
in form ((foo . 10) (bar . 20))."
(let iter ((klist klist) (result '()))
(if (null? klist)
result
(if (and (pair? klist) (pair? (cdr klist)) (key? (car klist)))
(begin
(log ":::" (cadr klist))
(log "data" (. (cadr klist) "data"))
(iter (cddr klist) (cons (cons (key->string (car klist)) (cadr klist)) result)))))))
(define (make-empty-object)
(alist->object '()))
(define empty-object (make-empty-object))
(define klist->object (pipe klist->alist alist->object))
;; main function that give problems
(define (make-tags expr)
(log "make-tags" expr)
`(h ,(key->string (car expr))
,(klist->object (cadr expr))
,(if (not (null? (cddr expr)))
(if (and (pair? (caddr expr)) (let ((s (caaddr expr))) (and (symbol? s) (eq? s 'list))))
`(list->array (list ,#(map make-tags (cdaddr expr))))
(caddr expr)))))
(define-macro (with-tags expr)
(make-tags expr))
I call this macro using this code:
(define (view state actions)
(with-tags (:div ()
(list (:h1 () (value (cdr (assoc 'count (. state "counter")))))
(:button (:onclick (lambda () (--> actions (down 1)))) "-")
(:button (:onclick (lambda () (--> actions (up 1)))) "+")))))
which should expand to almost the same code:
(define (view state actions)
(h "div" (make-empty-object)
(list->array (list
(h "h1" (make-empty-object) (value (cdr (assoc 'count (. state "counter")))))
(h "button" (klist->object `(:onclick ,(lambda () (--> actions (down 1))))) "-")
(h "button" (klist->object `(:onclick ,(lambda () (--> actions (up 1))))) "+")))))
This function works. I have problem with expanded code using my macro that call the main function, don't know how LIPS should behave when it find:
(:onclick (lambda () (--> actions (down 1))))
inside code and you try to process it like this:
,(klist->object (cadr expr))
Right now my lisp works that lambda is marked as data (have data flag set to true this is a hack to prevent of recursive evaluation of some code from macros) and klist->object function get lambda code as list, instead of function.
How this should work in Scheme or Common Lisp? Should klist->object get function object (lambda get evaluated) or list structure with lambda as first symbol? If second then how I sould write my function and macro to evaluate lambda should I use eval (kind of hack to me).
Sorry don't know how to test this, with more bug free LISP.
EDIT:
I've tried to apply the hint from #jkiiski in guile (because in my lisp it was not working)
;; -*- sheme -*-
(define nil '())
(define (key? symbol)
"(key? symbol)
Function check if symbol is key symbol, have colon as first character."
(and (symbol? symbol) (eq? ":" (substring (symbol->string symbol) 0 1))))
(define (key->string symbol)
"(key->string symbol)
If symbol is key it convert that to string - remove colon."
(if (key? symbol)
(substring (symbol->string symbol) 1)))
(define (pair-map fn seq-list)
"(seq-map fn list)
Function call fn argument for pairs in a list and return combined list with
values returned from function fn. It work like the map but take two items from list"
(let iter ((seq-list seq-list) (result '()))
(if (null? seq-list)
result
(if (and (pair? seq-list) (pair? (cdr seq-list)))
(let* ((first (car seq-list))
(second (cadr seq-list))
(value (fn first second)))
(if (null? value)
(iter (cddr seq-list) result)
(iter (cddr seq-list) (cons value result))))))))
(define (klist->alist klist)
"(klist->alist klist)
Function convert klist in form (:foo 10 :bar 20) into alist
in form ((foo . 10) (bar . 20))."
(pair-map (lambda (first second)
(if (key? first)
(cons (key->string first) second))) klist))
(define (h props . rest)
(display props)
(display rest)
(cons (cons 'props props) (cons (cons 'rest rest) nil)))
(define (make-tags expr)
`(h ,(key->string (car expr))
(klist->alist (list ,#(cadr expr)))
,(if (not (null? (cddr expr)))
(if (and (pair? (caddr expr)) (let ((s (caaddr expr))) (and (symbol? s) (eq? s 'list))))
`(list->array (list ,#(map make-tags (cdaddr expr))))
(caddr expr)))))
(define-macro (with-tags expr)
(make-tags expr))
(define state '((count . 10)))
(define xxx (with-tags (:div ()
(list (:h1 () (cdr (assoc 'count state)))
(:button (:onclick (lambda () (display "down"))) "-")
(:button (:onclick (lambda () (display "up"))) "+")))))
but got error:
ERROR: Unbound variable: :onclick
I've found solution for my lisp, Here is code:
(define (pair-map fn seq-list)
"(seq-map fn list)
Function call fn argument for pairs in a list and return combined list with
values returned from function fn. It work like the map but take two items from list"
(let iter ((seq-list seq-list) (result '()))
(if (null? seq-list)
result
(if (and (pair? seq-list) (pair? (cdr seq-list)))
(let* ((first (car seq-list))
(second (cadr seq-list))
(value (fn first second)))
(if (null? value)
(iter (cddr seq-list) result)
(iter (cddr seq-list) (cons value result))))))))
(define (make-tags expr)
(log "make-tags" expr)
`(h ,(key->string (car expr))
(alist->object (quasiquote
;; create alist with unquote for values and keys as strings
,#(pair-map (lambda (car cdr)
(cons (cons (key->string car) (list 'unquote cdr))))
(cadr expr))))
,(if (not (null? (cddr expr)))
(if (and (pair? (caddr expr)) (let ((s (caaddr expr))) (and (symbol? s) (eq? s 'list))))
`(list->array (list ,#(map make-tags (cdaddr expr))))
(caddr expr)))))
So in my code I'm writing some kind of meta macro I'm writing quasiquote as list that will get evaluated the same as if I use in my original code:
(klist->object `(:onclick ,(lambda () (--> actions (down 1)))))
I'm using alist->object and new function pair-map, so I can unquote the value and convert key symbol to string.
is this how it should be implemented in scheme? not sure If I need to fix my lisp or macros are working correctly there.

How to expand macros in guile scheme?

I'm trying to write let over lambda defmacro/g! in guile scheme. I have this:
(use-modules (srfi srfi-1))
(define (flatten x)
(let rec ((x x) (acc '()))
(cond ((null? x) acc)
((not (pair? x)) (cons x acc))
(else
(rec (car x)
(rec (cdr x) acc))))))
(define (g!-symbol? s)
(and (symbol? s)
(let ((symbol-string (symbol->string s)))
(and (> (string-length symbol-string) 2)
(equal? (string-downcase (substring symbol-string 0 2)) "g!")))))
(define-macro (define-macro/g! name-args . body)
(let ((syms (delete-duplicates
(filter g!-symbol? (flatten body)))))
`(define-macro ,name-args
(let ,(map
(lambda (s)
`(,s (gensym ,(substring (symbol->string s) 2))))
syms)
,#body))))
but when I try to macro expand define-macro/g! using this:
(use-modules (language tree-il))
(tree-il->scheme (macroexpand '(define-macro/g! (foo . body) `(let ((g!car ,(car body))) g!car))))
I've got this:
$15 = (if #f #f)
why I've got this result? How can I expand define-macro/g!?
I need to use this code:
(define macro '(define-macro/g! (foo . body) `(let ((g!car ,(car body))) g!car)))
(tree-il->scheme (macroexpand macro 'c '(compile load eval)))