
Frege: A Haskell-Like Language for the JVM - reirob
http://www.infoq.com/news/2015/08/frege-haskell-for-jvm
======
hugofirth
One 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
So thats the reason most Scala code reads like badly written Haskell fanfic.

~~~
dudul
I 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
To 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.)

~~~
david-given
I think a lot of the problems with monads is that they're way too low level to
really get a grip on what they're for --- it's like trying to explain algebra
by talking about manipulating pixels on a screen.

Once I finally saw some of the things you can _do_ with a monad rather than
those useless examples based around Maybe, I had an 'aha!' moment as
everything went click.

No sodding idea what a monoid is, though.

~~~
rarepostinlurkr
Ooo! Something I think I can answer! A monoid is just a thing that knows how
to add to itself!

~~~
whateveracct
Not quite ;) Semigroups are defined by their associative, binary operator of
type a -> a -> a. Monoids are that plus an identity value of a.

~~~
rarepostinlurkr
There Haskell people go again =) You try to define something in simple normal
terms, and off they go adding highly specific and technically correct words to
what was supposed to be a simple explanation.

(I'm not a Haskell expert, I dabble, done CIS194, half of RWH, and I have no
idea what you said -- which is a common problem I run into in the Haskell
world, lots of super helpful people that have forgotten what its like to not
speak their language)

------
lexicalscope
This 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.

~~~
evincarofautumn
Allowing 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.

~~~
dustingetz
Worth 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.

~~~
voxfrege
Yes, that is true.

But it is also not as relevant as one might think.

Consider how many Haskell programs actually use mutable C data, or export
functions that take a foreign ptr to some mutable stuff.

Why should this be generally different in Frege? Useful Java APIs will be
wrapped and sanitized through Frege libraries, and that is it then.

You can go directly to Java, just like you can directly go to C in Haskell,
but it turns out one rarely actually does this.

~~~
dustingetz
> You can go directly to Java, just like you can directly go to C in Haskell,
> but it turns out one rarely actually does this.

This might be the reason that haskell has not enjoyed nearly the adoption of
Scala and Clojure.

------
nnq
I 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)

~~~
tome
What syntax do you propose?

~~~
nnq
This 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
Thanks 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.

~~~
nnq
Thanks for examining the proposals. All in all I don't think improving this
bit of syntax would actually mean this much, it's only worth considering when
you start a new language from scratch.

But the records names / TDNR issue, this _makes a real difference_ , I'll
definitely take a look at Frege if I'll need functional programming on the JVM
...as Scala just seems too scary for me.

Now, about what I proposed above, I meant the two examples as different cases
of the same syntax, newlines should not really make a difference until after
the "=". So you'd use the second variant for pattern matching:

    
    
        myFunctionFoo :: Int -> Int -> Int -> Int
        : 1 b c =
            1984 - c
        : a b c =
            2*a + 3*b + 4*c
    

But it's probably better to direct your effort elsewhere. I see that even
Typed Clojure prefers to repeat the name of a symbol instead of bothering to
rearrange everything else just to avoid this repetition.

...and it's probably not worth spoiling the beauty of the ML-style-syntax for
this. I admit it, I find it 10x easier to read either Lisps or C-syntax-like
languages than MLs, but there is a beauty in the ML way, and math folks seem
to love it, so better keep it that way :)

~~~
voxfrege
Actually, you can write:

    
    
        foo = (\a -> \b ->  (a+b)*(a-b)) :: Num z => z -> z -> z
    

HOwever, it is quite un-idiomatic, of course.

------
OnleMeMeMe
What 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])

------
devty
[http://mmhelloworld.github.io/blog/2013/07/10/frege-hello-
ja...](http://mmhelloworld.github.io/blog/2013/07/10/frege-hello-java/)

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.

~~~
jmillikan
Calling 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-j...](https://mmhelloworld.github.io/blog/2013/07/10/frege-hello-java/)
talks about this, but doesn't quite explain the proxy mechanism, it just
points out an example.

~~~
voxfrege
> 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/Issue2...](https://github.com/Frege/frege/blob/master/tests/comp/Issue20.fr)
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.

------
mafribe
The 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
It 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
Thanks.

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
Type 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
Thanks. It's great to have basically Haskell on the JVM. I'll give it a try.

------
CommonLispr
I 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
Given 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
In what sense did Frege invent higher-order functions?

~~~
voxfrege
Well, 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
Thanks, 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.

~~~
voxfrege
I haven't read the "Begriffsschrift", but you are right. It is probable that
he had developed his formal apparatus already then.

------
michaelsbradley
You can try Frege using your web browser:

[http://try.frege-lang.org/](http://try.frege-lang.org/)

~~~
reirob
Thanks for sharing!

It shows with :java the produced Java code.

------
mafribe
How is the Frege compiler written? Is it a new compiler, built from scratch,
or does it borrow heavily from a Haskell compiler?

~~~
voxfrege
In 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
I 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
Yes, 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_f...](https://wiki.haskell.org/GHC:FAQ#Why_isn.27t_GHC_available_for_.NET_or_on_the_JVM.3F)

~~~
mafribe
I 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.

------
piokuc
The examples reminded me this artwork by Manuel Simoni:
[http://2.bp.blogspot.com/-nPo8up-
CfXc/TmjmkzfY5NI/AAAAAAAAA2...](http://2.bp.blogspot.com/-nPo8up-
CfXc/TmjmkzfY5NI/AAAAAAAAA2o/UD2OM-M1kDI/s1600/haskell.jpg)

~~~
thedufer

        main = putStrLn "\n"
    

Yes, that was very difficult. I see where you're coming from.

~~~
yawaramin
Actually putStrLn "" is enough, since it prints a newline after the string :-)

