17 ms·
Frege: A Haskell-Like Language for the JVM
- lexicalscope 11y agoThis is pretty cool and interesting, but I'm curious how they can claim purity if they still permit evaluation of code written in Java or other JVM languages, even if the types have to be redeclared. In other words, I'm curious if they are permitting execution of "impure" functions outside of a monad or unsafe function if the type has been redeclared. May have to pull it down and have a look.
- duaneb 11y agoI would imagine you could have some combination of unsafePerformIO + an exception handler.
- michaelsbradley 11y agoHere's a write-up from 2013, Frege: Hello Java: http://mmhelloworld.github.io/blog/2013/07/10/frege-hello-java/ http://mmhelloworld.github.io/blog/2013/07/10/frege-hello-ja...
- reirob 11y agoOn the related Reddit thread [0] a commenter links to a very nice blog that evaluates Frege [1] in a very succinct way. To answer your question by quoting this blog post: "Wrapping mutable Java stuff in Frege means that everything will end up in an ST monad, which is almost always IO. That means that using Java’s HashSet will force anything that uses that to be in the IO monad itself. So there goes purity and referential transparency, which are some of the best parts of Haskell in the first place." [0] https://www.reddit.com/r/haskell/comments/3gr7y6/infoq_frege_a_haskell_for_the_jvm/cu0vj5m https://www.reddit.com/r/haskell/comments/3gr7y6/infoq_frege... [1] http://taylor.fausak.me/2015/06/25/frege-a-jvm-haskell/ http://taylor.fausak.me/2015/06/25/frege-a-jvm-haskell/ EDIT: formatting
- lexicalscope 11y agoThanks for this. This is a bit misleading though I think, as you can actually unwrap and ST unlike an IO - my most common use for ST is actually to use a mutable object in a case where it's inefficient to keep copying immutable (e.g.: large vector or matrix manipulations) - then when you're done the ST monad can be unwrapped and you get the final structure - the entire function remains pure but inside of it, there are calculations that rely on state - but no state enters or leaves the function per say. This would mean using a hash set would be out of the question _for passing around outside of an ST monad_ but you could actually use it internally within functions.
- voxfrege 11y ago> This would mean using a hash set would be out of the question _for passing around outside of an ST monad_ but you could actually use it internally within functions. Yes, but this is what the author was saying: you end up writing your code in ST. Remeber, there is no (general) way to freeze a mutable collection that was passed and then use it as if it was immutable. There can be a dozen different threads be busy modifying it. However, as immutable objects are becoming more mainstream even in Java, there will still plenty of opportunities to make polyglot JVM programs employing pure code. Just not with the JAVA collection classes.
- zxexz 11y agoThe compiler isn't very 'user-friendly', but if you're literally looking for "Haskell on the JVM" and don't care about speed, Frege is a lot of fun once you get used to it. Impure functions/variables must be wrapped in a monad (ST) (take a look at [0]. Frege is almost identical to Haskell, but with a few differences [1] [0] https://github.com/Frege/frege-native-gen/issues/14 https://github.com/Frege/frege-native-gen/issues/14 [1] https://github.com/Frege/frege/wiki/Differences-between-Frege-and-Haskell https://github.com/Frege/frege/wiki/Differences-between-Freg...
- evincarofautumn 11y agoAllowing foreign code doesn’t change the purity of the language. By default in Haskell, an FFI declaration must be in IO, e.g: -- int frob(int, char*) foreign import ccall "frob" frob :: Int -> CString -> IO Int If you know such a function to be pure, you can use unsafePerformIO to tell the type system: refrob :: Int -> CString -> Int refrob x y = unsafePerformIO (frob x y) If you lie to the type system and tell it that an impure function is pure, then all bets are off.
- lexicalscope 11y agoI guess that was my question - if they are making it use FFI as in Haskell, since it's Haskell-like not actual Haskell, or if it's something else that's specific to their JVM version.
- voxfrege 11y agoIt is an FFI, though with different syntax, and much richer. Not only functions, but also foreign (in Frege its called "native") types. Which is indispensable IMHO when you interface a OO language where everything is classes and interfaces. The different syntax should not be a big issue, as Haskell code that uses FFI targeting C is per se not portable.
- voxfrege 11y ago> If you know such a function to be pure, you can use unsafePerformIO to tell the type system Better yet, if you know it to be pure, you can give it an appropriate type and just use it in pure code, like: pure native cos java.lang.Math.cos :: Double -> Double which should be roughly equivalent to: foreign import jvm "java.lang.Math.cos" cos :: Double -> Double except that no Haskell compiler that I know implements the "jvm" calling convention, for obvious reasons. In fact, all primitive operations, types and so on are defined this way in the Frege Prelude.
- dustingetz 11y agoWorth pointing out that this approach isn't particularly helpful when wrapping mutable Java objects, because Java land still has a reference and can/will mutate the object right underneath us. So we still need to write our Fredge code in ST.
- michaelsbradley 11y agoYou can try Frege using your web browser: http://try.frege-lang.org/ http://try.frege-lang.org/
- reirob 11y agoThanks for sharing! It shows with :java the produced Java code.
- devty 11y agohttp://mmhelloworld.github.io/blog/2013/07/10/frege-hello-java/ http://mmhelloworld.github.io/blog/2013/07/10/frege-hello-ja... Am I correct in thinking that Frege cannot leverage on third-party java libraries? Clojure, another functional language built on JVM, has great support for this (possibly) missing feature.
- maaku 11y agoI don't know about Frege, by why wouldn't it? Being able to call out over FFI or the Java equivalent is a pretty standard feature.
- voxfrege 11y agoNo, incorrect. You can use any existing bytecode, whether it was produced by Java or anything else.
- jmillikan 11y agoCalling Java from frege isn't hard, but there isn't currently a way to directly implement interfaces or inherit abstract classes in just frege. You can create a sort of proxy in Java (or whatever) and implement methods in frege, but it's not pretty. (I think; I haven't quite comprehended the examples.) The article at https://mmhelloworld.github.io/blog/2013/07/10/frege-hello-java/ https://mmhelloworld.github.io/blog/2013/07/10/frege-hello-j... talks about this, but doesn't quite explain the proxy mechanism, it just points out an example.
- voxfrege 11y ago> but there isn't currently a way to directly implement interfaces or inherit abstract classes in just frege. Not quite true anymore. TO be sure, some (inline) java will still be needed. Here is an example https://github.com/Frege/frege/blob/master/tests/comp/Issue20.fr https://github.com/Frege/frege/blob/master/tests/comp/Issue2... which compiles to a class that implements java.util.Comparator. Instances thereof can be created from Frege by passing a custom comparision function and could be passed to Java. The example would be useful in cases when you have Frege data in a Java collection and want to sort them. But it is merely there to show the possibilities.
- hugofirth 11y agoOne reason I would love to see this succeed which has almost nothing to do with the particulars of the Frege project itself is the effect it would have on the Scala community. There is a significant portion of the Scala community which desperately wants Scala to be the Haskell they can get their bosses buy in for. IMO the result is unsatisfactory, both for those people and the Scala community as a whole. If a straight Haskell variant in the JVM ecosystem were to "take off" then Scala could be its own thing.
- MrBuddyCasino 11y agoSo thats the reason most Scala code reads like badly written Haskell fanfic.
- dudul 11y agoI think most scala code reads like badly written Java code, mostly because people use at as a "better Java". FP fanatics try to use it as Haskell for JVM, but they are definitely not the majority. Most scala users have no f-ing clue what a monad is :)
- Nadya 11y agoTo be fair, most programmers have no clue what a monad is. To understand what a monad is you first have to understand what a monad is. (No, that wasn't a typo.)
- dudul 11y agoHa true :) I was making a jest to say that most scala programmers don't know anything about FP and just use it for the type inference and stick to OO practices, vars, etc.
- threeseed 11y agoNo I think almost all Scala programmers understand the basics of FP. They just don't understand / have much interest in the intermediate/advanced parts. I've seen lots of beginners take to for comprehensions, maps, filters etc pretty quickly. The problem with Scala is that at an advanced level the code can become pretty unreadable.
- piokuc 11y agoThe examples reminded me this artwork by Manuel Simoni: http://2.bp.blogspot.com/-nPo8up-CfXc/TmjmkzfY5NI/AAAAAAAAA2o/UD2OM-M1kDI/s1600/haskell.jpg http://2.bp.blogspot.com/-nPo8up-CfXc/TmjmkzfY5NI/AAAAAAAAA2...
- agumonkey 11y agoI hope this argument fades away into eternity.
- thedufer 11y agomain = putStrLn "\n" Yes, that was very difficult. I see where you're coming from.
- yawaramin 11y agoActually putStrLn "" is enough, since it prints a newline after the string :-)
- zak_mc_kracken 11y agoIt's called humor. You should get some.
- deleted 11y ago[deleted]
- CommonLispr 11y agoI think the name was a poor choice. It would have been a better fit for a Prolog-style language, and most people will probably mispronounce it.
- voxfrege 11y agoGiven that Gottlob Frege invented higher order functions and currying, I am of slightly different opinion. Regarding the pronounciation, who cares? For example, in Germany, half of the people say "Ay-Bee-Em", the other half pronounce the letters IBM in the german way.
- mafribe 11y agoIn what sense did Frege invent higher-order functions?
- voxfrege 11y agoWell, probably the word "discovered" would fit better. :) Here is a paragraph from "Funktion und Begriff" (1891): > Wie nun Funktionen von Gegenständen grundverschieden sind, so sind auch Funktionen, deren Argumente Funktionen sind und sein müssen, grundverschieden von Funktionen, deren Argumente Gegenstände sind und nichts anderes sein können. Diese nenne ich Funktionen erster, jene Funktionen zweiter Stufe. For non-german speakers: Frege makes a distinction between functions that take things as arguments and functions whose argument are and must be functions. He calls the former ones "first order functions" and the latter ones "second order functions". Today we call functions whose order is greater one "higher order".
- mafribe 11y agoThanks, that's a nice quote. I had read that text as a student, but overlooked this morsel. I wonder if Frege's older Begriffsschrift (1879) doesn't already discuss, or at least mention, higher-order functions. After all, in this text Frege explains his new conception of function. I also wonder if Cantor would have been aware that this is possible.
- nnq 11y agoI know it's a minor thing, but why do people keep coppying this annoying Haskell/ML pattern where I have to type twice the name of a function if I want to explicitly define it's type? current :: IO String current = ... (yeah, it's a minor issue compared to the uber-annoying problem of 'name clashes in record fields' https://wiki.haskell.org/Name_clashes_in_record_fields https://wiki.haskell.org/Name_clashes_in_record_fields ...but still)
- nightski 11y agoI personally find it incredibly clean. You separate the type signature from the implementation (mostly because a lot of the times it is unnecessary from the compiler's pov, but useful as documentation). To that end, I don't see it as any different from a javadoc or any kind of code documentation. In addition since Haskell supports multiple case defitions at the top level inline type declarations would be redundant. For example - current a 0 :: IO Int Int -> Int current 0 b :: IO Int Int -> Int current 0 0 :: IO Int Int -> Int vs. current :: IO Int Int -> Int current 0 a = ... current a 0 = ... current 0 0 = ...
- tome 11y agoWhat syntax do you propose?
- nnq 11y agoThis is the most obvious that comes to mind: current :: IO String : = do d <- Date.new () -- reads system timer, hence IO d.toString ...or for something that works better with a really huge type signature or list of arguments, you could extend it like this myFunctionFoo :: Int -> Int -> Int -> Int : a b c = 2*a + 3*b + 4*c
- reirob 11y agoThanks for the proposals. How would you make your first variant, work with pattern matching? I like the second variant better, because it seems to work with pattern matching. It would as well have to work without type declarations, letting Haskell infer the types. But all in all I prefer the way function definition is implemented now. The record issue is more of a trouble - for it Frege actually has some improvements.
- OnleMeMeMe 11y agoWhat helps most beginners with Monads etc. is seeing it from a problem perspective: You have two things and want to combine them to get a third thing. Depending on how these things are 'wrapped' you need different concepts: Monoid: A + B (|+|) Functor: M[A] => (A => B) => M[B] Monad: M[A] => (A => M[B]) => M[B] Applicative: M[A] => M[A=>B] => M[B] Kleisli: (A => M[B]) => (B => M[C]) => (A => M[C])
- mafribe 11y agoThe Frege page says that Frege features Higher rank types but says nothing about higher-kinded types (HKTs). The two are different. The rank of a type describes the depth at which universal quantifiers appear contravariantly. This is quite different from higher-kinded types, which allow type-level computation. For good monad support one uses HKTs. I wonder if Frege has HKTs and the description on the original page made a mistake?
- voxfrege 11y agoIt has both. Somewhere it is said that it has all language features of Haskell 2010. This implies higher kinded types. But in addition to Haskell 2010, Frege has also higher rank types.
- mafribe 11y agoThanks. Type inference for types of rank > 2 is undecidable, how does this go together with the claim that Frege has type inference? I'm not a Haskell expert, but I think the {-# LANGUAGE RankNTypes #-} extension enables HRTs in Haskell too.
- voxfrege 11y agoType inference for higher ranks is in fact undecidable, but not type checking. Hence, exactly like in Haskell with RankNTypes, you need to annotate your higher rank functions. Actually, the Frege compiler employs an algorithm described in Simon Peyton-Jones paper "Practical Type Inference for Higher Ranked Types". Ordinary HM types are inferred, and higher ranked types checked.
- mafribe 11y agoThanks. It's great to have basically Haskell on the JVM. I'll give it a try.
- mafribe 11y agoHow is the Frege compiler written? Is it a new compiler, built from scratch, or does it borrow heavily from a Haskell compiler?
- voxfrege 11y agoIn the InfoQ article this topic ponts to, I've said something about this. The short answer is that it is not derived from existing Haskell compilers.
- mafribe 11y agoI should have read the InfoQ article more carefully. If you had a Frege -> Haskell translator, which shouldn't be hard to do, except in edge cases, you could use GHC as a testing oracle for the Frege compiler.
- voxfrege 11y agoYes, I have often considered how I could employ GHC, for example. But it turns out, as always, that the devil is in the details. Ideally, one would think you could get away with just writing another backend and implementing another FFI calling convention for the JVM. Yet, projects like LambdaVM that pursue this approach are stalled or given up completly. The difficulties are clearly stated in the Hasell wiki here https://wiki.haskell.org/GHC:FAQ#Why_isn.27t_GHC_available_for_.NET_or_on_the_JVM.3F https://wiki.haskell.org/GHC:FAQ#Why_isn.27t_GHC_available_f...
- mafribe 11y agoI mean something simpler, and doesn't involve retargetting GHC. Write a Frege-to-Haskell compiler F2H, and then for each test T you simply compare the output of running Frege( T ) with the output of running GHC( F2H( T ) ). Maybe you have to transform the outputs into a universal format such as ASCII strings, but that should be straightforward. Now you have an oracle for random Frege programs.