LISP - Check Roman Numeral Converter for valid Roman Numeral - validation

I have a lisp program that converts Roman Numerals into decimal form. It works great for valid inputs, however I'm not sure how to check to see if the input is a valid Roman Numeral. Currently when given an invalid input ("MIM") for example, it still tries to incorrectly convert it. I need it to instead return an ERROR message.
(defun mapRomanToDecimal (chars nums string)
(loop as char across string
as i = (position char chars)
collect (and i (nth i nums))))
(defun parseThroughRoman (R)
(loop with nums = (mapRomanToDecimal "IVXLCDM" '(1 5 10 50 100 500 1000) R)
as (A B) on nums if A sum (if (and B (< A B)) (- A) A)))
(defun romanToDecimal (RomanNumeral)
(format t "~d~%" (parseThroughRoman (numlist-to-string RomanNumeral))))
(defun numlist-to-string (lst)
(when lst
(concatenate 'string
(write-to-string (car lst)) (numlist-to-string (cdr lst)))))
(romanToDecimal '(C D V)) -> 405
(romanToDecimal '(M I M)) -> 1999

A little bit about style...
data type conversion is often not necessary
code can easily be more generic
Example:
(defvar *roman-chars* "IVXLCDM")
(defvar *roman-nums* '(1 5 10 50 100 500 1000))
(defun roman-numeral-to-decimal (roman-numeral)
(let ((i (position (coerce roman-numeral 'character) *roman-chars*)))
(and i (nth i *roman-nums*))))
(defun map-roman-numerals-to-decimal (roman-numerals)
(map 'list #'roman-numeral-to-decimal roman-numerals))
(defun roman-to-decimal (roman)
(loop as (A B) on (map-roman-numerals-to-decimal roman)
if A sum (if (and B (< A B)) (- A) A)))
This means you can use it with lists of symbols/characters/strings, strings, vectors symbols/characters/strings:
CL-USER 20 > (roman-to-decimal '(C D V))
405
CL-USER 21 > (roman-to-decimal '("C" "D" "V"))
405
CL-USER 22 > (roman-to-decimal '(#\C #\D #\V))
405
CL-USER 23 > (roman-to-decimal "CDV")
405
CL-USER 24 > (roman-to-decimal #(c d v))
405

Related

Idiomatic way to decode hex-formatted strings in Racket Scheme or other schemes

My input data is a hex-formatted string without restriction on the length. I need to process the bytes individually. As an example, for "AABBCCDDEEFF" I want to process AA, then BB, CC, DD, EE, FF.
Using Common Lisp, we can use LOOP:
(loop for (a b) on list do [processing])
In Racket Scheme, I wrote this solution:
(define (split-string str)
(let ((bit #t)
(char-1 null)
(char-2 null)
(result '()))
(for ((char str))
(if bit
(begin
(set! bit #f)
(set! char-1 char))
(begin
(set! bit #t)
(set! char-2 char)
(set! result (cons (~a char-1 char-2) result)))))
;; return
(reverse result)))
(split-string "AABBCCDDEEFF")
;; '("AA" "BB" "CC" "DD" "EE" "FF")
I feel like this is not idiomatic Racket or Scheme code. I wrote a second solution:
(define (split-string2 str)
(bytes->list (integer->integer-bytes (string->number str 16) 8 false)))
(split-string2 "AABBCCDDEEFF")
;; '(255 238 221 204 187 170 0 0)
What is the idiomatic way to perform this kind of operations in Racket Scheme and more generally in Lisp?
There are a bunch of ways of doing this in Racket (as opposed to Scheme more generally): the notions you want are sequences, streams and generators.
First of all a function to compute hex digits from characters (this may exist in Racket, but I was too lazy to find it, and this works):
(define (char->hex-digit c)
;; Turn a character into a hex digit
(cond [(char<=? #\0 c #\9)
(- (char->integer c) (char->integer #\0))]
[(char<=? #\A c #\F)
(+ 10 (- (char->integer c) (char->integer #\A)))]
[(char<=? #\a c #\f)
(+ 10 (- (char->integer c) (char->integer #\a)))]
[else
(error 'char->hex-digit "~A is not a hex character" c)]))
Now here is a simple-minded approach to turning a hex string into a list of bytes which works by creating two sequences from the string, one of which picks out the high and the other the low digit in each pair:
(define (hex-string->byte-list hs)
(for/list ([h (in-string hs 0 #f 2)]
[l (in-string hs 1 #f 2)])
(+ (* (char->hex-digit h) 16) (char->hex-digit l))))
Obviously depending on which variant of for you use you can construct different results.
Examples:
> (hex-string->byte-list "F00D")
'(240 13)
> (hex-string->byte-list "0102030405060708090a0b0C0D0F")
'(1 2 3 4 5 6 7 8 9 10 11 12 13 15)
> (hex-string->byte-list "01xa")
; char->hex-digit: x is not a hex character [,bt for context]
Another approach is to use in-slice:
(define (hex-string->byte-list hs)
(for/list ([hl (in-slice 2 (in-string hs))])
(+ (* (char->hex-digit (first hl)) 16) (char->hex-digit (second hl)))))
And there are lots of other ways of doing this, including creating your own sequence or stream types, so you could write (for/list ([b (in-hex-stream-bytes ...)]) b).
Note that the Common Lisp version would not work since the input is a string; in order to use the same approach you should first convert the string to a list of characters; secondly, you would need to add a by directive to advance over the list by cddr, i.e. skipping the already read b.
That would finally look like:
(loop
for (a b) on (coerce "AABBCCDDEEFF" 'list) by #'cddr
collect (parse-integer (coerce (vector a b) 'string)
:radix 16))
=> (170 187 204 221 238 255)
But, this is a bit wasteful, parse-integer admits :start and :end arguments, so you do not need to allocate any intermediate list or string (apart for the last collect; you could skip it too and just process the value directly):
(loop
with string = "AABBCCDDEEFF"
with size = (length string)
initially (assert (evenp size))
for start from 0 by 2
for end from 2 by 2 upto size
collect (parse-integer string :start start :end end :radix 16))
=> (170 187 204 221 238 255)
One of the idiomatic ways would be to use recursion (preserving the same functionality as your split-string) as follows:
(define (split-string-recur str)
(cond [(or (string=? str "") (string=? "" (substring str 1))) '()]
[else (cons (substring str 0 2) (split-string-recur (substring str 2)))]))
and a tail-recursive version:
(define (split-string-trecur str)
(define (split-string-recur str acc)
(cond [(or (string=? str "") (string=? "" (substring str 1))) acc]
[else (split-string-recur (substring str 2) (append acc (list (substring str 0 2))))]))
(split-string-recur str '()))
The for/list approach with in-slice on in-string sequence (mentioned here) is also an idiomatic approach.
Note that we can also use a small interface on strings like the following to make it more readable:
(module string-util typed/racket
(provide (all-defined-out))
(: empty-string? : (-> String Boolean))
(define (empty-string? s)
(string=? "" s))
(: string-first : (-> String String))
(define (string-first s)
(substring s 0 1))
(: string-last : (-> String String))
(define (string-last s)
(substring s (- (string-length s) 1) (string-length s)))
(: string-rest : (-> String String))
(define (string-rest s)
(substring s 1 (string-length s))))
(require 'string-util)
(define (split-string-recur str)
(cond [(or (empty-string? str) (empty-string? (string-rest str))) '()]
[else (cons (string-append (string-first str) (string-first (string-rest str)))
(split-string-recur (string-rest (string-rest str))))]))
CL-USER 2 > (defun split-string (string)
(loop for i from 0 below (length string) by 2
collect (subseq string i (+ i 2))))
SPLIT-STRING
CL-USER 3 > (split-string "AABBCCDDEEFF")
("AA" "BB" "CC" "DD" "EE" "FF")
CL-USER 4 > (mapcar (lambda (s) (parse-integer s :radix 16)) *)
(170 187 204 221 238 255)

Transform a natural number to a specific base and return it as a list

I want to show the result of my function as a list not as a number.
My result is:
(define lst (list ))
(define (num->base n b)
(if (zero? n)
(append lst (list 0))
(append lst (list (+ (* 10 (num->base (quotient n b) b)) (modulo n b))))))
The next error appears:
expected: number?
given: '(0)
argument position: 2nd
other arguments...:
10
I think you have to rethink this problem. Appending results to a global variable is definitely not the way to go, let's try a different approach via tail recursion:
(define (num->base n b)
(let loop ((n n) (acc '()))
(if (< n b)
(cons n acc)
(loop (quotient n b)
(cons (modulo n b) acc)))))
It works as expected:
(num->base 12345 10)
=> '(1 2 3 4 5)

Reversing an integer

I am trying to write a function which takes an input number and outputs the number in reverse order.
Ie:
Input -> 25
Output -> 52
Input -> 125
Output -> 521
I am new to lisp, if its helpful here is the working function in c++
function.cpp
int revs(int rev, int n)
{
if (n <= 0)
return rev;
return revs((rev * 10) + (n % 10), n/10);
}
I have written it in Racket as follows:
(define (revs rev n)
(if (<= n 0)
rev
(revs (+ (* rev 10) (modulo n 10)) (/ n 10))))
But when I run it with (revs 0 125) I get this error:
modulo: contract violation
expected: integer?
given: 25/2
argument position: 1st
other arguments...:
10
Certainly I am doing something incorrect here, but I am unsure of what I am missing.
The division operator / doesn't do integer division, but general division, so when you call, e.g., (/ 25 2), you don't get 12 or 13, but rather the rational 25/2. I think you'd want quotient instead, about which the documentation has:
procedure (quotient n m) → integer?
n : integer?
m : integer?
Returns (truncate (/ n m)). Examples:
> (quotient 10 3)
3
> (quotient -10.0 3)
-3.0
> (quotient +inf.0 3)
quotient: contract violation
expected: integer?
given: +inf.0
argument position: 1st
other arguments...:
3
Treating the operation lexicographically:
#lang racket
(define (lexicographic-reverse x)
(string->number
(list->string
(reverse
(string->list
(number->string x))))))
Works[1] for any of Racket's numerical types.
[edit 1] "Works," I realized, is context dependent and with a bit of testing shows the implicit assumptions of the operation. My naive lexicographic approach makes a mess of negative integers, e.g. (lexicographic-reverse -47) will produce an error.
However, getting an error rather than -74 might be better when if I am reversing numbers for lexicographic reasons rather than numerical ones because it illuminates the fact that the definition of "reversing a number" is arbitrary. The reverse of 47 could just as well be -74 as 74 because reversing is not a mathematical concept - even though it might remind me of XOR permutation.
How the sign is handled is by a particular reversing function is arbitrary.
#lang racket
;; Reversing a number retains the sign
(define (arbitrary1 x)
(define (f n)
(string->number
(list->string
(reverse
(string->list
(number->string n))))))
(if (>= x 0)
(f x)
(- (f (abs x)))))
;; Reversing a number reverses the sign
(define (arbitrary2 x)
(define (f n)
(string->number
(list->string
(reverse
(string->list
(number->string n))))))
(if (>= x 0)
(- (f x))
(f (abs x))))
The same considerations extend to Racket's other numerical type notations; decisions about reversing exact, inexact, complex, are likewise arbitrary - e.g. what is the reverse of IEEE +inf.0 or +nan.0?
Here is my solution for this problem
(define (reverseInt number)
(define (loop number reversedNumber)
(if (= number 0)
reversedNumber
(let ((lastDigit (modulo number 10)))
(loop (/ (- number lastDigit) 10) (+ (* reversedNumber 10) lastDigit)))))
(loop number 0))
Each time we multiply the reversed number by 10 and add the last digit of number.
I hope it makes sense.
A R6RS version (will work with R7RS with a little effort)
#!r6rs
(import (rnrs)
(srfi :8))
(define (numeric-reverse n)
(let loop ((acc 0) (n n))
(if (zero? n)
acc
(receive (q r) (div-and-mod n 10)
(loop (+ (* acc 10) r) q)))))
A Racket implementation:
#!racket
(require srfi/8)
(define (numeric-reverse n)
(let loop ((acc 0) (n n))
(if (zero? n)
acc
(receive (q r) (quotient/remainder n 10)
(loop (+ (* acc 10) r) q)))))
With recursion, you can do something like:
#lang racket
(define (reverse-num n)
(let f ([acc 0]
[n n])
(cond
[(zero? n) acc]
[else (f (+ (* acc 10) (modulo n 10)) (quotient n 10))])))

Filter a list into two parts by a predicate

I want to do
(filter-list-into-two-parts #'evenp '(1 2 3 4 5))
; => ((2 4) (1 3 5))
where a list is split into two sub-lists depending on whether a predicate evaluates to true. It is easy to define such a function:
(defun filter-list-into-two-parts (predicate list)
(list (remove-if-not predicate list) (remove-if predicate list)))
but I would like to know if there is a built-in function in Lisp that can do this, or perhaps a better way of writing this function?
I don't think there is a built-in and your version is sub-optimal because it traverses the list twice and calls the predicate on each list element twice.
(defun filter-list-into-two-parts (predicate list)
(loop for x in list
if (funcall predicate x) collect x into yes
else collect x into no
finally (return (values yes no))))
I return two values instead of the list thereof; this is more idiomatic (you will be using multiple-value-bind to extract yes and no from the multiple values returned, instead of using destructuring-bind to parse the list, it conses less and is faster, see also values function in Common Lisp).
A more general version would be
(defun split-list (key list &key (test 'eql))
(let ((ht (make-hash-table :test test)))
(dolist (x list ht)
(push x (gethash (funcall key x) ht '())))))
(split-list (lambda (x) (mod x 3)) (loop for i from 0 to 9 collect i))
==> #S(HASH-TABLE :TEST FASTHASH-EQL (2 . (8 5 2)) (1 . (7 4 1)) (0 . (9 6 3 0)))
Using REDUCE:
(reduce (lambda (a b)
(if (evenp a)
(push a (first b))
(push a (second b)))
b)
'(1 2 3 4 5)
:initial-value (list nil nil)
:from-end t)
In dash.el there is a function -separate that does exactly what you ask:
(-separate 'evenp '(1 2 3 4)) ; => '((2 4) (1 3))
You can ignore the rest of the post if you use -separate. I had to implement Haskell's partition function in Elisp. Elisp is similar1 in many respects to Common Lisp, so this answer will be useful for coders of both languages. My code was inspired by similar implementations for Python
(defun partition-push (p xs)
(let (trues falses) ; initialized to nil, nil = '()
(mapc (lambda (x) ; like mapcar but for side-effects only
(if (funcall p x)
(push x trues)
(push x falses)))
xs)
(list (reverse trues) (reverse falses))))
(defun partition-append (p xs)
(reduce (lambda (r x)
(if (funcall p x)
(list (append (car r) (list x))
(cadr r))
(list (car r)
(append (cadr r) (list x)))))
xs
:initial-value '(() ()) ; (list nil nil)
))
(defun partition-reduce-reverse (p xs)
(mapcar #'reverse ; reverse both lists
(reduce (lambda (r x)
(if (funcall p x)
(list (cons x (car r))
(cadr r))
(list (car r)
(cons x (cadr r)))))
xs
:initial-value '(() ())
)))
push is a destructive function that prepends an element to list. I didn't use Elisp's add-to-list, because it only adds the same element once. mapc is a map function2 that doesn't accumulate results. As Elisp, like Common Lisp, has separate namespaces for functions and variables3, you have to use funcall to call a function received as a parameter. reduce is a higher-order function4 that accepts :initial-value keyword, which allows for versatile usage. append concatenates variable amount of lists.
In the code partition-push is imperative Common Lisp that uses a widespread "push and reverse" idiom, you first generate lists by prepending to the list in O(1) and reversing in O(n). Appending once to a list would be O(n) due to lists implemented as cons cells, so appending n items would be O(n²). partition-append illustrates adding to the end. As I'm a functional programming fan, I wrote the no side-effects version with reduce in partition-reduce-reverse.
Emacs has a profiling tool. I run it against these 3 functions. The first element in a list returned is the total amount of seconds. As you can see, appending to list works extremely slow, while the functional variant is the quickest.
ELISP> (benchmark-run 100 (-separate #'evenp (number-sequence 0 1000)))
(0.043594004 0 0.0)
ELISP> (benchmark-run 100 (partition-push #'evenp (number-sequence 0 1000)))
(0.468053176 7 0.2956386049999793)
ELISP> (benchmark-run 100 (partition-append #'evenp (number-sequence 0 1000)))
(7.412973128 162 6.853687342999947)
ELISP> (benchmark-run 100 (partition-reduce-reverse #'evenp (number-sequence 0 1000)))
(0.217411618 3 0.12750035599998455)
References
Differences between Common Lisp and Emacs Lisp
Map higher-order function
Technical Issues of Separation in Function Cells and Value Cells
Fold higher-order function
I don't think that there is a partition function in the common lisp standard, but there are libraries that provide such an utility (with documentation and source).
CL-USER> (ql:quickload :arnesi)
CL-USER> (arnesi:partition '(1 2 3 4 5) 'evenp 'oddp)
((2 4) (1 3 5))
CL-USER> (arnesi:partition '(1 2 b "c") 'numberp 'symbolp 'stringp)
((1 2) (B) ("c"))

read a polynomial from input stream in lisp

Reads a polynomial from a list pl (see below for input format) and returns it as a sorted list.
Example: (ReadPolynomial2 '(99 0 17 200 3 150 8 200 0 0)) should return ((99 0) (3 150) (25 200))
I don't know if you still need it, but here it is a possible solution:
(defun ReadPolynomial2 (lst)
(let ((even-positions (loop for p in (cdr lst) by #'cddr collect p)))
(loop for p in (remove-duplicates even-positions)
collect (list (loop for x on lst by #'cddr
when (= p (second x))
sum (first x)) p))))

Resources