#620 Dynamically controlled function types

tompalmer Wed 3 Jun 2009

There are times when a return type for a function needs controlled dynamically instead of statically. I recommend a Func constructor that lets you specify return types dynamically. Here's an example usage:

List callMap(List list, |Obj?, Int -> Obj?| mapper) {
  list.map(Func(mapper.params, mapper.returns) |Obj? val, Int i -> Obj?| {
    // Just ridiculous changes here to justify wrapping the function.
    mapper(val, list.size - i - 1)
  })
}

Such a constructor would be similar, say, to the List constructor that lets you explicitly set the type via a Type variable.

brian Wed 3 Jun 2009

Promoted to ticket #620 and assigned to brian

Not quite sure about that - I guess we could do something to parameterize a func which wraps another func.

But I'll mark it as a ticket to track it

tompalmer Thu 4 Jun 2009

Not quite sure about that - I guess we could do something to parameterize a func which wraps another func.

Mostly what I was thinking. Could be optimized/compressed down to one function in some cases. Not sure. Whatever's easiest (especially if it avoids reflection) would be fine to start with, I think.

By the way, my use case was for my matrix stuff I'm working on. I have a constructor to generate matrix data from a passed in function:

new generate(Int[] shape, |Int[] coords -> Obj?| gen) {
  shapeField = shape
  values = List(gen.returns, size)
  eachCoords {
    values.add(gen(it))
  }
}

It doesn't work from another matrix, but I figured that the map function (which does work from an existing matrix) could make nice use of this:

Mat map(|Obj?, Int[] -> Obj?| mapper) {
  // TODO How to use the return type of mapper to control the return type below?
  i := 0
  return ObjMat.generate(shape) |Int[] coords -> Obj?| {
    mapper(get(i++), coords)
  }
}

That "TODO" part is where I hit this issue.

I'm also willing to believe there will be other use cases for generating functions with dynamically defined types (even though my poor example starting this thread is obviously a bogus case).

Lacking this feature, I could recode this not to reuse the generate constructor. More likely I'll have to ignore the matrix type. Alternatively, I might add the explicit type literal for the matrix's of, which was decided against for List#map.

brian Sat 11 Jul 2009

Ticket resolved in 1.0.45

Tom,

I added a new Func.retype method:

**
** Return a new function which wraps this function but with
** a different reflective type signature.  No verification is
** done that this function actually conforms to new signature.
** Throw ArgErr if 't' isn't a parameterized function type.
**
** Examples:
**   f := |a,b->Obj| { "$a, $b" }
**   g := f.retype(|Int,Int->Str|#)
**   f.type  =>  |Obj?,Obj?->Obj|
**   g.type  =>  |Int,Int->Str|
**
Func retype(Type t)

Why don't you try it out and see how it works for your use case.

tompalmer Mon 13 Jul 2009

I haven't tried it out, but I don't think it will work for the general case, because you still can't specify a function type given Type variables for the args and return type, right? I think your current proposal can already be done like so, anyway, right?

g := |Int a, Int b -> Str| {f(a, b)}

My specific use cases, by the way, can be seen at the 'map' and related functions here.

tompalmer Mon 13 Jul 2009

Been off on vacation, by the way.

brian Tue 14 Jul 2009

I haven't tried it out, but I don't think it will work for the general case, because you still can't specify a function type given Type variables for the args and return type, right?

Use sys::Type.parameterize, for example:

Func#.parameterize(["A":Str#, "R":Int#])  =>  |Str->Int|

tompalmer Tue 14 Jul 2009

Thanks. I had missed (or forgotten) that. I might try profiling it. I'm afraid of the speed of using reflective names at the moment.

brian Tue 14 Jul 2009

Thanks. I had missed (or forgotten) that. I might try profiling it. I'm afraid of the speed of using reflective names at the moment.

Type.parameterize is purely munging of data structures, it is pretty light weight. The heaviest part if creating the map to use an argument which you can cache if you know it ahead of time.

tompalmer Tue 14 Jul 2009

Thanks for the info.

Login or Signup to reply.