Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Compose generic functions #7291

Closed
AnandA777 opened this issue Nov 6, 2017 · 4 comments
Closed

Compose generic functions #7291

AnandA777 opened this issue Nov 6, 2017 · 4 comments
Assignees
Milestone

Comments

@AnandA777
Copy link

AnandA777 commented Nov 6, 2017

Consider the general category of generic functions that take a single parameter of any type and return some result. I need to be able to compose type functions of this sort in a way that preserves the combined return type. Here is an example of the type of composition that I am talking about:

T() wrap<T>(T t) => () => t;
[T] tuplify<T>(T t) => [t];
???? tuplifyThenWrap = compose(wrap, tuplify);
[Integer]() result = tuplifyThenWrap(4);

Here is an example that does not work (legal Ceylon, but Nothing inferred for the generic types):

<T> => FRet(T) combineGenericMaps<FRet,GRet>(<T> => FRet(T) f, <T> => GRet(T) g) {
    FRet combineInner<T>(T t) => f(g(t));
    return combineInner;
}

I am guessing that this example does not work because the precise types of FRet and GRet can't be known until combineInner is called, and the type system apparently can't infer or can't represent some sort of parameterized types for them.

Is it possible to define such a function in Ceylon? If not, would any upcoming features like #3860 help? Thanks!

@gavinking
Copy link
Contributor

Hi, here's a much more correct code example for what you're trying to do, which currently passes the typechecker:

<T> => F<G<T>>(T) compose<F,G>
        (<T> => F<T>(T) f, <T> => G<T>(T) g)
    given F<T> given G<T> 
        => <T>(T t) => f(g(t));

shared void test() {
    T() lazy<T>(T t) => () => t;
    [T] singleton<T>(T t) => [t];
    value lazySingleton = compose<<T>=>T(),<T>=>[T]>(lazy, singleton);
    [Integer]() int = lazySingleton(4);
    [String]() str = lazySingleton("");
}

Note, however, that:

  1. We can't infer the type arguments <T>=>T(),<T>=>[T] to compose() because Ceylon doesn't (yet) have type arg inference for type functions.
  2. The code above seems to have broken the JavaScript backend, and doesn't actually run. I'll investigate further.

@gavinking
Copy link
Contributor

gavinking commented Apr 17, 2018

OK, so this runs correctly:

<T> => F<G<T>>(T) compose<F,G>
        (<T> => F<T>(T) f, <T> => G<T>(T) g)
    given F<T> given G<T>
        => <T>(T t) => f(g(t));

shared void test() {
    T() lazy<T>(T t) => () => t;
    [T] singleton<T>(T t) => [t];
    
    alias Lazy<T> => T();
    alias Sing<T> => [T];
    
    value lazySingleton = compose<Lazy,Sing>(lazy, singleton);
    
    [Integer]() int = lazySingleton(4);
    [String]() str = lazySingleton("hello");

    print(int);
    print(str);
    print(int());
    print(str());
}

Apparently there's a problem with anonymous type functions in type argument lists. I'll open an issue.

@gavinking
Copy link
Contributor

Closing, after opening #7354.

@gavinking
Copy link
Contributor

  1. We can't infer the type arguments <T>=>T(),<T>=>[T] to compose() because Ceylon doesn't (yet) have type arg inference for type functions.
  2. The code above seems to have broken the JavaScript backend, and doesn't actually run. I'll investigate further.

Both of these problems are now fixed!

@gavinking gavinking self-assigned this Apr 23, 2018
@gavinking gavinking added this to the 1.4.0 beta milestone Apr 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants