How to access sub-struct variables in Racket (Lisp/Scheme) - struct

I'm trying to write an AM/PM clock conversion function to a 24 hour clock (military time), but there's a struct and sub-struct that have variables I can't figure out how to pull. Neither 24HourClock-hours or AM/PM-hours is working to pull the hours or minutes variable out of the AM/PM instance of time that goes as the parameter of each of the two versions of the function.
The following two functions are two separate attempts at the same function:
(define (AM/PM->24HourClock2 time)
(cond
[(isAM? time) (24HourClock (24HourClock-hours 24HourClock-minutes))]
[else (24HourClock (+ 24HourClock-hours 12) 24HourClock-minutes)]))
(define (AM/PM->24HourClock time)
(cond
[(isAM? time) (24HourClock (AM/PM-hours AM/PM-minutes))]
[else (24HourClock (+ AM/PM-hours 12) AM/PM-minutes)]))
This one attempts to use a lambda function to access the sub-members:
(define (AM/PM->24HourClock time)
(lambda (hr min meridiem)
(cond
[(isAM? time) (24HourClock (hr min))]
[else (24HourClock (+ hr 12) min)]))
But here's the output:
Here's the earlier code that makes it reproducible:
#lang slideshow
(struct 24HourClock (hours minutes)
#:transparent
#:mutable
#:guard (lambda (hours minutes err_name)
(if (not (and (>= hours 0) (< hours 24)))
(error err_name "Hours must be between 0 and 24")
(if (not (and (>= minutes 0) (< minutes 60)))
(error err_name "Minutes must be between 0 and 60")
(values hours minutes)))))
(struct AM/PM 24HourClock (meridiem)
#:transparent
#:mutable
#:guard (lambda (hours minutes meridiem err_name)
(if (not(and(and(number? hours)(> hours 0)(<= hours 12)(number? minutes))))
(error err_name "Hours must be between 1 and 12 : 0")
(if [not (and(string? meridiem)(or
(equal? meridiem "am")
(equal? meridiem "AM")
(equal? meridiem "pm")
(equal? meridiem "PM")))]
(error err_name "Invalid value for meridiem")
(values hours minutes meridiem)))))
(define (isAM? time)
(or (equal? (AM/PM-meridiem time) "AM")
(equal? (AM/PM-meridiem time) "am")))

It should be rather
(define (AM/PM->24HourClock2 time)
(cond
[(isAM? time) (24HourClock (AM/PM-hours time) (AM/PM-minutes time))]
[else (24HourClock (+ (AM/PM-hours time) 12) (AM/PM-minutes time))]))
(define (AM/PM->24HourClock time)
(let ((hr (AM/PM-hours time))
(min (AM/PM-minutes time))
(mer (AM/PM-meridiem time)))
(cond
[(isAM? time) (24HourClock hr min)]
[else (24HourClock (+ hr 12) min)])))
But since AM/PM-hours and AM/PM-minutes are not defined when defining like you did here with 24HourClock as super class, you have to write:
(define (AM/PM->24HourClock2 time)
(cond
[(isAM? time) (24HourClock (24HourClock-hours time) (24HourClock-minutes time))]
[else (24HourClock (+ (24HourClock-hours time) 12) (24HourClock-minutes time))]))
(define (AM/PM->24HourClock time)
(let ((hr (24HourClock-hours time))
(min (24HourClock-minutes time))
(mer (AM/PM-meridiem time)))
(cond
[(isAM? time) (24HourClock hr min)]
[else (24HourClock (+ hr 12) min)])))
Your problem is that you think struct-slot is itself the value of slot in struct. But it isn't. It is just the getter function for the slot in struct. Therefore, you have to do (struct-slot instance) to get the value of slot in the instance which is of the type struct.
If you want AM/PM->24HourClock, then time is of the type AM/PM.

