I've read this question before, and followed Eli Barzilay's answer on srfi-25.
Besides reading the source code of srfi-25, I found writing some auxiliary function would be much more easier, for example
#lang racket
(define (set2v! vec x y value)
(vector-set! (vector-ref vec x) y value))
(define (get2v vec x y)
(vector-ref (vector-ref vec x) y))
(define v2 (vector (vector 1 2 3) (vector 4 5 6) (vector 7 8 9)))
(get2v v2 1 1)
(set2v! v2 1 1 99)
(get2v v2 1 1)
I was wondering if there maybe some Racket-y way on multidimensional vectors operation?
An alternative to using nested vectors for multidimensional vectors is to use the math library's array data structure.
Here's an example use:
Welcome to Racket v6.4.0.4.
-> (require math/array)
-> (define arr (mutable-array #[#[1 2 3] #[4 5 6]]))
-> (array-ref arr #(0 0))
1
-> (array-ref arr #(1 2))
6
-> (array-set! arr #(1 2) 15)
-> (array-ref arr #(1 2))
15
There is a caveat that this will be slower when you use the library from untyped code (e.g., #lang racket). It will be fast when used in Typed Racket.
Related
I am trying to write a function that computes the squared Euclidean distance. I originally stored the data inside lists of the form:
'(1 8 0 0 0 1 0 5 0 1)
'(1 0 2 0 0 0 0 5 0 0)
And basically what I try to obtain is the sum of:
'(0 64 4 0 0 1 0 0 0 1)
Using lists this isn't hard to achieve, like with the code from bellow:
(define (f a b)
(apply + (map (λ(x y) (sqr (- x y))) a b)))
However the data that I'm working with got quite many zeros in it, so instead I tried to replace lists with hash-sets, like so:
'#hash((0 . 1) (1 . 8) (5 . 1) (7 . 5) (9 . 1))
'#hash((0 . 1) (2 . 1) (7 . 5))
Here when I try to rewrite the f function but with hash-sets I get stuck, because I don't know how to iterate over both of them directly. What I wrote so far doesn't count the elements that are in the second hash-set but not in the first one.
(define (f a b)
(for/fold ([sum 0])
([(k v) (in-hash a)])
(+ sum (sqr (- (hash-ref b k 0) v)))))
Is there a way to achieve this in a fast way (preferably using a single for)? Or perhaps is there a better way to work with sparsed lists (that contain many zeros)?
One solution would be to get a list of all indices which occur in either of the sparse vectors, and then to map over that list of indices to calculate the squared distances:
(define (sparse-sum-of-squares u v)
(let ((indices (remove-duplicates (append (hash-keys u) (hash-keys v)))))
(apply + (map (lambda (i) (let ((x (hash-ref u i 0))
(y (hash-ref v i 0)))
(sqr (- x y))))
indices))))
You should probably do some actual testing on your data to see if performance is an issue before you start complicating the data representation. After fixing the sparse vectors in the posted example so that they match, here are the results:
sparse-vector.rkt> (f '(1 8 0 0 0 1 0 5 0 1)
'(1 0 2 0 0 0 0 5 0 0))
70
sparse-vector.rkt> (sparse-sum-of-squares '#hash((0 . 1) (1 . 8) (5 . 1) (7 . 5) (9 . 1))
'#hash((0 . 1) (2 . 2) (7 . 5)))
70
The thing is, we need to handle missing values in both hashes. Iterating only over indexes with actual values, we can do something like this:
(define (squared-euclidean-distance a b)
(for/fold ([sum 0])
([idx (set-union (hash-keys a) (hash-keys b))])
(+ sum (sqr (- (hash-ref a idx 0)
(hash-ref b idx 0))))))
We simply return 0 if an index is missing. It works as expected:
(squared-euclidean-distance
'#hash((0 . 1) (1 . 8) (5 . 1) (7 . 5) (9 . 1))
'#hash((0 . 1) (2 . 2) (7 . 5)))
=> 70
#lang racket
(define (cartesian-product . lists)
(foldr (lambda (xs ys)
(append-map (lambda (x)
(map (lambda (y)
(cons x y))
ys))
xs))
'(())
lists))
(cartesian-product '(1 2 3) '(5 6))
I have racket lang code, that calculate cartesian product of two sets or lists, I don't understand the code well, can any one convert code to pseudo code.
The function corresponds to this definition of cartesian products.
The dot . in the argument means that lists will collect all the arguments (in a list) no matter how many are passed in.
How to call such a function? Use apply. It applies a function using items from a list as the arguments: (apply f (list x-1 ... x-n)) = (f x-1 ... x-n)
foldr is just an abstraction over the natural recursion on lists
; my-foldr : [X Y] [X Y -> Y] Y [List-of X] -> Y
; applies fun from right to left to each item in lx and base
(define (my-foldr combine base lx)
(cond [(empty? lx) base]
[else (combine (first lx) (my-foldr func base (rest lx)))]))
Applying the simplifications from 1), 2) and 3) and turning the "combine" function in foldr to a separate helper:
(define (cartesian-product2 . lists)
(cond [(empty? lists) '(())]
[else (combine-cartesian (first lists)
(apply cartesian-product2 (rest lists)))]))
(define (combine-cartesian fst cart-rst)
(append-map (lambda (x)
(map (lambda (y)
(cons x y))
cart-rst))
fst))
(cartesian-product2 '(1 2 3) '(5 6))
Let's think about "what" combine-cartesian does: it simply converts a n-1-ary cartesian product to a n-ary cartesian product.
We want:
(cartesian-product '(1 2) '(3 4) '(5 6))
; =
; '((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
We have (first lists) = '(1 2) and the result of the recursive call (induction):
(cartesian-product '(3 4) '(5 6))
; =
; '((3 5) (3 6) (4 5) (4 6))
To go from what we have (result of the recursion) to what we want, we need to cons 1 onto every element, and cons 2 onto every element, and append those lists. Generalizing this, we get a simpler reformulation of the combine function using nested loops:
(define (combine-cartesian fst cart)
(apply append
(for/list ([elem-fst fst])
(for/list ([elem-cart cart])
(cons elem-fst elem-cart)))))
To add a dimension, we consed every element of (first lists) onto every element of the cartesian product of the rest.
Pseudocode:
cartesian product <- takes in 0 or more lists to compute the set of all
ordered pairs
- cartesian product of no list is a list containing an empty list.
- otherwise: take the cartesian product of all but one list
and add each element of that one list to every
element of the cartesian product and put all
those lists together.
How can I shift a range in ClojureScript ?
For example let's say we have the range:
(range 3)
Which gives: (0 1 2)
I'm looking for a function to shift the values to the left like this: (1 2 0) or like this (2 0 1)
I came up with an implementation which I'll share as an answer. I guess should be some built-in function to do this ? But I didn't found anything.
This is the function I wrote:
(defn <-range [n l]
(concat (drop n (range l)) (range n)))
A brief explanation:
(range l) create a range of length l
(drop n) drop n elements
(range n) create a new range until n
(concat) concat both the ranges
If I try:
(<-range 0 4) gives (0 1 2 3)
(<-range 2 4) gives (2 3 0 1)
(<-range 4 4) gives (0 1 2 3)
I've reversed the order of your args, as this feels closer to how range args work. lazy-cat is probably preferable to concat, as it won't even evaluate the second range until it's needed.
(defn <-range [length start-index]
(lazy-cat (range start-index length)
(range start-index)))
there is also a cycle function, that (unsurprisingly) cycles a collection (to avoid the concatenation):
user> (defn <-range [n l]
(->> (range l)
cycle
(drop n)
(take l)))
#'user/<-range
user> (<-range 0 4)
(0 1 2 3)
user> (<-range 2 4)
(2 3 0 1)
user> (<-range 4 4)
(0 1 2 3)
also you can do it even without any call to range, based on the remainder:
user> (defn <-range [n l]
(take l (iterate #(rem (inc %) l) (rem n l))))
or like this:
user> (defn <-range [n l]
(map #(rem (+ % n) l) (range l)))
I assume the range was just used as an example and you really want to be able to do this to any collection.
(defn rotate-left [c]
(lazy-cat (drop 1 c) (take 1 c)))
or with the ability to optionally specify more than 1 rotation,
(defn rotate-left
([c] (rot-left 1 c))
([n c] (lazy-cat (drop n c) (take n c))))
Using this,
(rotate-left (range 3)) yields (1, 2, 0) and
(rotate-left 2 (range 3)) yields (2, 0, 1)
Given the code snippet that follows, is there any meaningful difference between example-func-A and example-func-B?
#lang racket/base
(require (only-in racket/function curry))
(define (((example-func-A x) y) z)
(+ x y z))
(define example-func-B
(curry
(lambda (x y z)
(+ x y z))))
Yes, example-func-A (which uses the MIT-style curried-procedure syntax) is less flexible than example-func-B, in that it expects to only be called with a single argument at a time:
> (((example-func-A 4) 5) 6)
15
> (example-func-A 4 5 6)
example-func-A: arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 3
arguments...:
4
5
6
context...:
/opt/homebrew-cask/Caskroom/racket/6.4/Racket v6.4/collects/racket/private/misc.rkt:87:7
In contrast, example-func-B accommodates receiving multiple (or even zero!) arguments:
> (((example-func-B 4) 5) 6)
15
> (example-func-B 4 5 6)
15
> ((((example-func-B) 4)) 5 6)
15
(Presumably the flexibility of curry comes with a bit of a performance hit at runtime.)
What's the equivalent of foldr, foldl in Emacs Lisp?
If you
(require 'cl)
then you can use the Common Lisp function reduce. Pass the keyword argument :from-end t for foldr.
ELISP> (reduce #'list '(1 2 3 4))
(((1 2) 3) 4)
ELISP> (reduce #'list '(1 2 3 4) :from-end t)
(1 (2 (3 4)))
Since Emacs-24.3 we recommend the use of cl-lib over cl (which is planned for removal in some distant future), so it would be:
(require 'cl-lib)
(cl-reduce #'+ '(1 2 3 4))
and since Emacs-25, you can also use the seq package for that:
(require 'seq)
(seq-reduce #'+ '(1 2 3 4) 0)
Common Lisp library provides plenty of sequence functions like mapping, filtering, folding, searching and even sorting. CL library is shipped with Emacs by default, so you should stick to it. I however really like dash.el library, because it provides enormous amounts of functions for list and tree manipulations. It also supports anaphoric macros and encourages functional programming, which makes code concise and elegant.
Haskell's folds correspond with dash.el folds:
foldl with -reduce-from
foldr with -reduce-r-from
foldl1 with -reduce
foldr1 with -reduce-r
Sum of a range 1 to 10 using folds might look like in this in Haskell and dash.el:
foldl (+) 0 [1..10] -- Haskell
(-reduce-from '+ 0 (number-sequence 1 10)) ; Elisp
You probably know, that folds are very general, and it is possible to implement maps and filters via folds. For example, to increment every element by 2, Haskell's currying and sections would allow for terse code, but in Elisp you would usually write verbose throwaway lambdas like that:
foldr ((:) . (+2)) [] [1..10] -- Haskell
(-reduce-r-from (lambda (x acc) (cons (+ x 2) acc)) '() (number-sequence 1 10)) ; Elisp
Guess what, it isn't necessary in dash.el with anaphoric macros, which allow special syntax by exposing variables of a lambda as shortcuts, like it and acc in folds. Anaphoric functions start with 2 dashes instead of 1:
(--reduce-r-from (cons (+ it 2) acc) '() (number-sequence 1 10))
There are plenty fold-like functions in dash.el:
;; Count elements matching a predicate
(-count 'evenp '(1 2 3 4 5)) ; 2
;; Add/multiply elements of a list together
(-sum '(1 2 3 4 5)) ; 15
(-product '(1 2 3 4 5)) ; 120
;; Find the smallest and largest element
(-min '(3 1 -1 2 4)) ; -1
(-max '(-10 0 10 5)) ; 10
;; Find smallest/largest with a custom rule (anaphoric versions)
(--min-by (> (length it) (length other)) '((1 2 3) (4 5) (6))) ; (6)
(--max-by (> (length it) (length other)) '((1 2 3) (4 5) (6))) ; (1 2 3)