Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler error with higher-order types #293

Closed
praalhans opened this issue Jul 23, 2016 · 5 comments
Closed

Compiler error with higher-order types #293

praalhans opened this issue Jul 23, 2016 · 5 comments

Comments

@praalhans
Copy link

First of all, thank you for Frege! A very exciting project!

I found a compiler error, at least in the sense that it did not tell what was wrong with my source code.

Consider the following (working) example:

module bug.Example where
data Log t = LogA { message :: String,
                    integer :: Maybe t } |
             LogB { message :: String,
                    boolean :: Bool }
newtype Logger t a = Logger { runLog :: ([Log t], a) }
instance Monad (Logger t) where
  pure a = Logger ([], a)
  (Logger (xs, a)) >>= f = Logger (xs ++ xs', a')
    where (xs', a') = Logger.runLog $ f a
tell s = Logger (s, ())

Now, reversing the [Log t] and a in the tuple of Logger, and modifying the Monad code accordingly, results in the following errors:

module bug.Example where
data Log t = LogA { message :: String,
                    integer :: Maybe t } |
             LogB { message :: String,
                    boolean :: Bool }
newtype Logger t a = Logger { runLog :: (a, [Log t]) }
instance Monad (Logger t) where
  pure a = Logger (a, [])
  (Logger (a, xs)) >>= f = Logger (a', xs ++ xs')
    where (a', xs') = Logger.runLog $ f a
tell s = Logger ((), s)

Results in the following problem:

frege.runtime.Undefined: Can't adapt
Bind {Logger a (b->c), PreludeBase.TTuple2<Func.U<𝓑, 𝓒>, PreludeBase.TList<TLog<𝓐>>>, arg$1.call()}
to  Kind.U<PreludeBase.TTuple2<?, PreludeBase.TList<TLog<𝓐>>>, Func.U<𝓑, 𝓒>>
because  PreludeBase.TTuple2<Func.U<𝓑, 𝓒>, PreludeBase.TList<TLog<𝓐>>>  does not match  Kind.U<PreludeBase.TTuple2<?, PreludeBase.TList<TLog<𝓐>>>, Func.U<𝓑, 𝓒>>
    at frege.prelude.PreludeBase.error(PreludeBase.java:16095)
    at frege.compiler.gen.java.Bindings$30.call(Bindings.java:1865)
    at frege.compiler.gen.java.Bindings$30.call(Bindings.java:1863)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.gen.java.Bindings$33.call(Bindings.java:1964)
    at frege.compiler.gen.java.Bindings$33.call(Bindings.java:1950)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.gen.java.VarCode$5.apply(VarCode.java:568)
    at frege.compiler.gen.java.VarCode$19$5.call(VarCode.java:16376)
    at frege.compiler.gen.java.VarCode$19$5.call(VarCode.java:16374)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.gen.java.VarCode$19$2$1Let$33724$9$22$7.apply(VarCode.java:13791)
    at frege.compiler.gen.java.VarCode$19$2$1Let$33724$9$25.call(VarCode.java:15386)
    at frege.compiler.gen.java.VarCode$19$2$1Let$33724$9$25.call(VarCode.java:15382)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.gen.java.VarCode$15.apply(VarCode.java:5215)
    at frege.compiler.gen.java.VarCode$21$3.call(VarCode.java:17015)
    at frege.compiler.gen.java.VarCode$21$3.call(VarCode.java:17013)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.gen.java.Match$5.apply(Match.java:653)
    at frege.compiler.gen.java.VarCode$20.apply(VarCode.java:16470)
    at frege.compiler.gen.java.Match$5.apply(Match.java:653)
    at frege.compiler.gen.java.VarCode$20.apply(VarCode.java:16470)
    at frege.compiler.gen.java.VarCode$40$2.call(VarCode.java:21342)
    at frege.compiler.gen.java.VarCode$40$2.call(VarCode.java:21338)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.gen.java.VarCode$7.apply(VarCode.java:750)
    at frege.compiler.gen.java.VarCode$46.apply(VarCode.java:23089)
    at frege.compiler.gen.java.VarCode$48$1.call(VarCode.java:23358)
    at frege.compiler.gen.java.VarCode$48$1.call(VarCode.java:23356)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.gen.java.InstanceCode$9.apply(InstanceCode.java:4309)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9.apply(State.java:1290)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1296)
    at frege.control.monad.State$IMonad_State$9$1.call(State.java:1294)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.control.monad.State$IMonad_State$17.apply(State.java:1434)
    at frege.control.monad.State$TState$2.call(State.java:2175)
    at frege.control.monad.State$TState$2.call(State.java:2173)
    at frege.run7.Thunk.call(Thunk.java:234)
    at frege.compiler.passes.GenCode$12$1.apply(GenCode.java:2592)
    at frege.imp.parser.FregeParseController.runSTIO(FregeParseController.java:481)
    at frege.imp.parser.FregeParseController.parse(FregeParseController.java:807)
    at frege.imp.parser.FregeParseController.parse(FregeParseController.java:855)
    at frege.imp.builders.FregeBuilder.runParserForCompiler(FregeBuilder.java:255)
    at frege.imp.builders.FregeBuilder.compiled(FregeBuilder.java:166)
    at frege.imp.builders.FregeBuilderBase.compileNecessarySources(FregeBuilderBase.java:365)
    at frege.imp.builders.FregeBuilderBase.build(FregeBuilderBase.java:219)
    at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:734)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:205)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:245)
    at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:300)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:303)
    at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:359)
    at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:382)
    at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:144)
    at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:235)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

