Using map in scheme - dictionary

I've created a procedure called movies-satisfying:
(define movies-satisfying
(lambda (movies pred selector)
(map (pred movies))))
This is how I call the procedure.
(movies-satisfying our-movie-database
(lambda (movie)
(= (movie-year-made movie) 1974))
movie-title)
the movie title = car.
our-movie-database is a database of movies.
Which returns a lot of information about the movie from a database starting with movie title, director, date it was made, and actors. How do I return just the movie title instead of the entire list?
This is what currently gets returned:
(((amarcord)
(federico fellini)
1974
((magali noel) (bruno zanin) (pupella maggio) (armando drancia)))

It's not possible to give a perfect answer without knowing more of the code (as stated in my comment), but I can outline the answer, the trick is to make two passes - of course, assuming that both the predicate and the selector are correctly defined. For example, a search in particular will look like this:
(map (lambda (movie) ; 2nd pass: obtain the names of the movies returned by 1st pass
(movie-title movie))
(filter (lambda (movie) ; 1st pass: obtain only the movies of a given year
(= (movie-year-made movie) 1974))
our-movie-database))
To write the above as a parameterizable function, just pass the lambdas along, as parameters:
(define movies-satisfying
(lambda (movies pred selector)
(map selector (filter pred movies))))
Also be aware that filter must be used to find matches for a given predicate, map will always return a list of the same size of the original input list.

Related

Adapting readmacros UCI Lisp code to common lisp

I'm trying to make the common lisp equivalent of this UCI Lisp/Interlisp helper function for a pattern mather.
(DRM /? (LAMBDA () (LIST '*VAR* (READ]
The documentation is a follows:
-Variables, which are used by the pattern matcher, start with a question mark ("?"), as in ?FOO.
-This is converted internally to (*VAR* role-name), so ?FOO becomes (*VAR* FOO).
-The DRM defines ? to convert itself to *VAR* when it is read
This is my current implementation of it:
(set-macro-character #\? (lambda () (list '*var* (read))))
But when I ran the match function below:
(match (ptrans (actor ?x) (object ?x) (to (store)))
(ptrans (actor (person)) (object (person)) (to (store))) nil)
I get the following error that's coming from DRM function:
*** - EVAL/APPLY: too many arguments given to :LAMBDA
Is my implementation correct?
Reader macro functions need to take two arguments: one for the stream from which they can read the source code, and one for the character that triggered them to be called. If you change your implementation to
(set-macro-character #\? (lambda (stream char)
(declare (ignore char))
(list '*var* (read stream))))
then any occurrence of ?x will be read as (*VAR* X).
Note that this will be evaluated if used as a function argument, which will cause an error if VAR is not a bound function / macro.
You probably want ?x to be read in as '(*VAR* X) (note the quote) to get the list as data.
In that case you should do this:
(set-macro-character #\? (lambda (stream char)
(declare (ignore char))
(list 'quote
(list '*var* (read stream)))))
to prevent evaluation of the form the reader macro function returns.

Why am i getting a ClassCastException in this recursive function [duplicate]

This question already has an answer here:
Wrong number of args (0) passed to: PersistentVector on loop/recur function
(1 answer)
Closed 5 years ago.
I've written a recursive function to get a total cost of a journey.
costOfPath simply makes a call to ubergraph to get the cost for each journey, then this function adds them and displays it.
(defn routeCost [parcel cost]
"Calculate the total route cost"
(if (empty? parcel)
(print "Total Journey Cost: " cost)
((def first-parcel (first parcel))
(def start (:start first-parcel))
(def finish (:finish first-parcel))
(def value (costOfPath start finish))
(def parcel-two (rest parcel))
(routeCost parcel-two (+ cost value)))))
(routeCost task8 0)
Task 8 looks as such:
(def task8 [(Parcel. :main-office :r131 "Plastic Wallets" "Delivery" 1)
(Parcel. :r131 :r111 "CDs" "Delivery" 1)
(Parcel. :r111 :r121 "USBs" "Collection" 2)
(Parcel. :r121 :main-office "USBs" "Delivery" 2)])
The function prints out the correct cost, but gives a classCastException.
ClassCastException practice_ubergraph.core.Parcel cannot be cast to clojure.lang.IFn clojure.lang.Var.fn (Var.java:363)
The parcel record:
(defrecord Parcel [start
finish
package
run-type
weight
])
Why is this happening and how can i stop it?
EDIT: I think its something to do with the IF statement and the way i've put the brackets around the block.
As Tony says, it's a good idea to try to limit your use of defs to the top level.
The reason you see a ClassCastException is probably this line:
((def first-parcel (first parcel))
You're defining first-parcel and then calling it immediately with the outer set of parentheseis.
Compare it to this example which generates a similar exception:
((def a 1))
In this example a gets the value 1. def returns the var #'user/a, so the expression that is evaluated is:
(#'user/a)
The value of #'user/a is 1, and 1 is then treated as a function.
Generally, if you see cannot be cast to clojure.lang.IFn look for a double set of brackets.
Please do NOT use def in a function.
Here is a much better one
(defn route-cost [parcel cost]
"Calculate the total route cost"
(if (empty? parcel)
(print "Total Journey Cost: " cost)
(let [{:keys [start finish]} (first parcel)
value (cost-of-path start finish)]
(route-cost (rest parcel) (+ cost value)))))
The essence of clojure is that you could write your code as concise as possible . usually we use kebab-case in clojure to differentiate Java
Use let in your function will fix everything

The format function looping over a dotted alist

I am working on a function that transforms an alist into a query parameters. So far it looks like this.
(defun encode-options (opts)
"Turns an alist into url query parameters."
(format nil "~{~{~A=~A~}~^&~}" opts))
This works perfectly for alists like ((a b) (c d)) (Resulting in "A=B&C=D"), but fails for dotted alists like ((a . b) (c . d)). (Resulting in The value B is not of type LIST.)
My question is: Is it possible to format the dotted alist to give me the expected results and how?
Is it possible to format the dotted alist?
No, format iterates over proper lists.
There are many possible ways to implement what you want. Here I present two of them.
Keep control string, change data
(defun ensure-proper-list (value)
(typecase value
(null nil)
(cons (cons (car value)
(ensure-proper-list (cdr value))))
(t (list value))))
Now, you transform the option argument so that all elements are proper lists:
(defun encode-options (options)
"Turns an alist into url query parameters."
(format nil
"~{~{~A=~A~}~^&~}"
(mapcar #'ensure-proper-list options)))
Keep data, change control string
(defun print-alist (stream data &optional colonp atsignp)
(declare (ignore colonp atsignp))
(destructuring-bind (head . tail) data
(format stream "~A=~A" head (if (consp tail) (first tail) tail))))
With this new format control, print the list as given:
(defun encode-options (options)
"Turns an alist into url query parameters."
(format nil
"~{~/lib:print-alist/~^&~}"
options))
Note that I added a package prefix lib because without a package, print-alist would be looked up in the user package (a.k.a. COMMON-LISP-USER), which in my opinion is rarely what you want. From 22.3.5.4 Tilde Slash: Call Function:
The function corresponding to a ~/name/ directive is obtained by
looking up the symbol that has the indicated name in the indicated
package. If name does not contain a ":" or "::", then the whole name
string is looked up in the COMMON-LISP-USER package.
That's why I would recommend to always mention the package with ~/ directives.

In Clojure, How do I update a nested map correctly?

I've just started learning Clojure, after many years of Java (and PHP/JavaScript) experience. What a challenge :-)
How do I update a map of values idiomatically? When I use the map function on a map it doesn't return a map, it returns a sequence.
I'm working on a small app where I have a list of tasks. What I'd like to do is alter some of the values in some of the individual tasks, then update the list of original tasks. Here are the tasks I'm testing with:
(defrecord Task [key name duration])
(def tasks
(atom
{
"t1" (->Task "t1" "Task 1" 10)
"t2" (->Task "t2" "Task 2" 20)
"t3" (->Task "t3" "Task 3" 30)
}
))
I've put the tasks in a hashmap, using a string key so it has fast, direct access to any task in the map. Each task holds the key as well, so I know what it's key is when I'm passing individual tasks to other functions.
To update the durations I'm using map and update-in to iterate over and selectively update the duration of each task, and returning the modified tasks.
Here's the function:
(defn update-task-durations
"Update the duration of each task and return the updated tasks"
[tasks]
; 1) Why do I have to convert the result of the map function,
; from a sequence then back to a map?
(into {}
(map
(fn [task]
(println task) ; debug
(update-in
task
; 2) Why do I have to use vector index '1' here
; to get the value of the map entry?
[1 :duration]
(fn [duration]
(if (< duration 20)
(+ duration 1)
(+ duration 2)
)
)
)
) tasks))
)
I print the before/after values with this:
(println "ORIGINAL tasks:")
(println #tasks)
(swap! tasks update-task-durations)
(println "\nUPDATED tasks:")
(println #tasks)
1) The main problem I'm having is that the map function returns a sequence, and not a map, so I'm having to convert the sequence back to a map again using into {} which seems to me to be unnecessary and inefficient.
Is there a better way to do this? Should I be using a function other than map?
Could I arrange my data structures better, while still being efficient for direct access to individual tasks?
Is it ok to convert a (potentially very large) sequence to a map using into {} ?
2) Also, inside my function parameter, that I pass to the map function, each task is given to me, by map, as a vector of the form [key value] when I would expect a map entry, so to get the value from the map entry I have to pass the following keys to my update-in [1 :duration] This seems a bit ugly, is there a better/clearer way to access the map entry rather than using index 1 of the vector?
A popular way to solve this mapping-over-maps problem is with zipmap:
(defn map-vals
"Returns the map with f applied to each item."
[f m]
(zipmap (keys m)
(map f (vals m))))
(defn update-task-durations
[tasks]
(let [update-duration (fn [duration]
(if (< duration 20)
(+ 1 duration)
(+ 2 duration)))]
(->> tasks
(map-vals #(update % :duration update-duration)))))
(swap! tasks update-task-durations)
For Clojure < 1.7, use (update-in % [:duration] ... instead.
Alternatively, you could also use destructuring to simplify your current solution without defining a utility function:
(->> tasks
(map (fn [[k task]]
[k (update task :duration update-duration)]))
(into {})
Why?
map only deals with sequences. If you're into type signatures, this means that map always has the same type (map :: (a -> b) -> [a] -> [b]), but it also means that all you'll get out of map is a seq-of-something.
map calls seq on its collection parameter before doing anything, and seq-ing a map gives you a sequence of key-val pairs.
Don't worry too much about efficiency here. into is fast and this is pretty idiomatic.
Just get more alternatives:
Instead of a map you can use a for
(into {}
(for [[key value] your-map]
[key (do-stuff value)]))
A faster way is reduce-kv
(reduce-kv
(fn [new-map key value]
(assoc new-map key (do-stuff value)))
{}
your-map))
Of course you can also use a simple reduce
(reduce (fn [m key]
(update m key do-stuff))
your-map
(keys your-map))

Recursive Clojure function not recurring when called from last place in the calling function

This is my caller
(resolveEntity [r entity-id]
(println "resolve" entity-id)
(recursive-get r entity-id)
(cache entity-id)
)
Called function is
(defn recursive-get [r entity-id]
(println "recursive" entity-id)
(let [e (f (merge {} (-> r :conns first d/db (d/entity entity-id))))]
(alter-var-root #'cache assoc entity-id e)
(for [[k v] e]
(if (:db/isComponent (k components))
(if (not= (class v) Long)
(map #(recursive-get r %) v)
(recursive-get r v)
)))))
The called function is called just once. If I remove the last line in the caller (cache entity-id), then it recurs every time that I want it to, but I need to return something else (cache entity-id).
I tested a similar but simpler code (a recursive function not called at the tail of a calling function) the REPL and it worked, so I am left crashing my head against the table.
You have been bitten by a Lazy-Bug!
If you remove the last line then the return value of the function is the result of (recursive-get r entity-id) which the repl then iterates through so it can print it. The act of printing each value causes each entry in the lazy collection to be evaluated. When you put another line after that, the result of the map is ignored: nothing reads the entries, and they remain in the unrealized lazy state forever and the computation never happens.
To fix this wrap it in a call to dorun:
(dorun (recursive-get r entity-id))
Or if you need to save the result then use doall instead.

Resources