Why is my test.check test using inputs smaller than the generator? - testing

I've implemented my own version of index-of. It takes two strings and returns the index where the second string is found in the first. In use, it seems to work fine, but it's failing the test.check property test. The weird thing is test.check says it fails at values like "0bU", but I have it set so the smallest input is 100 characters. Why is it using inputs smaller than what I've told it to use?
I wrote my own generator using gen/fmap and it looks correct when I call it using gen/sample.
The code:
(defn gen-alphanumeric "A generator that accepts a minimum and maximum string length" [min max]
(gen/fmap str/join (gen/vector gen/char-alphanumeric min max)))
(defspec indexof-functionality-test
(prop/for-all [s1 (gen-alphanumeric 100 200)
begin gen/nat 80]
(let [end (+ begin 10)
s2 (subs s1 begin end)]
(= (str/index-of s1 s2) (cp-str/indexof s1 s2)))))
The output from lein test
FAIL in (indexof-functionality-test) (string_test.clj:57) expected:
{:result true} actual: {:shrunk {:total-nodes-visited 11, :depth 4,
:pass? false, :result false, :result-data nil, :time-shrinking-ms 2,
:smallest ["240"]}, :failed-after-ms 0, :num-tests 4, :seed
1676231835751, :fail ["n5n0"], :result false, :result-data nil,
:failing-size 3, :pass? false, :test-var "indexof-functionality-test"}
EDIT:
My cp-str/indexof
(defn indexof
"given two strings, returns the index where sb begins in sa. Nil if not found"
([sa sb]
(indexof sa sb 0))
([sa sb i]
(let [sa-len (count sa)
sb-len (count sb)]
(cond
(>= 0 sa-len) nil
(>= 0 sb-len) nil
; this is hit when element not found
(> (+ i sb-len) sa-len) nil
(= (subs sa i (+ i sb-len)) sb) i
:else (indexof sa sb (inc i))))))
EDIT2: It fails on one computer and passes on another. Those three methods are identical on the two computers.

Related

scheme: resuming a loop after a condition has been signaled

