Giter VIP home page Giter VIP logo

Comments (16)

gneuvill avatar gneuvill commented on June 27, 2024 2

Hi @clinuxrulz,

Here is the reasoning I followed to transcribe the Free datatype from scalaz in java (using derive4j and hkt) :

as you noted, forall on value constructors denotes an existential quantification in haskell. And in java, existentials are encoded with ? (wildcards). Now, the problem with ? is that each occurrence of it in a signature refers to a unique type. Hence the solution I've opted for in my encoding of Free to use an inner type (Free.Sub) that captures the whole signature and to existentially quantify it in the constructor declaration (R Gosub(Sub<f, A, ?> sub) in the gist below).

See https://gist.github.com/gneuvill/ec3f7c434549a19eefe7697e9549a849 for the complete example.

What I like in this encoding is that it makes use of the 'true' java existentials in a type safe way ; however the drawbacks of this approach is that you must use helper methods to 'capture' the wildcard (resumeGosub, resumeSubGosub, stepGosub, stepSubGosub and foldMapGosub in the gist) and that you must pay the price of a wrapper type (Sub).

from derive4j.

clinuxrulz avatar clinuxrulz commented on June 27, 2024 1

I know this is an old issue, but I've seen a solution to this in purescript.

data Stream a = forall s. Stream (s -> Step a s) s

is really ment to be

data Stream a = exists s. Stream (s -> Step a s) s

_exists_ because there is only one type for s but we do not know what it is.

You can define a helper class Exists that does the same as: https://pursuit.purescript.org/packages/purescript-exists/0.2.0/docs/Data.Exists

Or you can also mimic an exists qualification using codensity.

That is: exists a. F a is isomorphic to forall r. (forall a. F a -> r) -> r where F is Stream in this case.

from derive4j.

jbgi avatar jbgi commented on June 27, 2024

Yes, this is something that I wanted to add to the roadmap (and also planned by adt4j in sviperll/adt4j#15 and sviperll/adt4j#38).
I started working on this and

@Data(flavour = Flavour.FJ)
abstract class Stream<A> {
  static class Step<A, S> {/*...*/}
  interface Cases<R, A> {
    <S> R Stream(F<S, Step<A, S>> stepper, S init);
  }
  abstract <R> R match(Cases<R, A> cases);
}

should totally be doable. The main pain point is that I cannot use lambdas anymore to instantiate Cases when there is type parameters on constructors.

from derive4j.

gneuvill avatar gneuvill commented on June 27, 2024

The main pain point is that I cannot use lambdas anymore to instantiate Cases when there is type parameters on constructors.

Argh ! This is unfortunate indeed. Would it affect the user interface ?

from derive4j.

jbgi avatar jbgi commented on June 27, 2024

Well, it will impact pattern matching: you will need to either use method reference or traditional instantiation of a (anonymous) class

from derive4j.

gneuvill avatar gneuvill commented on June 27, 2024

Oh noes... And my first proposition ? (phantom type on the Cases interface ?)

from derive4j.

jbgi avatar jbgi commented on June 27, 2024

I think in the first proposition you would be forced to use Object as type argument for S when pattern matching... would be kind of ugly, no?

from derive4j.

gneuvill avatar gneuvill commented on June 27, 2024

Even by threading the type all along ?

Streams.<A, S>cases()
  .Stream(...)

or with the match method :

myStream.<A, S>match(...)

(assuming S is introduced in the scope anyhow (method, class, whatever...)

from derive4j.

jbgi avatar jbgi commented on June 27, 2024

mmm... where does S would come from? if you try to actually implement the Stream constructor, I can not see how it would work out. the semantic is completely different.

from derive4j.

gneuvill avatar gneuvill commented on June 27, 2024

Yeah, I was considering things on the user side only but I've not (yet) looked at your code and the way it generates its (immensely beneficial ) mess...

from derive4j.

gneuvill avatar gneuvill commented on June 27, 2024

Indeed, this

public abstract class Stream<A> {
    private Stream() {}

    protected abstract <S, R> R match(F3<Unlifted<S>, F<S, Step<A, S>>, S, R> f);

    private static final class Impl<A, S> extends Stream<A> {
        final Unlifted<S> us;
        final F<S, Step<A, S>> stepper;
        final S init;

        private Impl(Unlifted<S> us, F<S, Step<A, S>> stepper, S init) {
            this.us = us;
            this.stepper = stepper;
            this.init = init;
        }

        @Override
        protected <S, R> R match(F3<Unlifted<S>, F<S, Step<A, S>>, S, R> f) {
            return f.f(us, stepper, init);
        }
    }
}

obviously doesn't compile...

from derive4j.

jbgi avatar jbgi commented on June 27, 2024

@gneuvill what I meant is that even without speaking of the code-generation part, the first proposition is impossible to implement:

abstract class Stream<A> {
  interface Cases<R, S, A> {
    R Stream(F<S, Step<A, S>> stepper, S init);
  }
  abstract <R, S> R match(Cases<S, R, A> cases);

  static <S1, A> Stream<A> Stream(F<S1, Step<A, S1>> stepper, S1 init) {
    return new Stream<A>() {
      @Override <S2, R> R match(Cases<S2, R, A> cases) {
        F<S2,Step<A,S2>> _stepper = ???;
        S2 _init = ???;
        return cases.Stream(_stepper, _init);
      }
    };
  }
}

from derive4j.

jbgi avatar jbgi commented on June 27, 2024

😄

from derive4j.

gneuvill avatar gneuvill commented on June 27, 2024

Je comprends vite mais faut m'expliquer longtemps...

from derive4j.

clinuxrulz avatar clinuxrulz commented on June 27, 2024

This is my first time trying derive4j. I believe the following is one possible solution:

https://gist.github.com/clinuxrulz/0a56108f31bafa1452b7b38eba198285

Edit: Also if you want to define the Exists class your gonna need higher kinded types. (The hkt project)

Edit: Example: Creating a Stream of natural numbers (including 0).

        Stream<Integer> nats =
            Streams.Stream(
                new ExistsSStreamF<Integer>() {
                    @Override
                    public <R> R apply(ForallSStreamF<Integer, R> f) {
                        return f.apply(
                            StreamFs.StreamF(
                                (Integer x) -> Steps.Step(x, x + 1),
                                0
                            )
                        );
                    }
                }
            );

Little bit messy.

from derive4j.

clinuxrulz avatar clinuxrulz commented on June 27, 2024

@gneuvill I like it, and I did not know Java could do that. I'll remember that trick.

from derive4j.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.