How to Assign a Generic Function to a Variable

Is it possible to assign a generic function to a variable?

You can let Swift infer the specialization of function2 by the explicit type annotation of f2:

let f2: (Int) -> Int = function2

Alternatively, use an intermediate specializer function which supplies the explicit type annotation

func specialize1Dmap<T>(_ f: @escaping (T) -> T, as _: T.Type) -> (T) -> T { return f }
let f2int = specialize1Dmap(function2, as: Int.self)
let f2str = specialize1Dmap(function2, as: String.self)

Assign to generic function parameter in TypeScript

I am not quite sure what you are trying to achieve here but moving U to the front will fix this problem:

function foo<U>(a: number, f: (a: number) => U) {
return f(a)
}
function bar(a: number) : number {
return 2*a
}
foo(8, bar);

If you want to introduce generic types in a function declaration you should put them right after the function name. When the function is called TypeScript will then try to infer the correct types.

Assigning a Function with Generic Parameter to a Variable

var speakFuction: (speaker: ThingSayer) -> Void = aLoudspeaker.saySomething

You'll need to explicit the type of your function when declaring the variable to help the compiler.

Function with generic type as member variable

In Java (and JVM) values are not polymorphic, methods are.

So correct is to define it with a method

<T> Function<Class<T>, T> fun();

Polymorphic values in Java


Regarding EDIT.

Now, I want to hand a pointer to that function to class B like this:

public class B {
<T> Function<Class<T>, T> fun;

public <T> T get(Class<T> clazz) {
return fun.apply(clazz);
}
}

Once again, a value (including a field) can't be polymorphic, method can.

  • So you can make fun a method

     public abstract class B {
    abstract <T> Function<Class<T>, T> fun();

    public <T> T get(Class<T> clazz) {
    return this.<T>fun().apply(clazz);
    }
    }

    You can't write setter like setFun. Its signature should be something like

     public void setFun(<T> Function<Class<T>, T> fun); // pseudocode

    rather than

     public <T> void setFun(Function<Class<T>, T> fun);

    <T> Function<Class<T>, T> is called rank-N type and it's absent in Java

    What is the purpose of Rank2Types?

    https://wiki.haskell.org/Rank-N_types

  • Alternatively, you can wrap polymorphic fun with a class (interface)

    public interface PolyFunction {
    <T> T apply(Class<T> clazz);
    }

    public class B {
    PolyFunction fun;

    public void setFun(PolyFunction fun) {
    this.fun = fun;
    }

    public <T> T get(Class<T> clazz) {
    return fun.apply(clazz);
    }
    }

    PolyFunction looks like your A so maybe you want

    public class B {
    A a;

    public void setA(A a) {
    this.a = a;
    }

    public <T> T get(Class<T> clazz) {
    return a.get(clazz);
    }
    }

Swift: Assign an instance of a generic type to a class variable?

Break down the create method signature and the Batch1 type

public func create<Request: JSONRPCKit.Request>(_ request: Request) -> Batch1<Request>

public struct Batch1<Request: JSONRPCKit.Request>: Batch {
public typealias Responses = Request.Response
public typealias Results = Result<Request.Response, JSONRPCError>
}

create is a generic function that takes a single parameter of any type. The constraint <Request: JSONRPCKit.Request> specifies that the parameter's type must conform to the protocol JSONRPCKit.Request.

Batch1 is a generic struct that needs to define two internal types, both of which are associated with some arbitrary type. Again, <Request: JSONRPCKit.Request> specifies that that arbitrary type must conform to the protocol JSONRPCKit.Request.

The return type Batch1<Request> ties these two generics together, saying that the type used for the returned Batch1 struct will match the type of the request parameter.

When you call the create method, you must fill in the generic type with a concrete type, as in the example

let batch = batchFactory.create(Subtract(minuend: 42, subtrahend: 23))

Now the compiler can go through all of the definitions and create concrete implementations for that type:

public func create(_ request: Subtract) -> Batch1<Subtract>

public struct Batch1<Subtract>: Batch {
public typealias Responses = Int
public typealias Results = Result<Int, JSONRPCError>
}

This uses the fact that Subtract defines typealias Response = Int. Note that nothing is generic anymore; these are all concrete types. You would have no issue with trying to store a property of type Batch1<Subtract>.


This is why you can't easily store the batch in a property: Swift has no idea what types to put in it!

One way around this is to instead store a closure, this can wrap the generic batch such that the class doesn't have to know about it

// closure property
var responseProcessor: ((Any) -> Void)?

func createBatch<R: JSONRPCKit.Request>(request: R, processor: @escaping (R.Response) -> Void) {
let batch = batchFactory.create(request)
self.responseProcessor = { responseObject in
let response = try! batch.responses(from: responseObject)
processor(response)
}
}

// somewhere else when you get the responseObject
responseProcessor?(responseObject)

This method takes a specific closure that matches the generic type and wraps it in a closure that is no longer dependent on the generic. This way every batch can share the same closure property.

Unable to assign function to type with generic parameter

As mentioned by kaya3, you are trying to assign a function that take a specific type, string[], to a function that takes generic types . What you may do instead, is, define a type with the generic signature. And then create a function that takes is one specific instance of that generic signature. Something like this:

type MyType<T> = (v: T) => string;
const s: MyType<string[]> = (v: string[]) => v[0] || 'x' ;

If you have just one type, this would be sufficient:

const s  = (v: string[]) => v[0] || 'x' ;

How to define a generic function type in Typescript; two similar ways?

This:

type ConcatX<T> = (a: T, b: T) => T;

Is a generic type alias, which contains a function that uses the generic parameter. The generic parameter this function uses is locked in once the type is resolved. That can be handy when some type needs to set the type of your function.

For instance here:

const sum: ConcatX<number> = (a, b) => a + b;

This says that, externally to this function, you declare that the arguments of this function are numbers.

Note that this is not really part of the function type at all. This approach isn't fundamentally different than something like:

type ContatX<T> = { sum(a: T, b: T): T, someValue: T }

The point being that the T is set outside the function entirely, and the function just picks that up to use.



This:

type ConcatY = <T>(a: T, b: T) => T;

Is a generic function. The generic parameter is set when the function is called, and can be different each time it's called. And that parameter may be inferred from the type of the arguments a and b.

You cannot lock down T ahead of time here because T is decided when the function is called and no sooner.

Which means there is no subtype of ConcatY that only takes numbers. To type guard against bad usage here you would instead check the return type:

const resultStr: string = sum(1,2) // error: cannot assign number to string
const resultNum: num = sum('a','b') // error: cannot assign string to number

In both cases the function call is completely valid, but the result is not what the type system is expecting, so you get an error.


If you want a specific subtype of concat where the arguments must be numbers, then you want the generic type ConcatX.

But if your function could take lots of different arguments, and the return type depends on the type of those arguments, and you don't know exactly what types it will be called with ahead of time, then you want the generic function ContactY.

Which all means that if you want to:

"to indicate that a function takes one of these with specific argument types"

Then you need to use ContactX with a generic parameter to create a function type with the T locked to whatever you want.



Related Topics



Leave a reply



Submit