This is all code put together, it's the same as your response and what was shown:
#lang slideshow
(struct 24HourClock (hours minutes) #:transparent #:mutable
#:guard (lambda (hours minutes err_name)
(if (not (and (>= hours 0) (< hours 24)))
(error err_name "Hours must be between 0 and 24")
(if (not (and (>= minutes 0) (< minutes 60)))
(error err_name "Minutes must be between 0 and 60")
(values hours minutes)))))
(struct AM/PM 24HourClock (meridiem) #:transparent #:mutable
#:guard (lambda (hours minutes meridiem err_name)
(if (not(and(and(number? hours)(> hours 0)(<= hours 12)(number? minutes))))
(error err_name "Hours must be between 1 and 12 : 0")
(if [not (and(string? meridiem)(or
(equal? meridiem "am")
(equal? meridiem "AM")
(equal? meridiem "pm")
(equal? meridiem "PM")))]
(error err_name "Invalid value for meridiem")
(values hours minutes meridiem)))))
(define (isAM? time)
(or (equal? (AM/PM-meridiem time) "AM")
(equal? (AM/PM-meridiem time) "am")))
(define (AM/PM->24HourClock time)
(let ((hr (AM/PM-hours time))
(min (AM/PM-minutes time))
(cond
[(isAM? time) (24HourClock hr min)]
[else (24HourClock (+ hr 12) min)])))
Here's what I use for test cases:
;=======================
; Test Cases
;=======================
; (24HourClock 0 20)
; (24HourClock 24 20)
; (24HourClock 11 60)
; (AM/PM 0 20 "AM")
; (AM/PM 1 20 "Am")
; (AM/PM 2 20 "am")
; (is-AM? 2 20 "am")
; (AM/PM->24HourClock (AM/PM 0 10 "AM"))
; (AM/PM->24HourClock (AM/PM 12 10 "am"))

Related

PDDL temporal modelling help: how to change numeric value in the background?

I'm trying to model and RTS game (AOE2) for an optimal build order and plan using OPTIC. My thought is to represent villagers (workers) as a function, then resources increase depending on the number of villagers. This action works, but I believe is inefficient and the plans are not optimal:
(:durative-action collect_resource
:parameters (?r - resource) ;wood, food etc.
:duration (= ?duration 10)
:condition (and
(at start (> (workers ?r) 0))
(at start (idle ?r))
)
:effect (and
(at start (not (idle ?r)))
(at start (working ?r))
(at end (idle ?r))
(at end (not (working ?r)))
(at end (increase (amount ?r) (* (collect_rate ?r)(workers ?r))))
)
)
I tried this PDDL Durative-Action: Flexible duration, but OPTIC doesn't support non-linear numeric conditions:
(increase (amount ?r) (* (#t)(* (collect_rate ?r)(workers ?r)))
Does anyone have any suggestions for a better approach?
EDIT (error message):
Unfortunately, the planner does not supported non-linear numeric conditions,
effects, or duration constraints, but one or more of these is present in
the problem you have provided. Specifically, the sub-expression:
(3*(workers lumber1)) * (#t)
... was encountered. To use this planner with your problem, you will have
to reformulate it to avoid these.
Domain:
(define (domain aoe2)
(:requirements :strips :typing :fluents :durative-actions :timed-initial-literals)
(:types
location society - object
resource building - location
town_center barracks - building
lumber berries sheep gold - resource
)
(:predicates
(working ?l - location)
(idle ?l - location)
)
(:functions
(idle_villagers ?s - society)
(train_villager_time ?s - society)
(workers ?r - resource)
(walk_time ?r - resource)
(collect_rate ?r - resource)
(amount ?r - resource)
)
(:durative-action train_villager
:parameters (?tc - town_center ?s - society)
:duration (= ?duration (train_villager_time ?s))
:condition (and
(at start (idle ?tc))
)
:effect (and
(at start (not (idle ?tc)))
(at start (working ?tc))
(at end (idle ?tc))
(at end (not (working ?tc)))
(at end (increase (idle_villagers ?s) 1))
)
)
(:durative-action send_idle_to_resource
:parameters (?r - resource ?s - society)
:duration (= ?duration (walk_time ?r))
:condition (and
(at start (> (idle_villagers ?s) 0))
)
:effect (and
(at start (decrease (idle_villagers ?s) 1))
(at end (increase (workers ?r) 1))
)
)
(:action send_resource_to_idle
:parameters (?r - resource ?s - society)
:precondition (and
(> (workers ?r) 0)
)
:effect (and
(increase (idle_villagers ?s) 1)
(decrease (workers ?r) 1)
)
)
(:durative-action collect_resource
:parameters (?r - resource)
:duration (= ?duration 10)
:condition (and
(at start (> (workers ?r) 0))
(at start (idle ?r))
)
:effect (and
(at start (not (idle ?r)))
(at start (working ?r))
(at end (idle ?r))
(at end (not (working ?r)))
(at end (increase (amount ?r) (* (collect_rate ?r)(workers ?r))))
)
)
)
Problem
(define (problem dark_age)
(:domain aoe2)
(:requirements :strips :typing :fluents :durative-actions :timed-initial-literals)
(:objects
tc1 - town_center
mysociety - society
lumber1 - lumber
sheep1 - sheep
)
(:init
(= (train_villager_time mysociety) 25)
(= (idle_villagers mysociety) 0)
(idle tc1)
(= (workers lumber1) 0)
(= (walk_time lumber1) 5)
(= (collect_rate lumber1) 3)
(= (amount lumber1) 0)
(idle lumber1)
(= (workers sheep1) 5)
(= (walk_time sheep1) 0)
(= (collect_rate sheep1) 3)
(= (amount sheep1) 0)
(idle sheep1)
)
(:goal
(and
; (= (idle_villagers mysociety) 1)
; (> (workers lumber1) 1)
(> (amount lumber1) 600)
(> (amount sheep1) 600)
)
)
)

Not overwriting *standard-input* prevents multi-threading

I have a Common Lisp program that behaves differently depending on how I use *standard-input*. Here are the details:
(if input-stream?
(process)
(with-open-file (*standard-input* up :element-type 'unsigned-byte)
(process)))
The process function starts multiple threads. Each thread reads part of the standard input, writes it in a file (all within a lock) and processes the resulting files in parallel (out of the lock). In fact it processes the resulting files in parallel only in case input-stream? is false otherwise it processes them sequentially.
(defun process ()
(let ((psize 4194304)
(stream *standard-input*)
(result-lock (bt:make-lock))
(input-stream-lock (bt:make-lock))
eof)
(flet ((add-job (fname)
(make-thread
#'(lambda ()
(do () (eof)
(when (bt:with-lock-held (input-stream-lock)
(unless eof
(setq eof (write-input-stream-to-file stream fname psize))
t))
(sleep 0.1)
(bt:with-lock-held (result-lock)
(display-progress))))))))
(mapcar
#'join-thread
(loop for i from 1 to 10
collect (add-job
(make-pathname :directory "/tmp"
:name "test"
:type (princ-to-string i))))))))
(let ((counter 0))
(defun display-progress ()
(if (zerop (mod (incf counter) 10))
(format t " ~a " counter)
(write-char #\+))))
(defun write-input-stream-to-file (stream fname psize-bytes)
(with-open-file (out fname
:direction :output
:element-type 'unsigned-byte
:if-exists :supersede)
(do ((byte (read-byte stream nil nil)
(read-byte stream nil nil))
(offset 0 (1+ offset)))
((or (= offset psize-bytes) (null byte)) (not byte))
(write-byte byte out))))
If we create a FIFO (with mkfifo), copy the file to it and run the program with it instead, we again observe parallelism.
The above program is built as a command line utility with ECL and runs on Linux. I run it in one of the following ways:
cat "bigfile" | my-program
my-program "bigfile"
Parallelism happens only in case 2.
The question is why the difference?
Update:
I had mistake in my question. Now it is OK.
Added the process function and described how I run the program

compilation unit aborted, caught 1 fatal ERROR condition?

I have some common lisp code that is behaving oddly. It's a TCP client/server application.
Unless I add (sleep 0.01) or similar at the end of my code, I get the following utterly unhelpful error message after my program completes. It is a very short-lived program, simply hosting a TCP server and testing that it can be connected to.
;; compilation unit aborted; caught 1 fatal ERROR condition
This doesn't happen every time, maybe 80% of the runs cause this. There is no context, no explanation.
Code to reproduce the problem:
(defmacro with-gensyms ((&rest names) &body body)
`(let ,(loop for n in names collect `(,n (gensym)))
,#body))
(defmacro kilobytes (qty)
(* qty 1024))
(defun is-sequence (sequence)
(or (listp sequence) (vectorp sequence)))
(defmacro append-to (seq values)
(with-gensyms (cached-values)
`(let ((,cached-values ,values))
(cond
((is-sequence ,cached-values)
(setf ,seq (append ,seq (coerce ,cached-values 'list))))
(t
(setf ,seq (append ,seq (list ,cached-values))))))))
(defmacro remove-from (seq value)
(with-gensyms (cached-value)
`(let ((,cached-value ,value))
(delete-if (lambda (value) (equalp value ,cached-value)) ,seq))))
(defclass tcp-server ()
((server-socket :initform nil)
(server-threads :initform (list))))
(defgeneric start-server (this &key port bind-address buffer-length))
(defmethod start-server ((this tcp-server) &key (port 0) (bind-address #(127 0 0 1)) (buffer-length (kilobytes 10)))
(with-slots (server-socket server-threads) this
(when server-socket
(error "Server already running"))
(let ((backlog 5))
(setf server-socket (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))
(sb-bsd-sockets:socket-bind server-socket bind-address port)
(sb-bsd-sockets:socket-listen server-socket backlog)
(flet ((handle-connection (client-socket)
(let ((buffer (make-array buffer-length :element-type '(unsigned-byte 8) :fill-pointer t)))
(catch 'eof
(loop
while (sb-bsd-sockets:socket-open-p client-socket)
do (let ((length (nth-value 1 (sb-bsd-sockets:socket-receive client-socket buffer nil))))
(when (eq 0 length)
(throw 'eof nil)))))
(sb-bsd-sockets::socket-close client-socket)
(remove-from server-threads sb-thread:*current-thread*))))
(sb-thread:make-thread
(lambda ()
(loop
while (and server-socket (sb-bsd-sockets:socket-open-p server-socket))
do
(let ((client-socket (sb-bsd-sockets:socket-accept server-socket))) ;; Listen for incoming connections
(append-to server-threads
(sb-thread:make-thread #'handle-connection :name "Connection handler" :arguments client-socket)))) ;; Spawn a process to handle the connection))
(remove-from server-threads sb-thread:*current-thread*))
:name "Server")))
nil))
(defun start-tcp-server (&key (port 0) (bind-address #(127 0 0 1)) (buffer-length (kilobytes 10)))
(let ((server (make-instance 'tcp-server)))
(start-server server :port port :bind-address bind-address :buffer-length buffer-length)
server))
(defgeneric stop-server (this))
(defmethod stop-server ((this tcp-server))
(with-slots (server-socket server-threads) this
(unless server-socket
(error "Server not running"))
(sb-bsd-sockets:socket-close server-socket)
(setf server-socket nil)
(loop for thread in (reverse server-threads)
; do (sb-thread:interrupt-thread thread 'sb-thread:abort-thread))
do (sb-thread:terminate-thread thread))
(loop for thread in (reverse server-threads)
do (sb-thread:join-thread thread :default nil))))
(defgeneric server-running? (this))
(defmethod server-running? ((this tcp-server))
(if (slot-value this 'server-socket) t nil))
(defgeneric server-port (this))
(defmethod server-port ((this tcp-server))
(nth-value 1 (sb-bsd-sockets:socket-name (slot-value this 'server-socket))))
(let ((server-instance nil))
(defun deltabackup-start-server (&key (port 0) (bind-address #(127 0 0 1)) (buffer-length (kilobytes 10)))
(setf server-instance (start-tcp-server :port port
:bind-address bind-address
:buffer-length buffer-length))
nil)
(defun deltabackup-stop-server ()
(unless server-instance
(error "Server not running"))
(stop-server server-instance)
(setf server-instance nil))
(defun deltabackup-server-running? ()
(server-running? server-instance))
(defun deltabackup-server-port ()
(server-port server-instance)))
(defmacro with-tcp-client-connection (address port socket-var &body body-forms)
(with-gensyms (client-socket)
`(let* ((,client-socket (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))
(,socket-var ,client-socket)) ; duplicate this, to prevent body-form modifying the original
(sb-bsd-sockets:socket-connect ,client-socket ,address ,port)
(unless ,client-socket
(error "Failed to connect"))
,#body-forms
(sb-bsd-sockets:socket-close ,client-socket))))
(defmacro with-running-server ( (&optional (port 0)) &body body-forms)
`(progn
(deltabackup-start-server :port ,port)
(unless (deltabackup-server-running?)
(error "Server did not run"))
,#body-forms
(deltabackup-stop-server)))
(with-running-server ()
(with-tcp-client-connection #(127 0 0 1) (deltabackup-server-port) client-socket
client-socket))
Using SBCL common lisp.
The reason you get such a vague error message is that you're running directly from the command line and the error is happening in a thread. If you can get the error to happen in EMACS under SLIME, you'll get more detailed error information.
I ran your program from SLIME like this:
CL-USER> (loop repeat 100 do (load "/tmp/stackoverflow.lisp"))
...and got the following error in SLIME:
Socket error in "accept": EBADF (Bad file descriptor)
[Condition of type SB-BSD-SOCKETS:BAD-FILE-DESCRIPTOR-ERROR]
So, something is going wrong on the server's end when you try to accept the connection. My theory is you have a race condition. In the server thread, you have this:
(loop
while (and server-socket (sb-bsd-sockets:socket-open-p server-socket))
do
(let ((client-socket (sb-bsd-sockets:socket-accept server-socket))) ;; Listen for incoming connections
....))
...and in the client thread, you do this:
(defmethod stop-server ((this tcp-server))
(with-slots (server-socket server-threads) this
(unless server-socket
(error "Server not running"))
(sb-bsd-sockets:socket-close server-socket)
It is possible for sb-bsd-sockets:socket-close to be called and to finish between the call to socket-open-p and socket-accept in the server thread, so that socket-accept gets called on a closed socket.

Playing a sine-wave signal using rsound

I wrote this code after reading the rsound documentation in Racket:
#lang racket
(provide (all-defined-out))
(require rsound)
(define (sunet)
(sine-wave 880))
(signal-play sunet)
(stop)
I used the "sine-wave" function on a 880 Hz frequency and stored it into the function "sunet". Then I applied on it the function "signal-play" that plays signals as sound. I got this error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<network/s>
arguments.:
880
>
Isn't "sine-wave" a function and isn't it taking frequency as an argument?
I read more of the documentation of rsound and read about networks. Apparently you need to create a network with the input signal and the output signal that gets out to something like signal-play.
This would be the code that I needed yesterday:
(define sunet
(network ()
[A5 <= sine-wave 880]
[out = A5]))
(signal-play sunet)
(sleep 3)
(stop)
And with two signals to create a powerchord:
(define sunet
(network ()
[E2 <= sine-wave 82]
[B2 <= sine-wave 123]
[out = (+ E2 B2)]))
(signal-play sunet)
(sleep 3)
(stop)
So, I just answered my own question.
This was harder than I expected. Turns out sine-wave is not a function but a network. The following will play a sine wave.
#lang racket
(require rsound)
(define s (network ()
[a <= sine-wave 880]
[out = a]))
(signal-play s)
I do not know why the following simpler program does not work:
#lang racket
(require rsound)
(define s (network ()
[out = sine-wave 880]))
(signal-play s)

How to set the priority to thread in LISP?

(defvar firstnumber)
(defvar secondnumber)
(defvar length1)
(defvar mulb)
(defvar var1)
(defvar num1)
(defvar num2)
(defvar addition)
(defvar subs)
(defvar muls)
(defvar divs)
(defun acceptnumber()
(write-line "Enter the first number:")
(force-output t)
(setf firstnumber(read))
(write-line "Enter the second number:")
(force-output t)
(setf secondnumber(read))
(setf length1(integer-length secondnumber))
)
(defun add(num1 num2)
(setf addition(+ num1 num2))
(write-line "Addition of two numbers:")
(write addition)
(write-line " " )
)
(defun sub(num1 num2)
(setf subs(- num1 num2))
(write-line "Substraction of two numbers:")
(write subs)
(write-line " ")
)
(defun mul(num1 num2)
(setf muls(* num1 num2))
(write-line "Multiplication of two numbers:")
(write muls)
(write-line " ")
)
(defun div(num1 num2)
(setf divs(/ num1 num2))
(write-line "Division of two numbers:")
(write divs)
(write-line " ")
)
(defun binarymul(num1 num2)
(setf mulb 0)
(
loop for i from 1 to length1 do
(
if(= 1 (logand num2 1))
(setf mulb(+ mulb num1))
)
(setf num2(ash num2 -1))
(setf num1(ash num1 1))
)
(write-line "Binary Multiplication ::")
(write mulb)
(write-line " ")
(write-line "In binary form::")
(setf var1(format nil "~B" mulb ))
(write-line var1)
)
(acceptnumber)
(sb-thread:make-thread(lambda()(binarymul firstnumber secondnumber)))
(sb-thread:make-thread(lambda()(add firstnumber secondnumber)))
(sb-thread:make-thread(lambda()(sub firstnumber secondnumber)))
(sb-thread:make-thread(lambda()(mul firstnumber secondnumber)))
(sb-thread:make-thread(lambda()(div firstnumber secondnumber)))
I started learning with LISP concurrent programming. I wrote a simple calculation program with sb-thread. Now i want to set the priority for each thread. Ex like set priority higher ti binarymul function etc.
Can I set priority of sb-thread ? If yes How?
SBCL's manual says (emphasis added):
12 Threading
SBCL supports a fairly low-level threading interface that maps onto
the host operating system’s concept of threads or lightweight
processes. This means that threads may take advantage of hardware
multiprocessing on machines that have more than one CPU, but it does
not allow Lisp control of the scheduler. This is found in the
SB-THREAD package.
I think that thread priority would typically require some access to the scheduler, so you won't have the ability to set thread priority with SBCL.

Resources