Frege (programming language)
Frege is a non-strict, pure functional programming language in the spirit of Haskell. It enjoys a strong static type system with type inference. Higher rank types are supported, though type annotations are required for that.[1] The programming language is named after the German mathematician, logician and philosopher Gottlob Frege. While it is not a Haskell dialect, some effort has been put into making Frege look and feel like Haskell.[1]
Frege programs are compiled to Java bytecode and run in a Java virtual machine. Existing Java classes and methods can be used seamlessly from Frege.
Frege authoring is attributable to Ingo Wechsung.[2][3]
The Frege programming language is unrelated to the Frege Program Prover.
Contents |
Comparison with Haskell [edit]
A summary of differences between Frege and Haskell is listed at the Differences between Frege and Haskell.
The type String is custom defined as an interface with Java strings. String (++) is bound to Java's String (+).[4] Conversion functions to Haskell correspondent:
packed :: [Char] -> String unpacked :: String -> [Char]
Literals:
-- boolean literals true false are not capitalized -- frege: data Ordering = Lt | Eq | Gt -- haskell: data Ordering = LT | EQ | GT
Numeric literals are not overloaded. They follow the Java rules for numeric literals.
test = (*5) 5L -- type error!! -- with fromInt :: Num a => Int -> a test = (* fromInt 5) 5L -- passes typechecker
fregeFromToList = 1..5 -- without brackets :: [Int] haskellFromToList = [1..5] -- :: (Num t, Enum t) => [t]
Frege's Monad class does not include the method fail, included in a separate class MonadFail.[5]
Frege does not implement Haskell-like exceptions. Exceptions in calls to the native interface are caught and returned in an (Either JException resultType).
Numeric classes for floating point types are also different. Haskell's classes Fractional, RealFrac, RealFloat and Floating are not defined. Haskell's class Real defines toRational while Frege's defines (/):[4]
class Real (Num r) => r where -- classname precedes context --- the division operator (/) :: r -> r -> r
Hello World program [edit]
-- file hello.fr module Hello where -- moduleName maybe hierarchical as pkgdir.JavaClassname main args = println $ "Hello world! your arguments are: " ++ show args
Compiling Frege programs [edit]
Frege requires Java-7 JDK to compile and run.
at the console [edit]
As the "Getting started" page states,[6] to compile it:
mkdir classes java -Xss1m -jar <install-dir>/fregec.jar -d classes src/hello.fr
This assumes the downloaded frege3.xx.vvv.jar has been renamed to fregec.jar for ease of use.
To run the compiled program specify the package name as start class. On GNU/Linux and other Unix systems:
java -cp classes:<install-dir>/fregec.jar Hello arg1 arg2 Hello world! your arguments are: ["arg1", "arg2"]
On Microsoft Windows the classpath separator has to be changed to ';'
at the Eclipse devel. environment [edit]
There is a plug-in for Eclipse with instructions given at How-to EclipseFregIDE.
More involved examples [edit]
Arguments listing [edit]
module Test where -- main :: [String] -> IO () main args = do println "Hello World!" case args of [] -> println "Usage: give some parameters" _ -> do println "here come your parameters:" let pairs = zip numbering args forM_ pairs $ uncurry -- anonymous function (\pos -> \arg -> do -- (->) between params. can be omitted, but not the backslashes print $ show pos ++ ". " printArg arg ) where numbering = iterate (+1) 1 -- Haskell's [1..] doesn't parse -- :: [Int] -- function composition printArg = println • ("arg: "++) -- prepend label and print
data type admits methods to match a JavaVM Class interface [edit]
Let's view some more advanced constructs while showing how to reuse code on record types with properties in common.
Field accessors have to be used with the dot notation and they don't imply a corresponding function (à la Haskell) in the module namespace. (you have to qualify them like RecordType.fieldName)
-- file fregeRec.fr module FregeRec where -- with java scalar types incl. String data TRec = RecConstructor { fld1 :: Long, fld2 :: String, fld3 :: Int} where -- some methods follow new cnt = RecConstructor 0L "abc" cnt -- positional initialisation with java literals getProp1 (obj::TRec) = obj.fld1 setProp1 (obj::TRec) v = obj.{fld1 = v} -- dot before update clause incrProp1 (obj::TRec) = obj.{fld1 <- (+1L)} -- apply function to field derive Eq TRec ; derive Show TRec -- using the record ''methods'' with navigational style getATRecObj cnt = ((TRec.new cnt ).setProp1 1L ).incrProp1 -- the following line throws a compiler error!!: can't resolve `fld1` -- getField1 (obj::TRec) = fld1 obj -- fld1 does not belong to the module namespace data TRec2 = RecConstructor2 { fld4 :: Long, fld5 :: Float} where -- some methods follow new = RecConstructor2 { fld4 = 4L, fld5 = 0.0f} -- initialisation byName with java literals getProp1 (obj::TRec2) = obj.fld4 derive Eq TRec2 ; derive Show TRec2 getATRec2Obj () = TRec2.new
-- file test.fr module Test where import FregeRec (TRec, getATRecObj, TRec2, getATRec2Obj) -- typeclassing record methods defined above -- to derive functionality over them -- so we can use it with different record types having methods in common class HasProp1Long t where getProp1 :: t -> Long -- derived typeclass class PrintProp1 (HasProp1Long t) => t where -- classname precedes context requirements printProp1 :: t -> IO () printProp1 rec = println $ "printProp1: " ++ showLong rec.getProp1 where showLong (longv::Long) = show longv instance PrintProp1 TRec instance PrintProp1 TRec2 -- main :: [String] -> IO () main args = do let myTRecObj = FregeRec.getATRecObj 1 myTRec2Obj = FregeRec.getATRec2Obj () println $ "myTRecObj: " ++ show myTRecObj println $ "myTRec2Obj: " ++ show myTRec2Obj printProp1 myTRecObj printProp1 myTRec2Obj
IORefs / Exported identifiers [edit]
The IORef data type has Java style methods {.new iniVal, .get, .put val}.
- Exported identifiers
- There is no export list at the module clause. Instead, private / protected / public (default) access qualifiers. Protected items will only be available when explicitly mentioned in an import list.
- Operator definition
- to introduce a fresh symbol operator one must write it within backquotes in the fixity declaration. Associativity (left assoc.: infixl, right assoc.:infixr, no assoc:infix). Precedence range is 1..16 (unlike Haskell's 0..9) . See the op. precedence table at the manual.
module IORefTest where -- Monad's ops. use -- At the right of '>>=' is a computation function (funct. with side effects) -- on the result of the left side computation infixr 3 `>>>` -- operator fixity, within backquotes (unlike Haskell) f >>> g = g • f -- left-to-right (more readable) function composition (arrow style (>>>), F# style (>>)) -- instead of Haskell's export lists, ''private''/''protected'' qualifiers private incrCounter :: Enum a => IORef a -> IO a private incrCounter enumRef = do enumRef.get >>= (succ >>> enumRef.put) enumRef.get infixl 1 `|>` -- object navigational application (FSharp's pipeline op.) x |> f = f x main _ = do refCnt <- IORef.new 0 -- :: IO (IORef Int) cnt <- incrCounter refCnt cnt |> show |> ("counter shows: " ++) |> println
Accessing Java [edit]
See chapter "Native Interface" of the Manual.
- Calls to native Java must be handled in a Monad. (Except for pure tagged calls).
- Java nullable references as parameters translate into Maybe wrappers.
- Java calls that can throw exceptions must have a result type wrapped in an Exception resultType which is synonym of (Either JException resultType).
// file src/pkgdir/StringExtra.java package pkgdir ; public class StringExtra { // creating a class with extra functionality public static int lastIndexOf( String str, char ch) { return str.lastIndexOf( ch) ; } }
-- file src/pkgdir/MyNativeInterface.fr module pkgdir.MyNativeInterface where -- native types must include a phantom parameter, related to the monad state data JRuntime s = native java.lang.Runtime where -- static method native jrtGetRuntime java.lang.Runtime.getRuntime :: () -> IO (JRuntime RealWorld) -- instance method (the type of the first param. is the one defined) native jrtFreeMemory freeMemory :: JRuntime RealWorld -> IO Long getFreeMemory :: () -> IO Long getFreeMemory () = do runtime <- JRuntime.jrtGetRuntime () runtime.jrtFreeMemory -- when the native called routine throws Exceptions native getSysProp java.lang.System.getProperty :: String -> IO (Exception (Maybe String)) -- a pure method pure native stringLastIndexOf StringExtra.lastIndexOf :: String -> Char -> Int
-- file src/pkgdir/Test1.fr module pkgdir.Test where import pkgdir.MyNativeInterface -- testSysProp :: String -> IO () testSysProp name = do eitherRes <- getSysProp name -- :: IO (Exception (Maybe String)) case eitherRes of Left excep -> println $ "exception: " ++ excep.getMessage Right maybeResult -> case maybeResult of Just strRes -> println $ "system prop. "++ name ++ " is: " ++ strRes Nothing -> println $ name ++ " system prop. is not defined" -- testStrLastIndexOf :: String -> Char -> IO () testStrLastIndexOf string ch = println $ "stringLastIndexOf "++ show string ++ " "++ show ch ++" is: "++ show pos where pos = stringLastIndexOf string ch main _ = do mem <- getFreeMemory () println $ "freeMem: " ++ show mem testSysProp "myprop" testStrLastIndexOf "abc/def/ghi" '/'
running:
# set FREGE_HOME to where it is installed # cd to src parent dir. $ mkdir classes # compile Java files $ javac -cp classes:$FREGE_HOME/fregec.jar -d classes src/pkgdir/StringExtra.java # compile Frege files $ java -Xss1m -jar $FREGE_HOME/fregec.jar -d classes src/pkgdir/MyNativeInterface.fr src/pkgdir/Test1.fr # run $ java -cp classes:$FREGE_HOME/fregec.jar -Dmyprop=mypropval pkgdir.Test freeMem: 28196256 system prop. myprop is: mypropval stringLastIndexOf "abc/def/ghi" '/' is: 7
References [edit]
- ^ a b The Frege project
- ^ Downloads Language reference.
- ^ What is frege (or what will it be)? Historical post.
- ^ a b PreludeBase.fr
- ^ Monadic related functionality
- ^ Frege project - Getting started
External links [edit]
In depth [edit]
- Language reference
- downloads
- Frege Prelude and standard libraries (html docs to download) see doc/frege; subversion code repository source view
- Frege examples