12

I can write a simple function in untyped Racket called curry-all that takes a list of functions, all of which accept the same kind of value for their first argument, and produces a list of functions with their first arguments curried.

(define (curry-all fs arg)
  (map (λ (f) (curry f arg)) fs))

For a running example of the above function, see this snippet on pasterack.

This is a valid function, but I'm not sure if it's even possible to type in Typed Racket given its polymorphic typing constructs. The type of curry itself is already fairly complex, and obviously the type of curry-all would need to be necessarily more complex.

I made a relatively simple attempt at typing this function, though I was quite aware that it would not function as I liked:

(: curry-all
   (All [a c b ...]
        (Listof (-> a b ... b c)) a
     -> (Listof (-> b ... b c))))
(define (curry-all fs arg)
  (map (λ ([f : (-> a b ... b c)])
         (curry f arg))
       fs))

Obviously, this works if all the functions have identical types (which isn’t worthless!), but it fails if they have different arities, even if their first arguments’ types are shared.

Is there any way to specify this function’s type so that it will work in a more general case?

Alexis King
  • 40,717
  • 14
  • 119
  • 194
  • I would be very impressed if there is a solution :) – leppie Mar 04 '15 at 10:50
  • @leppie As would I. ;) I'm guessing there isn't one, but I figured I'd ask anyway. – Alexis King Mar 04 '15 at 10:51
  • Based the original paper, it seems to take a similar approach to C++ templates where a type contract is generated at a callsite. Given this, I cant see the approach would work for procedures with a different 'signature'. – leppie Mar 04 '15 at 10:58
  • @leppie Not quite. Contracts are not generated at the call site—they're only generated on typed/untyped boundaries. This includes using typed code in untyped code or using `require/typed` to import code from untyped code. No contracts are applied to values used within typed code, since the typechecker guarantees soundness. As you note, though, many polymorphic types can't be converted to contracts, so you're correct that this would not be usable from untyped code. – Alexis King Mar 04 '15 at 11:01
  • 1
    The arity of functions is available at runtime via [`procedure-arity`](http://docs.racket-lang.org/reference/procedures.html?q=procedure-arity#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._procedure-arity%29%29) and the [implementation](https://github.com/plt/racket/blob/2881b605361afacd98755c746ac2ac250e49b965/racket/collects/racket/function.rkt) of `curryr` uses it. That code may be modifiable to provide the required implementation of a `my-curry` to do what you want. – ben rudgers Mar 04 '15 at 16:23
  • 1
    What type do you want this function to have? And in what context would you use it? – Sam Tobin-Hochstadt Mar 10 '15 at 21:40
  • 1
    @SamTobin-Hochstadt I ran into this while attempting to emulate generic interfaces with some trickery involving currying. It would actually work, if the typing could support it. – Alexis King Mar 10 '15 at 21:42
  • I don't understand how you'd describe the type that you want, or a case in which you'd use it. There has to be some regularity described by the type. – Sam Tobin-Hochstadt Mar 10 '15 at 21:48
  • 1
    @SamTobin-Hochstadt All the functions in the list have the same type for their *first* argument. That's the unifying factor. – Alexis King Mar 10 '15 at 21:49
  • 1
    Right, but how would you call the functions you get back? Do you really want a sequence of sequences of types? – Sam Tobin-Hochstadt Mar 10 '15 at 21:57
  • can't you use some defunctionalization operator inside `map` ? – alinsoar Feb 04 '20 at 09:14

0 Answers0