Apart from syntactical issues, the biggest difference is in the type system and the execution model.
As @senia already pointed out, scala is strict and not pure, which does not mean that you can't write pure functions (you can do that in C, too), just that the compiler won't enforce it.
Frege, OTOH is lazy and pure, which means that all impure effects are forced to live in the ST or IO monad. The type system is essential that of Haskell 2010, with type classes and additional higher rank function types. Type inference works program wide, the only exception are functions with higher rank types, where at least the polymorphic argument must be annotated. Here is an example:
both f xs ys = (f xs, f ys)
For this function, the compiler infers the type:
both :: (α->β) -> α -> α -> (β, β)
Note that both xs
and ys
get the same type, because of the application of f
.
But now lets say we want use a polymorphic list function that we can use with differently typed xs and ys. For example, we want to write:
both reverse [1,2,3] ['a' .. 'z']
As it stands, this application would be in error, because the two lists have different element types and hence different types. So the compiler would refuse the character list.
Fortunately, we can tell the compiler more precisly what we want with a type annotation:
both :: (forall e.[e] -> [e]) -> [a] -> [b] -> ([a], [b])
This tells the following: we will pass to both
a function that does some list transformation but doesn't care about the list element type. Then we pass 2 lists with possibly different element types. And we get a tuple with our transformed lists back.
Note that the code of both
needs not to be changed.
Another way to achieve the same would be to write:
both (f :: forall e.[e]->[e]) xs ys = (f xs, f ys)
and the type checker infers the rest, namely that xs
and ys
must be lists, but can have different element types.
Scalas type system fully (to my knowledge) supports OO. While Frege supports it only partially with regard to types imported for Java, but does not support definition of own OO-like types.
Hence, both languages support functional programming in a JVM environment, although in completly different niches. A third niche is the dynamically typed one, where Clojure is king in the JVM world.