racket: Why doesn't apply work with "bitmap" function? - scheme

I have been cautioned against using eval in my code. However, in this bit of racket code, I can get eval working but not something more recommended, like apply. Here is the code:
(require 2htdp/image)
(define (get_img filename)
(let ([img (eval `(bitmap ,filename))])
(image->color-list mask)
))
I tried doing the naive replace of eval with apply:
(require 2htdp/image)
(define (get_img filename)
(let ([img (apply `(bitmap ,filename))])
(image->color-list mask)
))
and when I run it I get:
; apply: arity mismatch;
; the expected number of arguments does not match the given number
; expected: at least 2
; given: 1
; [,bt for context]
I have tried a few permutations of this code, but to no avail. I was hopeful this one
(let ([img (apply bitmap `(filename))])
(image->color-list img)`)
would work, but clearly there's still something I'm not understanding
EDIT:
The first thing I tried, with error message:
> (require 2htdp/image)
> (define (get_img filename)
(let ([img (bitmap filename)])
(image->color-list img)))
; readline-input:6:15: bitmap: expected a path with a / in it
; in: (bitmap filename)
; [,bt for context]
Another failed attempt:
> (define (get_img filename)
(let ([img (apply bitmap (list filename))])
(image->color-list mask)))
; readline-input:16:20: bitmap: bad syntax
; in: bitmap
; [,bt for context]

You're using it wrong. So behind the variable + there is a procedure object which can be applied. These are equal:
(+ (* 2 3) 5) ; ==> 11
(apply + (list (* 2 3) 5)) ; ==> 11
(apply + `(,(* 2 3) 5)) ; ==> 11
In your example you are using bitmap and it isn't a procedure at all but a macro and it seems it is to get bitmaps from a racket package and with strings it expects at least a slash since images should't be in the package root. You should replace it with bitmap/file which is a procedure and takes a file path absolute or relative to current working directory instead.
In your example (apply `(bitmap/file ,filename) you are passing apply a list as first argument instead of a procedure object and a last argument with parameters.
In your example (apply bitmap/file `(filename)) you are applying bitmap with a literal list with a symbol filename which has nothing to do with the variable with the same name. You were so close since I think you wanted (apply bitmap/file `(,filename)) which is a funny way of doing (apply bitmap/file (list filename)). What I don't understand is why can't you just do this:
(define (get_img filename)
(let ([img (bitmap/file filename)])
(image->color-list mask)))

The combination apply and bitmap doesn't work together because bitmap is not a function. Note that the entry in the documentation on bitmap says "Syntax" and not "procedure".
If f is a function, then (apply f (list a b c)) will compute (f a b c).
However, bitmap is not a function, it is a "special form".
You are in luck though, because bitmap/file is a function, so you can use that instead.

I think it's worth understanding what apply is useful for, in Racket or other Lisp-1s. In almost all code it is useful when you have a function and a bunch of arguments but you don't know how many there are, and you want to call the function with those arguments. What that means in practise is:
'you have a function' so in particular you are not trying to evaluate some macro form or something else special;
'you have a bunch of arguments' means you have a list of arguments.
If you know how many arguments you have then there is almost never a reason to use apply unless the arguments are already in a list and you don't want to bother extracting them: (apply cons l) might be easier than (cons (first l) (second l)) say.
In particular if you are trying to call a function with a single argument which you know then apply is definitely not what you want. And similarly it is never what you want if the 'function' is a macro.
In Lisp-2s there is an additional use for apply: calling a function which is the value of a variable. This is needed because, as a silly example, (let ((x (lambda (...) ...))) ... (x ...) ...) won't work in a Lisp-2. Lisp-2s have an additional function, funcall, which does what apply does when you know the number of arguments: you don't need funcall in a Lisp-1.
The cases where eval is useful are even rarer. There are some, but almost all the time it is at best a confusion and at worst a terrifying security problem: what does
(define (terror x) (eval `(list x)))
Do when it is called? Answer: anything at all that the language is capable of doing: (terror '(launch-the-nukes)), say.

Related

Simplistic way to think of the apply function

In trying to 'reduce' the apply function, is the correct a proper understanding?
For example for (apply func args)
Remove the (apply and matching ).
Inset the func as the first element of the args, moving the outer quote in one level if necessary.
Here would be an application:
; (add-pairs '((1 2)(3 4))) --> (3 7)
(define (add-pairs ps)
(if (null? ps) nil
(cons (+ (car (car ps)) (cadr (car ps))) (add-pairs (cdr ps)))))
(apply add-pairs '(((1 2) (3 4))))
xxxxxxx x
; Remove the "(apply " and matching ")"
add-pairs '(((1 2) (3 4)))
------------^
; Insert the function into the args, moving the quote in one level if required.
(add-pairs '((1 2) (3 4)))
Is the above an accurate way to show how the apply gets added in, or am I missing anything?
The example is unfortunate, as it only leaves one argument after "the opening of the parentheses". But yes, that's how I also think about it. The simpler the better, :) as long as it is correct.
Except that of course the values in the list are first evaluated, so it's not a simply-syntactical process. But as a basic example,
(apply + (list 1 2 3))
==
( + 1 2 3 )
i.e. the parens around the arguments is what goes away.
For a non-trivial example, see
Matrix multiplication in scheme, List of lists
It seems like you know Python. I personally think that apply in Scheme and star operator * in Python are quite similar.
Imagine you want to zip several lists, which were themselves packed inside a list. Trying to call
list_of_lists = [[1, 2],[3, 4]]
zip(list_of_lists)
would not give you [(1, 3), (2, 4)], so you write
zip(*list_of_lists)
# here it's the same as
zip(list_of_lists[0], list_of_lists[1])
using the iterable unpacking operator *. A (pretty full) alternative to this in Racket/Scheme is using an apply function:
(define list-of-lists '((1 2) (3 4)))
(apply zip list-of-lists)
;; here it's the same as
(zip (car list-of-lists) (cadr list-of-lists))
(If, of course, zip in Scheme was defined the same way as in Python, requiring arbitrary number of arguments)
But you can definitely see the difference here, the syntactic one. In Python version of apply we are 'applying' this * to arguments and then pass what was 'returned' to calling function (zip). Scheme acts like a functional language and reverses everything inside out (at least that's how I see it): you're 'applying' apply to a function and its arguments and then it handles everything itself.
The other significant difference is that, of course, apply in Scheme is a normal function, so we can write e.g.
(define (apply-func-to-sum-and-args func args)
(func + args))
(apply-func-to-sum-and-args apply (list 1 2 3))
;; returns 6
Though I believe (correct me if I'm wrong) that this function cannot be written in pure Scheme and it calls some weird C function under the hood.

evaluating my own functions from list with eval, R5RS

I am having problems with this
e.g. i have
(define (mypow x) (* x x))
and I need to eval expressions from given list. (I am writing a simulator and I get a sequence of commands in a list as an argument)
I have already read that R5RS standard needs to include in function eval as second arg (scheme-report-environment 5), but still I am having issues with this.
This works (with standard function):
(eval '(sqrt 5) (scheme-report-environment 5))
but this does not:
(eval '(mypow 5) (scheme-report-environment 5))
It says:
../../../../../../usr/share/racket/collects/racket/private/kw.rkt:923:25: mypow: undefined;
cannot reference undefined identifier
Eventhough simply called mypow in prompt returns:
#<procedure:mypow>
Any advice, please? (btw I need to use R5RS)
(scheme-report-environment 5) returns all the bindings that are defined in the R5RS Scheme standard and not any of the user defined ones. This is by design. You will never be able to do what you want using this as the second parameter to eval.
The report mentions (interaction-environment) which is optional. Thus you have no guarantee the implementation has it, but it will have all the bindings from (scheme-report-environment 5)
For completeness there is (null-environment 5) which only has the bindings for the syntax. eg. (eval '(lambda (v) "constan) (null-environment 5)) works, but (eval '(lambda (v) (+ 5 v)) (null-environment 5)) won't since + is not in the resulting procedures closure.
Other ways to get things done
Usually you could get away without using eval alltogether. eval should be avoided at almost all costs. The last 16 years I've used eval deliberately in production code twice.
By using a thunk instead of data:
(define todo
(lambda () ; a thunk is just a procedure that takes no arguments
(mypow 5))
(todo) ; ==> result from mypow
Now imagine you have a list of operations you'd like done instead:
(define ops
`((inc . ,(lambda (v) (+ v 1))) ; notice I'm unquoting.
(dec . ,(lambda (v) (- v 1))) ; eg. need the result of the
(square . ,(lambda (v) (* v v))))) ; evaluation
(define todo '(inc square dec))
(define with 5)
;; not standard, but often present as either fold or foldl
;; if not fetch from SRFI-1 https://srfi.schemers.org/srfi-1/srfi-1.html
(fold (lambda (e a)
((cdr (assq e ops)) a))
with
todo)
; ==> 35 ((5+1)^2)-1

Typed Racket - dynamic function calls (string to procedure) revisited

About a year ago, #soegaard provided an answer to an interesting problem - how to take a string and return the procedure named in that string. The solution was simple and elegant.
Enter typed racket and a twist.
I can make it work in typed racket as long as it returns only functions with the same arity, for example (-> Number Number Number), but if I try to have it able to return functions with different arities, such as shown below, I cannot figure out how to make the require/typed call work.
Here is the modified file with my second function with a different arity.
#lang racket
(provide string->procedure add square)
(define (add x y)
(+ x y))
(define (square x)
(sqr x))
(define ns (variable-reference->namespace (#%variable-reference)))
(define (string->procedure s)
(define sym (string->symbol s))
(eval sym ns))
(string->procedure "add")
((string->procedure "add") 1 2)
((string->procedure "square") 5)
And here is the call that only works with the "add" fuction or any other function that takes two numbers and returns one number.
#lang typed/racket
(require/typed "string-procedure.rkt"
[string->procedure
(-> String (-> Number Number Number))]
[add (-> Number Number Number)]
[square (-> Number Number)])
I've tried using case-> and unions to no avail. Using case-> for the return type at least will run but then it fails all calls.
In case you think I'm nuts for trying this, what I'm trying to do is take the result of a database call, a string, and determine the correct procedure to call to access the appropriate data element in a struct. I can do it with a long case statement, but I was hoping for a more elegant solution.
Thank you.
I don't think you want to use eval, or to solve this problem in quite this way. Specifically: what if the database contains a string that refers to a function that doesn't exist, or a function that you didn't want to have called? This is how security problems arise.
I would say that in this case, you'd probably be willing to specify the names of the procedures that are "legal", and you can probably do that easily with a macro that doesn't mangle hygiene too badly:
#lang typed/racket
;; defines the 'db-callable' syntax. Put this in a library file...
(define-syntax (db-callable stx)
(syntax-case stx ()
[(_ fun-name [id ...])
(with-syntax ([(id-strs ...)
(for/list ([id-stx (in-list (syntax->list #'(id ...)))])
(symbol->string (syntax-e id-stx)))])
#'(define (fun-name str)
(match str
[id-str id] ...)))]))
;; here are some functions we want the DB to be able to call
(define (f x) 3)
(define (g x) 4)
;; here's the list of functions we want the db to be able to call:
(db-callable getfun [f g])
((getfun "f") 9)
((getfun "g") 123)

How to make a Racket macro take an integer argument?

I've been trying to make a macro for 'wrapping' functions, i.e. if I have a function that will take a list and cons the symbol 'a to the first element, it'd normally be defined as lambda (l) (cons 'a l), but I want a macro that will take a function and a list of integer-expression pairs and 'wrap' that function by making a new function that takes the some arguments of the old function and gets the rest based on the pairs, using the integer as a position and the expression as the value to give the function. Something like this:
(wrap list (0 'blah) (2 'bloo) (4 'blee))
Should expand to:
(lambda (a1 a2 . rest)
(apply list 'blah a1 'bloo a2 'blee rest))
Problem is, I don't know how to get the macro to find the value of the integer in the pair, it only knows it as a syntax object. I'm fairly new to macros and this should be fairly simple, I'm just having trouble with the docs, and I can't find any info on the web other than simple tutorials on macros. Any help would be appreciated.
This seems like a crazy macro to want to write, especially when SRFI 26 is so much more intuitive to use. Instead of (wrap list (0 'blah) (2 'bloo) (4 'blee)), you can just use:
(cut list 'blah <> 'bloo <> 'blee <...>)
That is surely much easier to read.
If you really must write such a macro, here's one way to go about it, by transforming usages of wrap into equivalent usages of cut:
(require (for-syntax syntax/parse) srfi/26)
(define-syntax (wrap stx)
(syntax-parse stx
((_ func:expr (idx:nat expr:expr) ...)
(let* ((alist (map cons
(syntax->datum #'(idx ...))
(syntax-e #'(expr ...))))
(upper (add1 (apply max -1 (map car alist))))
(listfunc (lambda (i)
(cond ((assv i alist) => cdr)
(else #'<>)))))
(with-syntax (((args ...) (build-list upper listfunc)))
#'(cut func args ... <...>))))))
The key to answering your question, about how to get the integers given the syntax objects, is by using syntax->datum (for deep syntax-stripping) or syntax-e (for shallow syntax-stripping).
(P.S. (To Racket experts reading this.) I'm very new to syntax-parse, so I'm sure syntax-parse experts can find better ways to write the above. I originally wrote the macro as a syntax-case macro, then slapped on syntax-parse syntax classes. That's it.)

Issues with evaluating expressions from user input

I'm trying to make a recursive definition that reads and execute user expressions, such as (3 + 5). Everything is working, except of one problem with the arithmetic symbol.
I managed to replicate the error in a simpler example:
(define v '(1 + 3))
((cadr v) 2 4)
The (cadr v) is the + symbol, but for some reason the procedure can't be executed on the two arguments that followed. Am I missing something?
I think that's because
(cadr v)
returns '+ not + (literal + not a + function).
You need to evaluate it before applying it to arguments.
This should work:
((eval (cadr v)) 2 4)
^evaluates the '+ to +
edit
This worked in racket in interactive mode.
I'm not really sure what's the difference, but made it work in r5rs mode in racket (a script):
#lang r5rs
;required by r5rs
(define user-initial-environment (scheme-report-environment 5))
(define v '(1 + 2))
;eval expects a quoted expression
;(it seems that if it's a function it has to have arguments too)
;and evaluation environment.
((eval (cadr v) user-initial-environment) 2 4)
As others have pointed out, the problem is that the list you've constructed contains the symbol plus, rather than the function plus.
At its heart, this is the same reason that '(a b) returns a list of two symbols, rather than signalling an unbound identifier error; the quote starts a term in a "data language" where legal identifiers are interpreted as symbols, rather than as variable references.
The question, of course, is what you should do about it. Some here have suggested using 'eval'; this is probably a bad idea, for reasons that I think Matthew Flatt captures elegantly in his blog post on the topic.
Instead, you should probably write a simple mapping function. Here's the way I'd write it. If you use my code in an assignment, be sure to credit me :).
#lang racket
;; a mapping from symbols to operators
(define operator-hash
(hash '+ +
'- -
'* *))
;; ... and whatever other operators you want.
;; example of using it:
(hash-ref operator-hash '+) ;; ==> +
Try this:
(define v '(1 + 3))
(let ((operator (eval (cadr v)))
(operand1 (car v))
(operand2 (caddr v)))
(apply operator (list operand1 operand2)))
You can do it this way with eval in Guile:
(define (infix-eval v)
(eval (list (cadr v)(car v)(caddr v))
(interaction-environment)))
> (infix-eval '(1 + 2))
3
Rather than using interaction-environment, you could supply another environment for evaluation, where you could also define some other symbols not found in standard Scheme, so that expressions like (7 % 3) and (2 ^ 6) would also work.

Resources