At least a work-around exists, by swapping the elements of the tuple.

@Ingo60
Copy link
Member

Ingo60 commented Jul 23, 2016

This is indeed a bug.
It is related to newtypes which are used as higher ranked types (here through the instantiation as Monad).

To verify this, you can try the failing example with data instead of newtype and if I am right it should work.

Unfortunately, I haven't figured out yet to full extent why some newtypes do work, while others don't. But in this case it is quite clear that the order of the type variables on the LHS is not the same as on the RHS, and this won't work with the encoding for higher ranked types in Java that is utilized in the current implementation.

@yuxuanchiadm
Copy link
Contributor

yuxuanchiadm commented Mar 25, 2018

Simplest test case I could construct. Compiler generate illegal java code:

newtype Bar a = Bar { getBar :: String }

class Foo f where
  foo :: f a -> f a -> f a

instance Foo Bar where
  foo (Bar a) (Bar b) = Bar (a ++ b)

main = println (Bar.getBar (foo (Bar "1") (Bar "2")))

Or this. Compiler failed to compile code:

newtype Bar a = Bar { getBar :: Int }

class Foo f where
  foo :: f a -> f a -> f a

instance Foo Bar where
  foo (Bar a) (Bar b) = Bar (a + b)

main = println (Bar.getBar (foo (Bar 1) (Bar 2)))

All those test case could be fixed by changing newtype to data

Edit: In the String case. Looks like compiler thinking the higher kinded type is String :: * -> * instead of Bar :: * -> *

@yuxuanchiadm
Copy link
Contributor

yuxuanchiadm commented Mar 26, 2018

So I think the fundamental problem is we treat newtype as just type alias. This usually working fine without any problem. But if we got higher kinded type and RHS and LHS of newtype declaration has different kind signature or kind signature in different order. We can't just think newtype is type alias. We need deal those as special case of newtype.

@yuxuanchiadm
Copy link
Contributor

yuxuanchiadm commented Mar 26, 2018

There would be multiple solution for this issue:

  1. Deal those declaration as normal data declaration and warning about this mechanism if user write those code. Because the semantic of normal data type and newtype is not same https://wiki.haskell.org/Newtype (Best short term solution imo)
  2. Keep newtype as type alias. But instead generate real data type for it. Just don't use real data type in normal case. Except we got higher kinded type. Warp value into real data type. And unwarp it soon as possible after higher kinded type is not the case. As long as we keep real data type away from pattern match. Semantic of newtype should be the same.
  3. Since all we need to have are just const and swap functions at kind level. We simply brute force it. Prepare all those possible types up to limit. And do warp and unwarp when necessary.

@yuxuanchiadm
Copy link
Contributor

Actually I found current implementation of newtype is some what wrong. I'll open another issue about that.

@Ingo60 Ingo60 closed this as completed in 2e6215c Mar 31, 2018
catull pushed a commit to catull/frege that referenced this issue Jun 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants