Evaluating arguments in Clojure macro - macros

I'd like to build a function, which, given a 2D matrix and some element from that matrix, will return the indexes of the element's position:
(get-indices [[1 2 3] [4 5 6] [7 8 9]] 6)
;=> [1 2]
which, given back to get-in, will return the element itself:
(get-in [[1 2 3] [4 5 6] [7 8 9]] [1 2])
;=> 6
I wanted the function (get-indices) to be fast, so I was thinking about doing a macro which will expand to something similar to the (cond ...) part of this function (but generic for every 2D matrix of size NxN):
(defn get-indices
[matrix el]
(let [[[a b c] [d e f] [g h i]] matrix]
(cond
(= a el) [0 0]
(= b el) [0 1]
(= c el) [0 2]
(= d el) [1 0]
(= e el) [1 1]
(= f el) [1 2]
(= g el) [2 0]
(= h el) [2 1]
(= i el) [2 2])))
I came up with this macro:
(defmacro get-indices
[matrix el]
(let [size (count matrix)
flat (flatten matrix)
compare-parts (map #(list '= % el) flat)
indices (for [x (range size) y (range size)] [x y])]
(cons 'cond (interleave compare-parts indices))))
It seemed just nice... But when called with var, not a direct value, it throws an exception:
(def my-matrix [[1 2 3] [4 5 6] [7 8 9]])
(get-indices my-matrix 6)
;=> java.lang.UnsupportedOperationException: count not supported on this
; type: Symbol (NO_SOURCE_FILE:0)
To me it seems like the symbol "matrix" isn't resolved to value at macro expansion time or something like that, but I'm absolute beginner in macros...
How can I make this macro to work also with vars as arguments?
I was also thinking about using syntax-quote etc., but I'd like to avoid having (let ...) as a part of the macro output and also didn't know how to implement (interleave compare-parts indices) within the syntax-quote....

Writing this as a macro is a disastrous choice. As a function it's pretty simple, and more efficient than what you wanted your macro to expand to anyway:
(defn get-indices [matrix el]
(let [h (count matrix), w (count (first matrix))]
(loop [y 0, x 0, row (first matrix), remaining (rest matrix)]
(cond (= x w) (recur (inc y) 0 (first remaining), (rest remaining))
(= y h) nil
(= (first row) el) [y x]
:else (recur y (inc x) (rest row) remaining)))))
Conversely, as a macro it is simply impossible. Macros are for writing code at compile-time - how could you generate the cond-based code for 2D matrices at compile time, if you don't know the matrix's size until runtime?

Related

Why are there problems using map in an IF statement?

Why won't the following run?
if (map [ [a b c] -> a + b = c ] [1] [2] [3]) [show 100]
The following produces 'true' as an output:
show (map [ [a b c] -> a + b = c ] [1] [2] [3])
so I expected the first statement above to be the same as:
if true [show 100]
(P.S. in my full version the lists are longer but are collapsed into a single true/false using reduce.)
Thanks.
To elaborate on ThomasC's comment, map always produces a list, even if it only has one element. So
(map [ [a b c] -> a + b = c ] [1] [2] [3])
does produce [true]. Thus
(map [ [a b c] -> a + b = c ] [1 2] [2 3] [3 5])
will produce [true true]. reduce is helpful here,
reduce AND (map [ [a b c] -> a + b = c ] [1 2] [2 3] [3 5])
will produce a simple true by "anding" all the elements of the map output, and
reduce AND (map [ [a b c] -> a + b = c ] [1 2] [2 3] [3 6])
will produce a simple false.

How to write exponent in racket?

Using (x^4) or (^ x 4) giving an error message. Is there some functions for exponent than simply using (* x x x x)?
Use the primitive function expt (see reference):
(expt x 4) ; = x⁴
If you forget expt, you can use:
(for/product ((i 4)) x)
It's easier than writing (* x x x x) for larger values.

Haskell type class instantiation

I am trying to set (PolyA a) and (PolyB a) to be instances of class Polynomial, where I want to implement coeffs, fromCoeffs, coeffsB, fromCoeffsB. I am not quite sure what am I doing wrong, because I receive an error message saying that my functions are not visible to the class Polynomial. Any help please?
class Polynomial p where
--default implementations
data PolyA a = Coeffs [a]
deriving (Show)
data PolyB a = Const a | X (PolyB a) a
deriving (Show)
--instances
instance Polynomial (PolyA a) where
coeffs (Coeffs f)=f
fromCoeffs f= Coeffs f
instance Polynomial (PolyB a) where
coeffsB (Const f)= [f]
coeffsB (X f a)= coeffsB f ++ [a]
fromCoeffsB [] = error "Wrong Input!"
fromCoeffsB [f]= Const f
fromCoeffsB lis#(_:t)= X (fromCoeffsB (init lis)) (last lis)
The following code compiles for me:
class Polynomial p where
coeffs :: p a -> [a]
fromCoeffs :: [a] -> p a
--default implementations
data PolyA a = Coeffs [a]
deriving (Show)
data PolyB a = Const a | X (PolyB a) a
deriving (Show)
--instances
instance Polynomial PolyA where
coeffs (Coeffs f)=f
fromCoeffs f= Coeffs f
instance Polynomial PolyB where
coeffs (Const f)= [f]
coeffs (X f a)= coeffs f ++ [a]
fromCoeffs [] = error "Wrong Input!"
fromCoeffs [f]= Const f
fromCoeffs lis#(_:t)= X (fromCoeffs (init lis)) (last lis)
Summary of changes:
Add methods to the Polynomial class declaration.
Remove the type arguments in the instance declarations.
Change coeffsB to coeffs and fromCoeffsB to fromCoeffs everywhere.
Outdent the PolyB instance declaration by one space.

How can I use the return of a MAPLE procedure as a function directly

This may be very basic, but I can't seem to figure it out: I am trying to use the output of a procedure directly as a function. The Procedure is a prefabricated one, namely the dsolve option in MAPLE. Specifically, I would like to say
dsolve({diff(y(t), t) = y(t)*t, y(1) = 1}, y(t), series, t = 1, order = 7)
The result is
y(t) = t+1-1+(t-1)^2+(2/3)*(t-1)^3+(5/12)*(t-1)^4+(13/60)*(t-1)^5+(19/180)*(t-1)^6+O((t-1)^7)
Which is great, but I can't use this as a function directly, i.e., when I type in y(3), I get y(3). I'm sure this is because the procedure is returning a statement instead of a function. I guess the most basic way around this would be to copy and paste the expression and say y:=t-> whatever, but this is inelegant. How can I get around this?
Thank you
Yes, you are getting back an equation of the form y(t)=<some series> from your dsolve call.
dsol := dsolve({diff(y(t), t) = y(t)*t, y(1) = 1}, y(t), series, t = 1, order = 5);
2 2 3 5 4 / 5\
dsol := y(t) = 1 + (t - 1) + (t - 1) + - (t - 1) + -- (t - 1) + O\(t - 1) /
3 12
You can also convert the series structure on the right-hand side of that to a polynomial (ie. get rid of the big-O term).
convert( dsol, polynom );
2 2 3 5 4
y(t) = t + (t - 1) + - (t - 1) + -- (t - 1)
3 12
You can also evaluate the expression you want, y(t), at that equation. (Or you could just use the rhs command. For sets of equations in the multivariable case the eval approach is more robust and straighforward.)
eval( y(t), convert( dsol, polynom ) );
2 2 3 5 4
t + (t - 1) + - (t - 1) + -- (t - 1)
3 12
And, finally, you can also produce an operator from this expression.
Y := unapply( eval( y(t), convert( dsol, polynom ) ), t );
2 2 3 5 4
Y := t -> t + (t - 1) + - (t - 1) + -- (t - 1)
3 12
That operator is a procedure, and can be applied to whatever point you want.
Y(3);
19
The way I have it above, the statement which assigns to Y happens to contain all the individual steps. And that's the only statement above which you'd need to execute, to get the operator that I assigned to Y.If you prefer you could do each step separately and assign each intermediate result to some name. It just depends on whether you want them for any other purpose.
restart:
dsol := dsolve({diff(y(t), t) = y(t)*t, y(1) = 1}, y(t), series, t = 1, order = 5):
peq := convert( dsol, polynom ):
p := eval( y(t), peq ):
Y := unapply( p, t ):
Y(3);
19

racket. Implement the Ackermann's function

I'm trying to understand, but so far I can not make myself. When I see the finished solution is easier to understand how to do it. This is my first exercise, the others want to do it myself, but need to understand how to implement it.
Please help me how to write a racket function.
Implement the Ackermann's function A. It takes two parameters, x and y, and works as follows:
if y = 0, then it returns 0;
if x = 0, then it returns 2*y;
if y = 1, then it returns 2;
else, it calls itself (function A) with x = x-1 and y = A ( x, (y - 1) )
The project is given
#lang racket/base
(require rackunit)
;; BEGIN
;; END
(check-equal? (A 1 10) 1024)
(check-equal? (A 2 4) 65536)
(check-equal? (A 3 3) 65536)
It's a straightforward translation, you just have to write the formula using Scheme's syntax:
(define (A x y)
(cond ((= y 0) 0) ; if y = 0, then it returns 0
((= x 0) (* 2 y)) ; if x = 0, then it returns 2*y
((= y 1) 2) ; if y = 1, then it returns 2
(else (A (- x 1) ; else it calls itself (function A) with x = x-1
(A x (- y 1)))))) ; and y = A ( x, (y - 1))
Here is one solution:
#lang racket
(define (ack x y)
(match* (x y)
[(_ 0) 0] ; if y = 0, then it returns 0
[(0 y) (* 2 y)] ; if x = 0, then it returns 2*y
[(_ 1) 2] ; if y = 1, then it returns 2
[(x y) (ack (- x 1) (ack x (- y 1)))]))