Application not a procedure error in Racket - racket

I'm trying to write a function called dates_in_month that takes a list of dates and a month and returns a list holding the dates from the argument list of dates that are in the month. The returned list should contain dates in the order they were originally given. However I'm new to Racket and I'm getting the error "application: not a procedure;
expected a procedure that can be applied to arguments
given: 5"
Does anyone know what this means or how to fix it? If anyone can point out my error that'd be much appreciated.
This is the code i am working on with my test case at the bottom.
#lang racket
(define (append lst1 lst2)
(if (null? lst1)
lst2
(cons (car lst1) (append (cdr lst1) lst2))))
(define (dates_in_month dates month)
(if (null? dates)
'()
(let ((date (car dates)))
(if (= (month date) month)
(cons date (dates_in_month (cdr dates) month))
(dates_in_month (cdr dates) month)))))
(define test-dates '(#(1 1 2000) #(2 2 2000) #(3 3 2000) #(4 4
2000) #(5 5 2000) #(6 6 2000)))
(dates_in_month test-dates 5)

Your error is caused by calling (month date)- month should be some procedure, which you want to call with the argument date (date will be some vector), but month has value 5, that isn't a procedure.
That is the meaning of the error message:
"application: not a procedure; expected a procedure that can be applied to arguments given: 5"
I guess you need to get somehow the second element of the vector date and then compare it with the value of month. You should use the function vector-ref- example:
> (vector-ref #(5 5 2000) 1)
5
See also DrRacket docs for Vectors for other functions for working with vectors.
And if you can, you could also use filter instead of recursion. Here are both variants:
(define (dates-in-month dates month)
(if (null? dates)
'()
(let ((date (car dates)))
(if (= (vector-ref date 1) month)
(cons date (dates-in-month (cdr dates) month))
(dates-in-month (cdr dates) month)))))
(define (dates-in-month2 dates month)
(filter (lambda (date) (= (vector-ref date 1) month))
dates))
(define test-dates '(#(1 1 2000) #(2 2 2000) #(3 3 2000) #(4 4 2000) #(5 5 2000) #(6 6 2000)))
(dates-in-month test-dates 5)
(dates-in-month2 test-dates 5)
And append is already part of the DrRacket language, so you don't have to reimplement it.

Related

How to list all the leap year from 1800 in LISP?

I have this code below which takes one parameter and prints all the list of leap year in reverse order. how can I make it take 1800 as default input and just run command (leap) to list all the leap years from 1800-2018?
CODE:
(defun leap (q)
(if (< q 1800)
(RETURN-FROM leap nil)
)
(leap (- q 1))
(if (leapyear q)
(push q mylist)
)
mylist
)
(reverse(leap 2018))
I can't completely understand what you are trying to do, but:
(defun leapyearp (y)
;; is Y a leap year, as best we can tell?
(= (nth-value 3 (decode-universal-time
(+ (encode-universal-time 0 0 0 28 2 y)
(* 60 60 24))))
29))
(defun leapyears (&key (start 1800) (end (nth-value 5 (get-decoded-time))))
;; all the leap years in a range
(loop for y from start to end
if (leapyearp y) collect y))

How to use foldr in Racket to eliminate numbers in a list that are greater than any subsequent numbers

I have to write a function in Racket using foldr that will take a list of numbers and remove list elements that are larger than any subsequent numbers.
Example: (eliminate-larger (list 1 2 3 5 4)) should produce (1 2 3 4)
I can do it without using foldr or any higher-order functions but I can't figure it out with foldr. Here's what I have:
(define (eliminate-larger lst)
(filter (lambda (z) (not(equal? z null)))
(foldr (lambda (x y)
(cons (determine-larger x (rest lst)) y)) null lst))
)
(define (determine-larger value lst)
(if (equal? (filter (lambda (x) (>= x value)) lst) lst)
value
null)
)
determine-larger will take in a value and a list and return that value if it is greater than or equal to all elements in the list. If not, it returns null. Now the eliminate-larger function is trying to go through the list and pass each value to determine-larger along with a list of every number after it. If it is a "good" value it will be returned and put in the list, if it's not a null is put in the list. Then at the end the nulls are being filtered out. My problem is getting the list of numbers that follow after the current number in the foldr function. Using "rest lst" doesn't work since it's not being done recursively like that. How do I get the rest of the numbers after x in foldr?
I really hope I'm not doing your homework for you, but here goes ...
How do I get the rest of the numbers after x in foldr?
Because you're consuming the list from the right, you can structure your accumulator such that "the rest of the numbers after x" are available as its memo argument.
(define (eliminate-larger lst)
(foldr
(lambda (member memo)
(if (andmap (lambda (n) (<= member n)) memo)
(cons member memo)
memo))
'()
lst))
(eliminate-larger (list 1 2 3 5 4)) ;; (1 2 3 4)
This is admittedly a naive solution, as you're forced to traverse the entire accumulator with each iteration, but you could easily maintain a max value, in addition to your memo, and compare against that each time through.
Following works:
(define (el lst)
(define (inner x lsti)
(if(empty? lsti) (list x)
(if(<= x (apply max lsti))
(cons x lsti)
lsti)))
(foldr inner '() lst))
(el (list 1 2 3 5 4))
Output:
'(1 2 3 4)
The cond version may be preferable:
(define (el lst)
(define (inner x lsti)
(cond
[(empty? lsti) (list x)]
[(<= x (apply max lsti)) (cons x lsti)]
[else lsti] ))
(foldr inner '() lst) )

Decompose a list of numbers into digits

I am trying to create a list of digits starting from a list of numbers.
For example I want to break (11 4 6) into (1 5 6) by dividing the head of the list to 10 if the head is >= 10 and adding 1 to the next element.
My code looks like this
(defun createparameters (l)
(cond ((null l) l)
((> 9 (car l)) (setf (car l) (mod (car l ) 10))
(setf (cadr l) (+ (cadr l) 1)))
(t (createparameters (cdr l)))))
but it does not change my referenced list.
Help would be greatly appreciated.
You write that you want the operation done if the first element is greater than 9, but in your code you are doing the opposite. (> 9 (car l)) is the same as infix 9 > (car l) so you do your thing when first element is 8 or lower.
Here is a functional version of your code that continues to process the next sublist:
(defun createparameters (l)
(cond ((null l) l)
((and (consp l) (< 9 (car l)))
(cons (mod (car l ) 10)
(createparameters
(cons (+ (cadr l) 1)
(cddr l)))))
(t (cons (car l)
(createparameters (cdr l))))))
(defparameter test (list 11 11 2 3))
(setf test (createparameters test))
test ; ==> (1 2 3 3)
Here is a modified mutating version (similar to your code):
(defun createparameters (l)
(cond ((null l) l)
((< 9 (car l)) (setf (car l) (mod (car l ) 10))
(setf (cadr l) (+ (cadr l) 1))
(createparameters (cdr l)))
(t (createparameters (cdr l)))))
(defparameter test (list 11 11 2 3))
(createparameters test)
test ; ==> (1 2 3 3)
I'm starting to wonder if this is a carry so that the first element is the least significant digit and the last is the most. If so just adding one will only work if the number always are below 20 and the code will not work if the last digit became 10 or higher.
A direct approach
Here's a version that performs the task directly.
(defun decompose (digits)
"Given a list of digits (least-significant digit first), return a
list of normalized digits, i.e., where each digit is less than 10."
(do ((digits digits (rest digits)) ; iterate through the digits.
;; There's no initial digit, and the carry is initially 0.
(carry 0) (digit)
;; The result starts as '(), and adds a digit on each successive
;; iteration, where the digit is computed in the loop body.
(result '() (list* digit result)))
;; End when there are no digits left. Most of the result is
;; simply the reversed result, but if there's a non-zero carry
;; at the end, put it into a list and decompose it, too.
((endp digits)
(nreconc result (if (zerop carry) '()
(decompose (list carry)))))
;; At each iteration, add the first digit to the carry, and divide
;; by 10. The quotient is the carry for the next iteration, and
;; the remainder is the digit that's added into the results.
(multiple-value-setq (carry digit)
(floor (+ carry (first digits)) 10))))
(decompose '(10005 2 3))
;=> (5 2 3 0 1)
(decompose '(11 2 4))
;=> (1 3 4)
(decompose '(23 0))
;=> (3 2)
(decompose '(11 11 4 6))
;=> (1 2 5 6)
A modular approach
A more modular approach might break this down into two parts. First, given a list of digits, each of which might be greater than 9, we can reconstruct the original number as a number (i.e., not as a list of digits). This is pretty straightforward:
(defun digits->number (digits)
(reduce (lambda (digit number)
(+ digit (* 10 number)))
digits
:from-end t))
(digits->number '(1 2 3 4))
;=> 4321
(digits->number '(205 3))
;=> 235
Now, converting a number into a list of digits isn't too hard either.
(defun number->digits (number)
(do ((digit)
(digits '() (list* digit digits)))
((zerop number) (nreverse digits))
(multiple-value-setq (number digit)
(floor number 10))))
(number->digits 1024)
;=> (4 2 0 1)
(number->digits 8923)
;=> (3 2 9 8)
Now, we can observe that digits->number converts the digits list into the number in the form that we need, even when there are 'digits' that are greater than 9. number->digits always produces a representation where all the digits are less than 10. Thus, we can also implement decompose as number->digits of digits->number.
(defun decompose (digits)
(number->digits (digits->number digits)))
(decompose '(10005 2 3))
;=> (5 2 3 0 1)
(decompose '(11 2 4))
;=> (1 3 4)
(decompose '(23 0))
;=> (3 2)
(decompose '(11 11 4 6))
;=> (1 2 5 6)
As an interesting observation, I think you can say that the space of input for decompose is lists of non-negative integers, and that each list of non-negative integers less than 10 is a fixed point of decompose.

How to count days excluding weekends and holidays in Emacs calendar

In Emacs calendar, one can count days between two dates (including both the start and the end date) using the M-= which runs the command calendar-count-days-region. How can I count days excluding the weekends (Saturday and Sunday) and if defined holidays coming from the variables: holiday-general-holidays and holiday-local-holidays?
I think this essentially breaks down into three parts:
Count the days in a region
subtract the weekend days
subtract the holidays
Emacs already has the first part covered with M-= (calendar-count-days-region), so let's take a look at that function.
Helpful, but unfortunately it reads the buffer and sends the output directly. Let's make a generalized version which takes start and end date parameters and returns the number of days instead of printing them:
(defun my-calendar-count-days(d1 d2)
(let* ((days (- (calendar-absolute-from-gregorian d1)
(calendar-absolute-from-gregorian d2)))
(days (1+ (if (> days 0) days (- days)))))
days))
This is pretty much just a copy of the calendar-count-days-region function, but without the buffer reading & writing stuff. Some tests:
(ert-deftest test-count-days ()
"Test my-calendar-count-days function"
(should (equal (my-calendar-count-days '(5 1 2014) '(5 31 2014)) 31))
(should (equal (my-calendar-count-days '(12 29 2013) '(1 4 2014)) 7))
(should (equal (my-calendar-count-days '(2 28 2012) '(3 1 2012)) 3))
(should (equal (my-calendar-count-days '(2 28 2014) '(3 1 2014)) 2)))
Now, for step 2, I can't find any built-in function to calculate weekend days for a date range (surprisingly!). Luckily, this /might/ be pretty simple when working with absolute dates. Here's a very naive attempt which simply loops through all absolute dates in the range and looks for Saturdays & Sundays:
(defun my-calendar-count-weekend-days(date1 date2)
(let* ((tmp-date (if (< date1 date2) date1 date2))
(end-date (if (> date1 date2) date1 date2))
(weekend-days 0))
(while (<= tmp-date end-date)
(let ((day-of-week (calendar-day-of-week
(calendar-gregorian-from-absolute tmp-date))))
(if (or (= day-of-week 0)
(= day-of-week 6))
(incf weekend-days ))
(incf tmp-date)))
weekend-days))
That function should be optimized since it does a bunch of unnecessary looping (e.g. we know that the 5 days after Sunday won't be weekend days, so there is no need to convert & test them), but for the purpose of this example I think it's pretty clear and simple. Good Enough for now, indeed. Some tests:
(ert-deftest test-count-weekend-days ()
"Test my-calendar-count-weekend-days function"
(should (equal (my-calendar-count-weekend-days
(calendar-absolute-from-gregorian '(5 1 2014))
(calendar-absolute-from-gregorian '(5 31 2014))) 9))
(should (equal (my-calendar-count-weekend-days
(calendar-absolute-from-gregorian '(4 28 2014))
(calendar-absolute-from-gregorian '(5 2 2014))) 0))
(should (equal (my-calendar-count-weekend-days
(calendar-absolute-from-gregorian '(2 27 2004))
(calendar-absolute-from-gregorian '(2 29 2004))) 2)))
Lastly, we need to know the holidays in the range, and emacs provides this in the holiday-in-range function! Note that this function calls calendar-holiday-list to determine which holidays to include, so if you really want to search only holiday-general-holidays and holiday-local-holidays you would need to set your calendar-holidays variable appropriately. See C-h v calendar-holidays for the details.
Now we can wrap all this up in a new interactive function which does the three steps above. This is essentially another modified version of calendar-count-days-region that subtracts weekends and holidays before printing the results (see edit below before running):
(defun calendar-count-days-region2 ()
"Count the number of days (inclusive) between point and the mark
excluding weekends and holidays."
(interactive)
(let* ((d1 (calendar-cursor-to-date t))
(d2 (car calendar-mark-ring))
(date1 (calendar-absolute-from-gregorian d1))
(date2 (calendar-absolute-from-gregorian d2))
(start-date (if (< date1 date2) date1 date2))
(end-date (if (> date1 date2) date1 date2))
(days (- (my-calendar-count-days d1 d2)
(+ (my-calendar-count-weekend-days start-date end-date)
(my-calendar-count-holidays-on-weekdays-in-range
start-date end-date)))))
(message "Region has %d workday%s (inclusive)"
days (if (> days 1) "s" ""))))
I'm sure someone more knowledgeable about lisp/elisp could simplify/improve these examples considerably, but I hope it at least serves as a starting point.
Actually, now that I've gone through it, I expect somebody to come along any minute and point out that there is an emacs package that already does this...
Edit: DOH!, Bug #001: If a holiday falls on a weekend, that day is removed twice...
Once solution would be to simply wrap holiday-in-range so we can eliminate holidays which were already removed for being on a weekend:
(defun my-calendar-count-holidays-on-weekdays-in-range (start end)
(let ((holidays (holiday-in-range start end))
(counter 0))
(dolist (element holidays)
(let ((day (calendar-day-of-week (car element))))
(if (and (> day 0)
(< day 6))
(incf counter))))
counter))
I've updated the calendar-count-days-region2 above to use this new function.

How to implement the 24 solar terms in Lisp with Emacs Calendar

I tried to learn the code in cal-china.el in Emacs source code and found the following code:
;;;###holiday-autoload
(defun holiday-chinese-winter-solstice ()
"Date of Chinese winter solstice, if visible in calendar.
Returns (((MONTH DAY YEAR) TEXT)), where the date is Gregorian."
(when (memq displayed-month '(11 12 1)) ; is December visible?
(list (list (calendar-gregorian-from-absolute
(calendar-chinese-zodiac-sign-on-or-after
(calendar-absolute-from-gregorian
(list 12 15 (if (eq displayed-month 1)
(1- displayed-year)
displayed-year)))))
"Winter Solstice Festival"))))
This code is used to calculate the winter solstice. I also knew that these 24 solar terms are needed for calculating Chinese calendar. So I wonder how to calculate all the 24 solar terms in Lisp.
Thank you.
For anyone interested in Chinese calendar, please refer to this repo for details.
https://github.com/xwl/cal-china-x
The solar terms can be calculated with the following code after you install cal-china-x
;;;###autoload
(defun holiday-solar-term (solar-term str)
"A holiday(STR) on SOLAR-TERM day.
See `cal-china-x-solar-term-name' for a list of solar term names ."
(cal-china-x-sync-solar-term displayed-year)
(let ((terms cal-china-x-solar-term-alist)
i date)
(while terms
(setq i (car terms)
terms (cdr terms))
(when (string= (cdr i) solar-term)
(let ((m (caar i))
(y (cl-caddar i)))
;; displayed-year, displayed-month is accurate for the centered month
;; only. Cross year view: '(11 12 1), '(12 1 2)
(when (or (and (cal-china-x-cross-year-view-p)
(or (and (= displayed-month 12)
(= m 1)
(= y (1+ displayed-year)))
(and (= displayed-month 1)
(= m 12)
(= y (1- displayed-year)))))
(= y displayed-year))
(setq terms '()
date (car i))))))
(holiday-fixed (car date) (cadr date) str)))