This program is using Scheme conditions and restarts to execute a procedure 10 times in a loop, and return the number of times the procedure did succeed.
Here the procedure throws an error each times n is a multiple of 3.
For some reason, the first error (n=3) is caught but the loop fails to resume with n=4:
(define (handle! thunk)
(bind-condition-handler
'() (lambda (condition)
(display "resuming...")
(invoke-restart (find-restart 'next)))
thunk))
(let loop((n 1) (count 0))
(display n)(display #\,)
(if (> n 10) count
(handle!
(call/cc
(lambda (cc)
(with-restart
'next "restart here"
(lambda ()
(cc (loop (1+ n) count)))
#f
(lambda ()
(if (= 0 (modulo n 3))
(error n "is multiple of 3!")
(loop (1+ n) (1+ count))))))))))
I failed to find examples of conditions and restarts beyond the ones at the MIT Scheme Reference.
The solution is to move down the call/cc to the loop argument 'count' which is affected by the condition:
(let loop((n 1) (count 0))
(display n)(display #\,)
(if (> n 10) count
(handle!
(lambda()
(loop (1+ n)
(call/cc
(lambda (cc)
(with-restart
'next "restart here"
(lambda ()
(cc count))
#f
(lambda ()
(if (= 0 (modulo n 3))
(error n "is multiple of 3!"))
(1+ count))))))))))
Runs correctly:
1 ]=> 1,2,3,resuming...4,5,6,resuming...7,8,9,resuming...10,11,
;Value: 7

How to read just two integers from file in common lisp

(defun read-file (filename)
(with-open-file (stream filename)
(loop for line = (read-line stream nil)
while line
collect line)
)
)
I'm totally new to lisp so I want to read integer by integer but I have this line by line piece of code.
So I couldn't find that.
For exmp my file;
10 20
I need help .thx
Not sure exactly what you're asking, so here's a short proposition to read a file into a string, split it by whitespace, and parse each number with parse-integer:
(mapcar #'parse-integer (str:words (uiop:read-file-string "foo.txt")))
uiop comes from ASDF and is included in all major implementations, str is a library to quickload.
uiop also has read-file-lines.
OP goal seems to be to read lines from a file, each line containing a pair of integers, and to return a list containing all of the integers read from the file.
Given an input file, numbers.dat:
10 20
30 40
50 60
70 80
90 100
the file can be read into a list using read-line:
CL-USER> (with-open-file (in "numbers.dat" :direction :input)
(loop :for line := (read-line in nil)
:while line
:collect line))
("10 20" "30 40" "50 60" "70 80" "90 100" "")
But now the list contains strings, and each string corresponds to a pair of integers. We need a function to extract the integers from the strings. Common Lisp has the function read-from-string, which parses a string containing a printed representation of an object and returns that object and the first unread position of the input string. This function can be used in a loop to extract the integers from an input string:
CL-USER> (loop :with num
:and pos := 0
:do (setf (values num pos)
(read-from-string "10 20" t nil :start pos))
:collect num
:until (= pos 5))
(10 20)
If this code is removed to a function that can handle strings of varying lengths and empty strings, and mapped over an input list like ("10 20" "30 40" "50 60" "70 80" "90 100" ""), we will be close to the goal with ((10 20) (30 40) (50 60) (70 80) (90 100) ()). The contents of such a list could be appended together to obtain the desired list of all integers from the file:
;;; Expects well-behaved input
(defun get-numbers-from-string (string)
(if (string= string "") ; empty string returns empty list
'()
(let ((*read-eval* nil) ; small precaution to guard against malicious input
(length (length string)))
(loop :with num ; number from STRING
:and pos := 0 ; next position in STRING to read from
:do (setf (values num pos)
(read-from-string string t nil :start pos))
:collect num
:until (= pos length)))))
(defun read-integer-pairs (filename)
(with-open-file (in filename
:direction :input)
(apply #'append ; combine sublists into a single list of numbers
(mapcar #'get-numbers-from-string ; transform strings to number pairs
(loop :for line := (read-line in nil)
:while line
:collect line)))))
Sample interaction:
CL-USER> (read-integer-pairs "numbers.dat")
(10 20 30 40 50 60 70 80 90 100)
"Read just 2 integers from a file"
leaves some room for interpretation.
I will start by answering in the most literal sense:
Really just 2 integers in the file
(defun read-2-integers (stream)
(let ((i0 (read stream nil))
(i1 (read stream nil)))
(list i0 i1)))
If you write your functions in terms of a stream instead of a filename, you have an easier time testing interactively. For example:
CL-USER> (with-input-from-string (stream "10 20")
(read-2-integers stream))
(10 20)
2 integers per line in the file
Here is, where your code in the question comes in - as you would want
to read the file line by line (in case there are so many lines, that the whole file might not fit into memory or just because of other reasons).
(defun read-lines-with-2-integers (stream)
(loop
for line = (read-line stream nil)
while line
collecting (with-input-from-string (line-stream line)
(read-2-integers line-stream))))
Let's test if it works:
CL-USER> (with-input-from-string (stream "10 20
30 40
50 60")
(read-lines-with-2-integers stream))
((10 20) (30 40) (50 60))
Lines with integers in the file
;; first, we replace our function "read-2-integers" with something a bit more general, so we can apply it to a single line:
(defun read-integers (stream)
(loop
for c = (peek-char t stream nil) ;; skips whitespace
while c
collecting (read stream nil)))
;; next, we use this function just like we used "read-2-integers" before:
(defun read-lines-with-integers (stream)
(loop
for line = (read-line stream nil)
while line
collecting
(with-input-from-string (line-stream line)
(read-integers line-stream))))
which we can test like so:
CL-USER> (with-input-from-string (stream "10 20
30 40 50
60 70
80")
(read-lines-with-integers stream))
((10 20) (30 40 50) (60 70) (80))
File with integers - lines do not matter
In this case, we can just use our read-integers function from above:
CL-USER> (with-input-from-string (stream "10
20
30 40")
(read-integers stream))
(10 20 30 40)

Split lines in clojure while reading from file

I am learning clojure at school and I have an exam coming up. I was just working on a few things to make sure I get the hang of it.
I am trying to read from a file line by line and as I do, I want to split the line whenever there is a ";".
Here is my code so far
(defn readFile []
(map (fn [line] (clojure.string/split line #";"))
(with-open [rdr (reader "C:/Users/Rohil/Documents/work.txt.txt")]
(doseq [line (line-seq rdr)]
(clojure.string/split line #";")
(println line)))))
When I do this, I still get the output:
"I;Am;A;String;"
Am I missing something?
I'm not sure if you need this at school, but since Gary already gave an excellent answer, consider this as a bonus.
You can do elegant transformations on lines of text with transducers. The ingredient you need is something that allows you to treat the lines as a reducible collection and which closes the reader when you're done reducing:
(defn lines-reducible [^BufferedReader rdr]
(reify clojure.lang.IReduceInit
(reduce [this f init]
(try
(loop [state init]
(if (reduced? state)
#state
(if-let [line (.readLine rdr)]
(recur (f state line))
state)))
(finally
(.close rdr))))))
Now you're able to do the following, given input work.txt:
I;am;a;string
Next;line;please
Count the length of each 'split'
(require '[clojure.string :as str])
(require '[clojure.java.io :as io])
(into []
(comp
(mapcat #(str/split % #";"))
(map count))
(lines-reducible (io/reader "/tmp/work.txt")))
;;=> [1 2 1 6 4 4 6]
Sum the length of all 'splits'
(transduce
(comp
(mapcat #(str/split % #";"))
(map count))
+
(lines-reducible (io/reader "/tmp/work.txt")))
;;=> 24
Sum the length of all words until we find a word that is longer than 5
(transduce
(comp
(mapcat #(str/split % #";"))
(map count))
(fn
([] 0)
([sum] sum)
([sum l]
(if (> l 5)
(reduced sum)
(+ sum l))))
(lines-reducible (io/reader "/tmp/work.txt")))
or with take-while:
(transduce
(comp
(mapcat #(str/split % #";"))
(map count)
(take-while #(> 5 %)))
+
(lines-reducible (io/reader "/tmp/work.txt")))
Read https://tech.grammarly.com/blog/building-etl-pipelines-with-clojure for more details.
TL;DR embrace the REPL and embrace immutability
Your question was "what am I missing?" and to that I'd say you're missing one of the best features of Clojure, the REPL.
Edit: you might also be missing that Clojure uses immutable data structures so
consider this code snippet:
(doseq [x [1 2 3]]
(inc x)
(prn x))
This code does not print "2 3 4"
it prints "1 2 3" because x isn't a mutable variable.
During the first iteration (inc x) gets called, returns 2, and that gets thrown away because it wasn't passed to anything, then (prn x) prints the value of x which is still 1.
Now consider this code snippet:
(doseq [x [1 2 3]] (prn (inc x)))
During the first iteration the inc passes its return value to prn so you get 2
Long example:
I don't want to rob you of the opportunity to solve the problem yourself so I'll use a different problem as an example.
Given the file "birds.txt"
with the data "1chicken\n 2duck\n 3Larry"
you want to write a function that takes a file and returns a sequence of bird names
Lets break this problem down into smaller chunks:
first lets read the file and split it up into lines
(slurp "birds.txt") will give us the whole file a string
clojure.string/split-lines will give us a collection with each line as an element in the collection
(clojure.string/split-lines (slurp "birds.txt")) gets us ["1chicken" "2duck" "3Larry"]
At this point we could map some function over that collection to strip out the number like (map #(clojure.string/replace % #"\d" "") birds-collection)
or we could just move that step up the pipeline when the whole file is one string.
Now that we have all of our pieces we can put them together in a functional pipeline where the result of one piece feeds into the next
In Clojure there is a nice macro to make this more readable, the -> macro
It takes the result of one computation and injects it as the first argument to the next
so our pipeline looks like this:
(-> "C:/birds.txt"
slurp
(clojure.string/replace #"\d" "")
clojure.string/split-lines)
last note on style, for Clojure functions you want to stick to kebab case so readFile should be read-file
I would keep it simple, and code it like this:
(ns tst.demo.core
(:use tupelo.test)
(:require [tupelo.core :as t]
[clojure.string :as str] ))
(def text
"I;am;a;line;
This;is;another;one
Followed;by;this;")
(def tmp-file-name "/tmp/lines.txt")
(dotest
(spit tmp-file-name text) ; write it to a tmp file
(let [lines (str/split-lines (slurp tmp-file-name))
result (for [line lines]
(for [word (str/split line #";")]
(str/trim word)))
result-flat (flatten result)]
(is= result
[["I" "am" "a" "line"]
["This" "is" "another" "one"]
["Followed" "by" "this"]])
Notice that result is a doubly-nested (2D) matrix of words. The simplest way to undo this is the flatten function to produce result-flat:
(is= result-flat
["I" "am" "a" "line" "This" "is" "another" "one" "Followed" "by" "this"])))
You could also use apply concat as in:
(is= (apply concat result) result-flat)
If you want to avoid building up a 2D matrix in the first place, you can use a generator function (a la Python) via lazy-gen and yield from the Tupelo library:
(dotest
(spit tmp-file-name text) ; write it to a tmp file
(let [lines (str/split-lines (slurp tmp-file-name))
result (t/lazy-gen
(doseq [line lines]
(let [words (str/split line #";")]
(doseq [word words]
(t/yield (str/trim word))))))]
(is= result
["I" "am" "a" "line" "This" "is" "another" "one" "Followed" "by" "this"])))
In this case, lazy-gen creates the generator function.
Notice that for has been replaced with doseq, and the yield function places each word into the output lazy sequence.

Custom Scheme indexing function returns list-external value

I'm a newbie to scheme programming and I was writing small codes when I encountered the following issue and couldn't reason about it satisfactorily.
(define (at_i lst i)
(if (eq? i 0)
(car lst)
(at_i (cdr lst)
(- i 1) )))
Evaluation of (at_i '(1 2 3 4) 0) returns 1.
Now lets define same procedure with a lambda syntax.
(define (at_i lst i)
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec)
(- x 1) )))
lst i)
But now Evaluation of (at_i '(1 2 3 4) 0) returns 0, which is not in the list and in general, it returns element at index-1.
I don't understand why this is happening.
Note: I just realized its not returning element at index - 1 but the index itself. The reason for this has been well explained below by #Renzo. Thanks!
First, you should indent properly the code if you intend to learn the language, since code indentation is very important to understand programs in Scheme and Lisp-like languages.
For instance, your function correctly indented is:
(define (at_i lst i)
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec) (- x 1))))
lst
i)
From this you can see that you are defining the function at_i exactly as before in terms of a function with two parameters (lst and i), and whose body is constitued by three expressions: the first lambda (vec x) ... (- x 1)))), which is an (anonymous) function (lambda) which is not called or applied, the second, which is the first parameter lst, and finally the third which is the second parameter i. So, when the function at_i is called with two arguments, the result is the evaluation of the three expressions in sequence, the first two values are discarded (the function and the value of lst), and the result is the value of the second parameter i. This is reason for which the result of (at_i '(1 2 3 4) 0) is 0, since it is the value of i.
A proper redefinition of the function in lambda form would be the following, for instance:
(define at_i
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec) (- x 1)))))
(at_i '(1 2 3 4) 0) ;; => 1
in which you can see that the name at_i, through the define, is associated to a two parameter function which calculates correctly the result.
eq? is memory object equality. Only some Scheme implementations interpret (eq? 5 5) as #t. Use = for numbers, eqv? for values, and equal? for collections.
(define (index i xs) ; `index` is a partial function,
(if (= i 0) ; `i` may go out of range
(car xs)
(index (- i 1) ; Tail recursion
(cdr xs) )))
Your second function returns the index because you missed parenthesis around the lambda's application. It should be
(define (index i xs)
((lambda (i' xs')
(if (= i' 0)
(car xs')
(index (- i' 1) ; Not tail-recursive
(cdr xs') )))
i xs))
But this is verbose and differs semantically from the first formulation.
You say you are defining the "same procedure with a lambda syntax", but you are not. That would be (define at_i (lambda lst i) ...). Instead, you are effectively saying (define (at_i lst i) 1 2 3), and that is 3, of course.
In your particular case, you defined the procedure at_i to return (lambda (vec x) ...), lst and i. Now, if you call (at_i '(1 2 3 4) 0), the procedure will return 0, since that is the value of i at this point.

How to run a test file in SBCL

I am trying to run a test file in SBCL by executing the command sbcl --load file.lisp. However, when I execute the command the file is loaded, but I can't see my program output.
By the way here is a example of a test file:
(locally
(declare #+sbcl(sb-ext:muffle-conditions style-warning))
(handler-bind
(#+sbcl(style-warning #'muffle-warning))
(load "load.lisp")
))
(interval 5)
(interval 20)
(interval 500)
The load.lisp file, loads the source code of my program, that contains the definitions of several functions, including the interval function.
I already try other option from sbcl such as run sbcl --script file.lisp but the output is the same.
Anybody can help me with this problem? Thanks in advance.
** PRINT-OBJECT METHOD **
(defmethod print-object ((tensor tensor) stream)
"Implementation of the generic method print-object for the tensor data structure.
If the tensor is a vector, prints its elements separated by a whitespace.
If the tensor is not one of the previous cases, then for each sub-tensor of the
first dimension, prints the sub-tensor separated from the next sub-tensor by a
number of empty lines that is equal to the number of dimensions minus one."
(labels ((rec (arg last-iteration)
(cond ((null arg) nil)
((atom (car arg))
(format stream
(if (null (cdr arg)) "~A" "~A ")
(car arg))
(rec (cdr arg) nil))
((and (listp (car arg)) (null (cdr arg)))
(rec (car arg) last-iteration)
(unless last-iteration
(format stream "~%")))
(t
(rec (car arg) nil)
(format stream "~%")
(rec (cdr arg) last-iteration)))))
(rec (tensor-content tensor) t)))
When you load a file the return values of the forms are not automatically printed.
One option out of many:
(defun show (&rest items)
(dolist (i items)
(prin1 i)
(fresh-line))
(finish-output))
(locally
(declare #+sbcl(sb-ext:muffle-conditions style-warning))
(handler-bind
(#+sbcl(style-warning #'muffle-warning))
(load "load.lisp")
))
(show
(interval 5)
(interval 20)
(interval 500))
Should be usable with sbcl --script file.lisp.