2
votes

I understand Haskell syntax.

I want to curry (partially apply) a function called "play-note", and pass one argument "manually," and the second with a map.

If I could write it in Haskell, I'd say:

playNote :: Time -> Instrument -> Int -> Int -> Int -> Int -> Music -- made up, but just to give you an idea

notes = [46, 47, 35, 74]  
loopGo = True

loop time = do mapM_ (playNote' time) notes 
               if loopGo then (loop (time+(second/2))) else return () -- time element removed
playNote' time pitch = playNote time drums pitch 80 11025 9 -- ignore extra args

In Scheme, here's the best I've got:

(define notes '(46 47 35 74))  
(define *loop-go* #t)
(define play-note-prime  
   (lambda (time2)  
      (lambda (pitch)  
         (play-note time2 drums pitch 80 11025 9))))  ; drums is another variable
(define loop  
   (lambda (time)  
      (map (play-note-prime time) notes)  
      (if *loop-go*  
          (callback (+ time (/ *second* 2)) 'loop (+ time (/ second 2)))))) ; time element is more sophisticated here

The Scheme version "compiles," but doesn't do what I expect it to (curry the 1st arg, then the 2nd). Help? Thanks!

Edit:
The essence of my problem is not being able to define a function which takes two arguments, in a way that the following code produces the right result:

map ({some function} {some value; argument 1}) {some list; each element will be an argument 2}
3
If you provide an example of how you are calling loop with where you are passing in time and pitch I think it will be easier to see where this program is not matching your expectations.Davorak
@Davorak: respectfully, I think that may cause more confusion :). I've added a clarification about what the "heart" of the problem is.amindfv
Partial function application is not currying and I think you want the former because if you curry the play-note function then by definition it can only take one argument and return a function that takes one argument so there would be no second argument for you to pass using mapHasaniH

3 Answers

2
votes

To answer my own question:

The function needs to be defined as taking arguments "piecemeal": in other words, it's not really currying. I was trying that above, but wasn't getting it right.

A function which is partially applied needs to be described as a lambda or chain of lambdas, each accepting exactly the number of arguments it'll be passed (in descending order of when they will be recieved).

A working example:

(define nums '(3 3 1 2))
(define f
   (lambda (num1)
      (lambda (num2)
         (expt num1 num2))))
(define ans (map (f 5) nums))
(print ans)

Defining f as accepting all arguments will not work:

(define f
   (lambda (num1 num2)
      (expt num1 num2))) ; Can't be curried
1
votes

You're right -- one way to do it in scheme is to manually create lambdas. This would of course be a pain to implement in a general, correct way, i.e. checking numbers of arguments (don't want to have too many!).

Here's how Clojure (another LISP dialect) does it:

http://clojuredocs.org/clojure_core/clojure.core/partial

Is the source ugly? Maybe. Does it work? Sure.

1
votes

Unless I'm missing something, wouldn't cut or cute from srfi-26 provide what you need? Then its just a question of whether your scheme implementation provides it (I think that most do)