diff --git a/Makefile b/Makefile index 002d6a16..7a8023b9 100644 --- a/Makefile +++ b/Makefile @@ -209,7 +209,7 @@ SOURCES = $(COMPS)/Scanner.fr $(COMPS)/Classtools.fr \ $(COMPS)/Javatypes.fr $(COMPS)/Kinds.fr \ $(COMPS)/Transdef.fr $(COMPS)/Classes.fr \ $(COMPS)/Transform.fr \ - $(COMPS)/tc/Methods.fr \ + $(COMPS)/tc/Methods.fr $(COMPS)/tc/Patterns.fr \ $(COMPS)/Typecheck.fr \ $(COMPS)/tc/Util.fr \ $(COMPS)/gen/Util.fr $(COMPS)/gen/Const.fr \ @@ -226,7 +226,7 @@ CLASSES = $(COMPF1)/Scanner.class $(COMPF1)/Classtools.class \ $(COMPF1)/Javatypes.class $(COMPF1)/Kinds.class $(COMPF1)/Transdef.class \ $(COMPF1)/tc/Util.class \ $(COMPF1)/TAlias.class $(COMPF1)/Classes.class \ - $(COMPF1)/tc/Methods.class \ + $(COMPF1)/tc/Methods.class $(COMPF1)/tc/Patterns.class \ $(COMPF1)/Typecheck.class $(COMPF1)/Transform.class \ $(COMPF1)/gen/Util.class $(COMPF1)/gen/Const.class \ $(COMPF1)/gen/Bindings.class $(COMPF1)/gen/Match.class \ @@ -248,6 +248,8 @@ $(DIR1)/List.class: frege/List.fr $(FREGEC0) $? $(CONTROL1)/Monoid.class: frege/control/Monoid.fr $(FREGEC0) $? +$(COMPF1)/tc/Patterns.class: frege/compiler/tc/Patterns.fr + $(FREGEC0) -make $? $(COMPF1)/tc/Methods.class: frege/compiler/tc/Methods.fr $(FREGEC0) -make $? $(COMPF1)/Classtools.class: frege/compiler/Classtools.fr diff --git a/examples/CommandLineClock.fr b/examples/CommandLineClock.fr index b879ee36..8927e543 100644 --- a/examples/CommandLineClock.fr +++ b/examples/CommandLineClock.fr @@ -31,7 +31,8 @@ current = do - throws ... throws .... -} -native sleep java.lang.Thread.sleep :: Long -> IO () throws InterruptedException +-- .... defined in frege.java.Lang +-- native sleep java.lang.Thread.sleep :: Long -> IO () throws InterruptedException main args = @@ -39,5 +40,5 @@ main args = current >>= print print "\r" stdout.flush - sleep 999L + Thread.sleep 999L \ No newline at end of file diff --git a/examples/NumericLiterals.fr b/examples/NumericLiterals.fr new file mode 100644 index 00000000..e8c7e508 --- /dev/null +++ b/examples/NumericLiterals.fr @@ -0,0 +1,100 @@ +{-- + The following module exemplifies the _flexibly typed numeric literal_ (FTNL) typing rules. + + A numeric literal with a suffix (one of 'l', 'n', 'f', 'd', 'L', 'N', 'F', 'D' ) is + never a FTNL. The type is fixed to 'Long', 'Integer', 'Double' or 'Float'. + + An integer FTNL is either @0@ or a non-null digit followed by arbitrary many digits, + without suffix letter. Octal literals (which are starting with @0@ and have at least one + further digit) and hexadecimal literals (starting with @0x@) are not FTNLs, rather, + their type is invariably 'Int'. + + A floating point FTNL is a number in decimal or scientific notation, without suffix letter. + + -} + +module examples.NumericLiterals where + +import Prelude.Floating + +{-- + 1. If there is one and only one numeric type (that is, instance of type class 'Num') + that is valid for the integer FTNL, + then the literal denotes a value of that type. + + Since @n@ is 'Integer', both literals must be 'Integer' + -} +rule1 :: Integer -> Bool +{-- Alternativly, the following types would be possible: + > rule1 :: Int -> Bool + > rule1 :: Long -> Bool + > rule1 :: Integral i => i -> Bool + -} +rule1 n = n `rem` 2 != 0 + +--- Since @x@ is 'Float', both literals must be 'Float' literals. +--- Alternativly, the following types would be possible: +--- > rule1d :: Double -> Double +--- > rule1d :: Real r => r -> r +rule1d :: Float -> Float +rule1d x = 0.5 * x + 1 + + + +{-- + 2. If only a type that is an instance of 'Real', 'PrimitiveFloating' + or some class that has 'Real' as superclass would be valid, + it denotes a value of type 'Double'. + + Since + + > sqrt :: Floating α => α -> α + > (**) :: Floating α => α -> α -> α + + and 'Floating' is a subclass of 'Real', both literals will be 'Double'. + -} +-- rule2 :: Float -- also possible +-- rule2 :: Floating r => r -- also possible (see below) +-- rule2 :: Double -- default +rule2 = sqrt 2 ** 7 + +{-- + 3. If a type signature is present which forces the type to be polymorphic, + the literal will be replaced by an application of 'fromInt' or 'fromDouble' + to the same literal + (which then itself will get typed as 'Int' or 'Double' by the previous rules). + + Because of the type signature, the literals must be polymorphic, which is achieved + through implicit application of 'fromInt' to @7@ and 'fromDouble' to @2.0@. + However, this requires that type variables + that stand for the type of the literal must have a constraint that + ensures they are numbers, i.e. instances of (a subclass of) 'Num'. + + -} +rule3a :: Floating r => r +rule3a = sqrt 2.0 ** 7 + +rule3b :: Integral n => n -> Bool +rule3b n = n `rem` 2 != 0 + +-- inferred type is more constrained than expected type +-- inferred: Num a => a -> a +-- expected: a -> a +-- rule3c :: a -> a +-- rule3c n = n + 2 + +{-- + 4. If the type of an integer literal cannot be determined by the rules above, + it defaults to 'Int'. + + The functions 'rem' and '!=' are polymorphic over 'Integral'/'Eq' types, + so no concrete type is enforced by the code, and rules 2 and 3 above + are not applicable. Therefore, it defaults to 'Int'. +-} +rule4 n = n `rem` 2 != 0 + +--- @2.0@ gets type 'Double' since the type ox @x@ is unknown. +rule4d x = x / 2.0 + + + diff --git a/frege/Prelude.fr b/frege/Prelude.fr index 116cab65..d2ccff55 100644 --- a/frege/Prelude.fr +++ b/frege/Prelude.fr @@ -2,7 +2,8 @@ package frege.Prelude where import frege.prelude.PreludeBase public hiding(Ordering) -import frege.prelude.PreludeBase public (Ordering(Eq EQ, Lt LT, Gt GT)) +-- provide some names Haskellers are used to +import frege.prelude.PreludeBase public (Ordering(Eq EQ, Lt LT, Gt GT), != /=) import frege.prelude.PreludeBase public (from toEnum, ord fromEnum) import frege.prelude.PreludeNative public import frege.prelude.PreludeList public diff --git a/frege/compiler/Data.fr b/frege/compiler/Data.fr index 12cb2f03..a538f502 100644 --- a/frege/compiler/Data.fr +++ b/frege/compiler/Data.fr @@ -245,6 +245,7 @@ pPreludeText = Pack.new "frege.prelude.PreludeText" pPreludeList = Pack.new "frege.prelude.PreludeList" pPreludeMonad = Pack.new "frege.prelude.PreludeMonad" pPreludeIO = Pack.new "frege.prelude.PreludeIO" +pPreludeMath = Pack.new "frege.prelude.Math" {-- List of Prelude packages and the namespace that needs to be assigned on import time diff --git a/frege/compiler/Fixdefs.fr b/frege/compiler/Fixdefs.fr index 00ef0b1b..c11ce2d6 100644 --- a/frege/compiler/Fixdefs.fr +++ b/frege/compiler/Fixdefs.fr @@ -12,7 +12,7 @@ package frege.compiler.Fixdefs where - +import frege.Prelude hiding(<+>) import frege.List(Tree) -- import all from data diff --git a/frege/compiler/GUtil.fr b/frege/compiler/GUtil.fr index d3ad93be..0743a3d6 100644 --- a/frege/compiler/GUtil.fr +++ b/frege/compiler/GUtil.fr @@ -49,6 +49,7 @@ package frege.compiler.GUtil where +import frege.Prelude hiding(<+>) import frege.List(Tree, keyvalues, keys, insertkv) import Data.List as DL(elemBy) diff --git a/frege/compiler/GenJava7.fr b/frege/compiler/GenJava7.fr index 4e1d6716..0274f2f3 100644 --- a/frege/compiler/GenJava7.fr +++ b/frege/compiler/GenJava7.fr @@ -60,7 +60,7 @@ package frege.compiler.GenJava7 where -import frege.Prelude hiding(apply) +import frege.Prelude hiding(apply, <+>) import frege.List (Tree, values, keys, each, insert, lookup, insertkv, updatekv) import Data.List as DL(sortBy, partitioned) @@ -1231,10 +1231,10 @@ cafCode (sym@SymV {depth = 0, expr = Just x}) binds = do code <- compiling sym (genStmts (autoboxed rtype) x binds) case badguard of Just (Left x) -> do - U.warn (getpos x) (msgdoc ("guard (" ++ nice x g ++ ") may evaluate to false.")) + U.warn (getpos x) (msgdoc ("guard (" ++ nicer x g ++ ") may evaluate to false.")) stio (Right (code ++ jthrow)) Just (Right p) -> do - U.warn (getpos p) (msgdoc ("pattern guard (" ++ nice p g ++ ") may fail to match.")) + U.warn (getpos p) (msgdoc ("pattern guard (" ++ nicer p g ++ ") may fail to match.")) stio (Right (code ++ jthrow)) Nothing -> stio (Right code) @@ -1749,14 +1749,14 @@ genLambda rm (Lam {pat, ex}) ((arg@(_, _, _, s)) : args) binds = do Just p -> do U.warn (getpos pat) (msgdoc ("function pattern is refutable, " ++ "consider adding a case for " - ++ nice p g)) + ++ nicer p g)) stio (code ++ jthrow) _ -> case badguard of Just (Left x) -> do - U.warn (getpos x) (msgdoc ("guard (" ++ nice x g ++ ") may evaluate to false.")) + U.warn (getpos x) (msgdoc ("guard (" ++ nicer x g ++ ") may evaluate to false.")) stio (code ++ jthrow) Just (Right p) -> do - U.warn (getpos p) (msgdoc ("pattern guard (" ++ nice p g ++ ") may fail to match.")) + U.warn (getpos p) (msgdoc ("pattern guard (" ++ nicer p g ++ ") may fail to match.")) stio (code ++ jthrow) Nothing -> stio code diff --git a/frege/compiler/GenMeta.fr b/frege/compiler/GenMeta.fr index 0e20911e..ca5527e2 100644 --- a/frege/compiler/GenMeta.fr +++ b/frege/compiler/GenMeta.fr @@ -46,7 +46,8 @@ package frege.compiler.GenMeta where -import frege.Prelude except(print,println,break) +import frege.Prelude except(print,println,break,<+>) + import frege.List (Tree, insertkv, keys, each, values) import Data.List as DL(sortBy) @@ -183,7 +184,7 @@ banner v = do text "This code was generated with the frege compiler version", text v, text "from", - text g.options.source, + text ((´\\´.matcher g.options.source).replaceAll "/"), text "Do not edit this file!", text "Instead, edit the source file and recompile."]) "*/") println "" diff --git a/frege/compiler/Grammar.y b/frege/compiler/Grammar.y index 29e0f3e9..9464253d 100644 --- a/frege/compiler/Grammar.y +++ b/frege/compiler/Grammar.y @@ -36,7 +36,7 @@ «•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•» */ /** -* This is the grammar for the Frege language ($Revision$). +* This is the grammar for the Frege language. */ package frege.compiler.Grammar where @@ -44,6 +44,7 @@ package frege.compiler.Grammar where * !!! DO NOT CHANGE FILE Grammar.fr, IT HAS BEEN CREATED AUTOMATICALLY !!! */ +import frege.Prelude hiding(<+>) import frege.List(Tree, keyvalues, keys, insertkv) import Data.List as DL(elemBy) diff --git a/frege/compiler/Kinds.fr b/frege/compiler/Kinds.fr index 45595335..d9d59764 100644 --- a/frege/compiler/Kinds.fr +++ b/frege/compiler/Kinds.fr @@ -39,6 +39,8 @@ module frege.compiler.Kinds where +import frege.Prelude hiding(<+>) + import frege.compiler.Data import frege.compiler.Nice except (group, break) import frege.compiler.Utilities as U() diff --git a/frege/compiler/Nice.fr b/frege/compiler/Nice.fr index 310a03ac..85a7fa85 100644 --- a/frege/compiler/Nice.fr +++ b/frege/compiler/Nice.fr @@ -52,7 +52,7 @@ package frege.compiler.Nice where -import frege.Prelude except(break) +import frege.Prelude except(break, <+>) import Data.List(intersperse) import frege.compiler.Data import frege.lib.PP public except (line) diff --git a/frege/compiler/Scanner.fr b/frege/compiler/Scanner.fr index a839b06f..cededcc8 100644 --- a/frege/compiler/Scanner.fr +++ b/frege/compiler/Scanner.fr @@ -64,18 +64,10 @@ -} -{- - * $Author$ - * $Revision$ - * $Date$ - * $Id$ - -} + package frege.compiler.Scanner where ---- This is $Revision$ -public version = v "$Revision$" where - v (m ~ #(\d+)#) | Just g <- m.group 1 = g.atoi - v _ = 0 +import frege.Prelude hiding(<+>) -- import of library packages diff --git a/frege/compiler/Transform.fr b/frege/compiler/Transform.fr index a3c10357..54281c14 100644 --- a/frege/compiler/Transform.fr +++ b/frege/compiler/Transform.fr @@ -44,6 +44,7 @@ package frege.compiler.Transform where +import frege.Prelude hiding(<+>) import frege.List (Tree, lookup, insert, insertkv, update, keys, values, each, fromKeys, including, contains, union, isEmpty) diff --git a/frege/compiler/Typecheck.fr b/frege/compiler/Typecheck.fr index b256176d..64f034c7 100644 --- a/frege/compiler/Typecheck.fr +++ b/frege/compiler/Typecheck.fr @@ -73,6 +73,7 @@ package frege.compiler.Typecheck where +import frege.Prelude hiding(<+>) import frege.List (Tree, values, lookup, insertkv, insert, update, keys, including, union, contains) import frege.compiler.Data @@ -84,6 +85,7 @@ import frege.compiler.Kinds as K() import frege.compiler.tc.Util import frege.compiler.Javatypes import frege.compiler.tc.Methods as M() +import frege.compiler.tc.Patterns post = stio true @@ -667,6 +669,15 @@ rhoRegex = RhoTau [] (TCon {pos=Position.null,name=TName pPreludeNative "Rege rhoMatcher = RhoTau [] (TCon {pos=Position.null,name=TName pPreludeNative "Matcher"}) rhoInteger = rhoFor "Integer" tauString = TApp (tc "StringJ") (tc "Char") +numVar = ForAll [("int", KType)] + RhoTau{context=[Ctx{pos, cname=TName pPreludeBase "Num", tau}], tau} + where tau = TVar{pos, kind=KType, var="int"} + pos = Position.null +realVar = ForAll [("int", KType)] + RhoTau{context=[Ctx{pos, cname=TName pPreludeBase "Real", tau}], tau} + where tau = TVar{pos, kind=KType, var="int"} + pos = Position.null + instance Nice Nice z => Maybe z where nicer (Just x) g = x.nicer g @@ -676,16 +687,24 @@ instance Nice Nice z => Maybe z where tcRho' :: Expr -> Expected Rho -> StG Expr -tcRho' (x@Lit {pos,kind}) ety = case kind of - LBool -> instRho x (rhoBool) ety - LChar -> instRho x (rhoChar) ety - LString -> instRho x (rhoString) ety - LInt -> instRho x (rhoInt) ety - LLong -> instRho x (rhoLong) ety - LBig -> instRho x (rhoInteger) ety - LDouble -> instRho x (rhoDouble) ety - LFloat -> instRho x (rhoFloat) ety - LRegex -> instRho x (rhoRegex) ety +tcRho' (x@Lit {pos,kind, value}) ety = case kind of + LBool -> instRho x (rhoBool) ety + LChar -> instRho x (rhoChar) ety + LString -> instRho x (rhoString) ety + LInt -> if isDWIM LInt value then do + r <- instantiate numVar + let t = maybe r Sigma.rho x.typ + instRho x t ety + else instRho x (rhoInt) ety + LLong -> instRho x (rhoLong) ety + LBig -> instRho x (rhoInteger) ety + LDouble -> if isDWIM LDouble value then do + r <- instantiate realVar + let t = maybe r Sigma.rho x.typ + instRho x t ety + else instRho x (rhoDouble) ety + LFloat -> instRho x (rhoFloat) ety + LRegex -> instRho x (rhoRegex) ety tcRho' (x@Vbl {name}) ety = do @@ -733,13 +752,15 @@ tcRho' (x@Case {ex,alts}) ety instSigma x.{ex, alts} asig ety where checkAlt rho ety (alt@CAlt {ex,pat}) = do + (pat,ex) <- dwimPatEx pat ex checkPat pat (ForAll [] rho) ex <- tcRho ex ety - stio alt.{ex} + stio alt.{pat,ex} tcAlt rho (alt@CAlt {ex,pat}) = do + (pat,ex) <- dwimPatEx pat ex checkPat pat (ForAll [] rho) (rho, ex) <- inferRho ex - stio (rho, alt.{ex}) + stio (rho, alt.{pat, ex}) tcRho' (x@Let {env,ex}) ety = do g <- getST @@ -747,12 +768,16 @@ tcRho' (x@Let {env,ex}) ety = do ex <- tcRho ex ety instSigma x.{env, ex} (unJust ex.typ) ety -tcRho' (x@Lam {pat,ex}) (ety@Check rho) = do +tcRho' (lam@Lam {pat,ex}) (ety@Check rho) = do + (pat, ex) <- dwimPatEx pat ex + let x = lam.{pat, ex} (asig, brho) <- unifyFun x rho checkPat pat asig ex <- checkRho ex brho instRho x.{ex} (RhoFun [] asig (unJust ex.typ).rho) ety -tcRho' (x@Lam {}) ety = do +tcRho' (lam@Lam {}) ety = do + (pat, ex) <- dwimPatEx lam.pat lam.ex + let x = lam.{pat, ex} sigma <- inferPat x.pat (rho, ex) <- inferRho x.ex instRho (x.{ex}) (RhoFun [] sigma rho) ety @@ -934,9 +959,76 @@ tcPat' p _ = do g <- getST U.fatal (getpos p) (text ("can't tcPat: " ++ p.nice g)) +private real = TName{pack=pPreludeBase, base="Real"} +private num = TName{pack=pPreludeBase, base="Num"} + +--- Type the literals +literalType ctxs (lit@Lit{pos, kind, value, typ=Just sigma}) + | kind != LInt, kind != LDouble = return (Left lit) + | kind == LInt, isDWIM LInt value, RhoTau _ tau <- sigma.rho = do + + tau <- reduced tau + + case tau of + TCon{pos, name} + | name == rhoInt.tau.name = return (Right lit) + | name == rhoLong.tau.name = return (Right lit.{kind=LLong, value <- (++"L")}) + | name == rhoInteger.tau.name = return (Right lit.{kind=LBig}) + | name == rhoFloat.tau.name = return (Right lit.{kind=LFloat, value <- (++"F")}) + | name == rhoDouble.tau.name = return (Right lit.{kind=LDouble, value <- (++"D")}) + | otherwise = fromInt + Meta Flexi{uid, ref, hint, kind} = do -- unbound, because already reduced + g <- getST + rctxs <- reducedCtxs ctxs + let qns = [ cname | + Ctx{pos, cname, tau = Meta Flexi{uid=id}} <- rctxs, + uid == id ] + if (real `elem` qns + || TName{pack=pPreludeMath, base="PrimitiveFloating"} `elem` qns + || any (U.isSuper real g) qns) + then instRho lit.{kind=LDouble, value <- (++"D")} sigma.rho (Check rhoDouble) + >>= return . Right -- infer Double + else checkRho lit rhoInt + >>= return . Right -- infer Int + Meta Rigid{} -> fromInt + TApp _ _ -> fromInt -- force type error unless Num + default -> do + x <- checkRho lit rhoInt -- fix unresolved to Int + return (Right x) -- or force type error + | kind == LDouble, isDWIM LDouble value, RhoTau _ tau <- sigma.rho = do + g <- getST + tau <- reduced tau + + case tau of + TCon{pos, name} + | name == rhoFloat.tau.name = return (Right lit.{kind=LFloat, value <- (++"F")}) + | name == rhoDouble.tau.name = return (Right lit.{kind=LDouble, value <- (++"D")}) + | otherwise = fromDouble + Meta Rigid{} -> fromDouble + TApp _ _ -> fromDouble -- force type error unless Real + default -> do + x <- checkRho lit rhoDouble -- fix unresolved to Double + return (Right x) -- or force type error + | kind == LDouble = checkRho lit rhoDouble >>= return . Right -- no DWIM + | otherwise = checkRho lit rhoInt >>= return . Right -- no DWIM + where + frmIntlit = nApp frmInt lit.{typ=Just sigInt} + frmDbllit = nApp frmDbl lit.{typ=Just sigDouble} + frmInt = Vbl{pos = pos.change VARID "fromInt", + name = MName{tynm=num, base="fromInt"}, typ=Nothing} + frmDbl = Vbl{pos= pos.change VARID "fromDouble", + name = MName{tynm=real, base="fromDouble"}, typ=Nothing} + fromInt = checkRho frmIntlit sigma.rho >>= return . Right + fromDouble = checkRho frmDbllit sigma.rho >>= return . Right +literalType _ x = return (Left x) + + + --- Resolve the x.m finally --- Resolve overloaded methods -resolveHas = mapEx true rHas +resolveHas expr = do + ctxs <- collectConstrs expr + mapEx true (literalType ctxs) expr >>= mapEx true rHas where rHas (x@Mem{ex, member, typ = Just sigma}) = do app <- checkRho x.{typ = Nothing} sigma.rho -- now type of ex should be known diff --git a/frege/compiler/Utilities.fr b/frege/compiler/Utilities.fr index bd6989e2..cfbbe65c 100644 --- a/frege/compiler/Utilities.fr +++ b/frege/compiler/Utilities.fr @@ -42,7 +42,7 @@ package frege.compiler.Utilities inline (isFun) where -import frege.Prelude except (error, print, println, break) +import frege.Prelude except (error, print, println, break, <+>) import frege.List (Tree, Map, OrdSet, updatekv, insertkv, union, including, contains, keys, values, fromKeys) import Data.List as DL(partitioned, sortBy, minimumBy) diff --git a/frege/compiler/gen/Bindings.fr b/frege/compiler/gen/Bindings.fr index 6da7ba53..c35b5bc0 100644 --- a/frege/compiler/gen/Bindings.fr +++ b/frege/compiler/gen/Bindings.fr @@ -46,6 +46,8 @@ module frege.compiler.gen.Bindings inline (adaptSigma, adaptSigmaWith) where +import frege.Prelude hiding(<+>) + import frege.List (insertkv) import Data.List as DL(zip4) diff --git a/frege/compiler/gen/Match.fr b/frege/compiler/gen/Match.fr index a7d18b37..b4816ad0 100644 --- a/frege/compiler/gen/Match.fr +++ b/frege/compiler/gen/Match.fr @@ -44,7 +44,7 @@ package frege.compiler.gen.Match where -import frege.Prelude hiding(apply) +import frege.Prelude hiding(apply, <+>) import frege.List (Tree, values, keys, each, insert, lookup, insertkv, updatekv) import Data.List as DL(sortBy, partitioned) diff --git a/frege/compiler/gen/Util.fr b/frege/compiler/gen/Util.fr index 206d9ca0..670f31ac 100644 --- a/frege/compiler/gen/Util.fr +++ b/frege/compiler/gen/Util.fr @@ -40,7 +40,8 @@ package frege.compiler.gen.Util where -import frege.Prelude except(print,println,break) +import frege.Prelude except(print, println, break, <+>) + import frege.List (values) import frege.compiler.Data import frege.compiler.Utilities as U(print, println) diff --git a/frege/compiler/tc/Patterns.fr b/frege/compiler/tc/Patterns.fr new file mode 100644 index 00000000..14f9da4d --- /dev/null +++ b/frege/compiler/tc/Patterns.fr @@ -0,0 +1,81 @@ +--- Work with DWIM patterns +module frege.compiler.tc.Patterns where + +import frege.compiler.Data +import frege.compiler.Utilities as U() + +{-- + Check if literal is a "do what I mean" literal, i.e. one that could + have a flexible type: + + - 'Int' literals in decimal without any suffix + - 'Double' literals without suffix +-} +isDWIM LInt ´^[1-9]\d*$´ = true +isDWIM LInt "0" = true +isDWIM LDouble ´\d$´ = true +isDWIM _ _ = false + +eq = Vbl{pos = Position.null, + name = MName{tynm=TName{pack=pPreludeBase, base="Eq"}, base="=="}, + typ=Nothing} + +{-- + Replace certain numeric literals in 'Pattern's and with variables + and return a list of expressions of the form + + > v == 123 + + The patterns that qualify for replacement are determinded by 'isDWIM'. + The idea is to have + + > foo 123 = x + + changed to + + > foo dwim | 123 == dwim = x + +-} +replDWIM :: Pattern -> StG (Pattern, [Expr]) +replDWIM p = case p of + PLit{pos, kind, value} -> do -- undefined -- TODO: complete code + if isDWIM kind value then do + uid <- U.uniqid + let pvar = PVar{pos, uid, var = "dwim" ++ show uid} + xvar = Vbl{pos, name = Local{uid, base="dwim"}, typ = Nothing} + xlit = Lit{pos, kind, value, typ=Nothing} + U.enter (U.patLocal pos uid pvar.var) + return (PUser{pat = pvar, lazy = false}, [eq `nApp` xlit `nApp` xvar]) + else return (p, []) + PVar{pos, uid, var} -> return (p, []) + PMat{pos, uid, var, value} -> return (p, []) + PCon{pos, qname, pats} -> do + pxs <- mapM replDWIM pats + return (p.{pats=map fst pxs}, fold (++) [] (map snd pxs)) + -- PConFS{pos, qname, fields} -> undefined -- handled below + _ | p.{pat?} = do + (pat, xs) <- replDWIM p.pat + return (p.{pat}; xs) + | otherwise = error "illegal pattern" + +{-- + Transform + + > pat -> ex + + to + + > pat | lit == dwim = ex + + This works for lambdas and case alternatives alike. +-} +dwimPatEx pat ex = do + (p, xs) <- replDWIM pat + case xs of + [] -> return (pat, ex) + _ -> return (p, newex) where + newex = foldr casewhen ex xs + casewhen cond ex = Case{ckind=CWhen, ex=cond, alts=[alt], typ=Nothing} where + alt = CAlt{pat = PLit{pos=getpos cond, kind=LBool, value="true"}, ex} + + diff --git a/frege/compiler/tc/Util.fr b/frege/compiler/tc/Util.fr index 9de15988..e9f5969b 100644 --- a/frege/compiler/tc/Util.fr +++ b/frege/compiler/tc/Util.fr @@ -41,6 +41,8 @@ package frege.compiler.tc.Util where +import frege.Prelude hiding(<+>) + import frege.List (Tree, values, lookup, insert, update, keys, including, union, contains) import Data.List as DL(unique, uniq, sort, elemBy, partition) diff --git a/frege/control/monad/Reader.fr b/frege/control/monad/Reader.fr index 5da696a4..5cb72506 100644 --- a/frege/control/monad/Reader.fr +++ b/frege/control/monad/Reader.fr @@ -1,6 +1,6 @@ package frege.control.monad.Reader where -import frege.Prelude hiding (id, .) +import frege.Prelude hiding (id, Reader) import frege.control.Category import frege.control.arrow.Kleisli import frege.data.wrapper.Identity diff --git a/frege/java/Lang.fr b/frege/java/Lang.fr index 4aeaeaad..8381c0cc 100644 --- a/frege/java/Lang.fr +++ b/frege/java/Lang.fr @@ -45,6 +45,7 @@ protected package frege.java.Lang where import frege.prelude.PreludeBase import frege.prelude.PreludeBase public(Throwable, Object, ClassNotFoundException, + NumberFormatException, InterruptedException) import frege.prelude.PreludeIO (Exceptional, Mutable, MutableIO) import frege.prelude.PreludeIO public(Exception) diff --git a/frege/lib/PP.fr b/frege/lib/PP.fr index 4b8527e9..e69ce22c 100644 --- a/frege/lib/PP.fr +++ b/frege/lib/PP.fr @@ -1,4 +1,3 @@ --- enable UTF-8 ««««««««««««««•••••••••••••»»»»»»»»»»»»¦¦¦¦¦¦¦¦ {-- Courtesy of Philip Wadler. @@ -11,18 +10,12 @@ * Author: Philip Wadler, Professor of Theoretical Computer Science * School of Informatics, University of Edinburgh * Ported to Frege: Ingo Wechsung - * $Revision$ - * $Date$ - * $Id$ * -} package frege.lib.PP where ---- This is $Revision$ -protected version = v "$Revision$" where - v (m ~ #(\d+)#) | Just g <- m.group 1 = g.atoi - v _ = 0 +import frege.Prelude hiding(<+>) infixr 9 `GROUP` -- :<|> diff --git a/frege/prelude/PreludeBase.fr b/frege/prelude/PreludeBase.fr index a624e6b7..86ec5a3d 100644 --- a/frege/prelude/PreludeBase.fr +++ b/frege/prelude/PreludeBase.fr @@ -85,8 +85,9 @@ Uncommon characters defined here: protected package frege.prelude.PreludeBase inline candidates (otherwise, id, const, asTypeOf, $!, $, •, flip, curry, und, oder, - ST.>>= + ST.>>=, -- State.put, State.change, State.>>=, State.>>, State.return, -- State.run, + Int.fromInt, Double.fromDouble ) where @@ -138,7 +139,7 @@ class Eq eq where --- Ayn Rand's favorite law --- > a == a --- shall be obeyed by all implementations. - (==), (/=) :: eq -> eq -> Bool -- must be defined in instances + (==) :: eq -> eq -> Bool -- must be defined in instances --- Check for inequality. The default implementation obeys the laws --- > !(a != a) --- > (a != b) == !(a == b) @@ -146,8 +147,6 @@ class Eq eq where --- These laws shall also be obeyed in all implementations. (!=) :: eq -> eq -> Bool a!=b = if a==b then false else true -- may be replaced by more efficient version - --- provided for Haskell compatibility as an alias for '!=' - (/=) = (!=) --- Compute a hash code. --- The follwoing rules shall hold in all instances: --- > a == b ==> hashCode a == hashCode b @@ -735,7 +734,7 @@ data GuardFailed = pure native frege.runtime.GuardFailed protected data NumberFormatException = pure native java.lang.NumberFormatException --- Forward declaration of @java.lang.ClassNotFoundException@ - protected data ClassNotFoundException +protected data ClassNotFoundException = pure native java.lang.ClassNotFoundException --- This is the standard undefined value. @@ -1060,6 +1059,8 @@ class Num Ord n => n where class Real Num r => r where --- the division operator (/) :: r -> r -> r + --- convert a 'Doubloe' to any 'Real' value + fromDouble :: Double -> r @@ -1543,9 +1544,11 @@ instance Real Float where zero = 0.0f one = 1.0f pure native negate "-" :: Float -> Float - fromInt i = i.float + fromInt i = i.float + fromDouble d = d.float pure native isInfinite java.lang.Float.isInfinite :: Float -> Bool pure native isNaN java.lang.Float.isNaN :: Float -> Bool + -- ################# Double Instances ############# @@ -1574,7 +1577,8 @@ instance Real Double where zero = 0.0 one = 1.0 pure native negate "-" :: Double -> Double - fromInt i = i.double + fromInt i = i.double + fromDouble d = d pure native isInfinite java.lang.Double.isInfinite :: Double -> Bool pure native isNaN java.lang.Double.isNaN :: Double -> Bool diff --git a/shadow/frege/java/Lang.fr b/shadow/frege/java/Lang.fr index 4aeaeaad..8381c0cc 100644 --- a/shadow/frege/java/Lang.fr +++ b/shadow/frege/java/Lang.fr @@ -45,6 +45,7 @@ protected package frege.java.Lang where import frege.prelude.PreludeBase import frege.prelude.PreludeBase public(Throwable, Object, ClassNotFoundException, + NumberFormatException, InterruptedException) import frege.prelude.PreludeIO (Exceptional, Mutable, MutableIO) import frege.prelude.PreludeIO public(Exception) diff --git a/shadow/frege/prelude/PreludeBase.fr b/shadow/frege/prelude/PreludeBase.fr index d2037c39..86ec5a3d 100644 --- a/shadow/frege/prelude/PreludeBase.fr +++ b/shadow/frege/prelude/PreludeBase.fr @@ -84,9 +84,10 @@ Uncommon characters defined here: -} protected package frege.prelude.PreludeBase - inline candidates (otherwise, id, const, asTypeOf, $!, $, •, flip, curry, - ST.>>= + inline candidates (otherwise, id, const, asTypeOf, $!, $, •, flip, curry, und, oder, + ST.>>=, -- State.put, State.change, State.>>=, State.>>, State.return, -- State.run, + Int.fromInt, Double.fromDouble ) where @@ -105,7 +106,7 @@ infix 15 `=~` `!~` `?~` `/~` `~` `~~` `~~~` infixl 14 `*` `/` `%` `mod` `rem` `div` `quot` infix 14 `\\` infixl 13 `+` -- `-` is handled specially -infixr 13 `++` mplus +infixr 13 `++` `<+>` mplus infixl 12 `<<` `bshl` `bshr` `ushr` infixl 11 `band` infixl 10 `bor` `bxor` @@ -117,7 +118,7 @@ infixr 5 `||` `oder` `^^` -- infix 4 `..` infixr 4 `:` infixl 4 `<$>` `<*>` `<*` `*>` fmap -infixl 3 `>>` `>>=` -- monad bind +infixl 3 `>>` `>>=` `<|>` -- monad bind infixr 3 `<=<` `>=>` -- Kleisli opeartors infixr 2 `:=` `=<<` `@` `seq` -- so that in x@a:bs x is bound to the list infixl 2 either catch finally @@ -138,7 +139,7 @@ class Eq eq where --- Ayn Rand's favorite law --- > a == a --- shall be obeyed by all implementations. - (==), (/=) :: eq -> eq -> Bool -- must be defined in instances + (==) :: eq -> eq -> Bool -- must be defined in instances --- Check for inequality. The default implementation obeys the laws --- > !(a != a) --- > (a != b) == !(a == b) @@ -146,8 +147,6 @@ class Eq eq where --- These laws shall also be obeyed in all implementations. (!=) :: eq -> eq -> Bool a!=b = if a==b then false else true -- may be replaced by more efficient version - --- provided for Haskell compatibility as an alias for '!=' - (/=) = (!=) --- Compute a hash code. --- The follwoing rules shall hold in all instances: --- > a == b ==> hashCode a == hashCode b @@ -735,7 +734,7 @@ data GuardFailed = pure native frege.runtime.GuardFailed protected data NumberFormatException = pure native java.lang.NumberFormatException --- Forward declaration of @java.lang.ClassNotFoundException@ - protected data ClassNotFoundException +protected data ClassNotFoundException = pure native java.lang.ClassNotFoundException --- This is the standard undefined value. @@ -1060,6 +1059,8 @@ class Num Ord n => n where class Real Num r => r where --- the division operator (/) :: r -> r -> r + --- convert a 'Doubloe' to any 'Real' value + fromDouble :: Double -> r @@ -1543,9 +1544,11 @@ instance Real Float where zero = 0.0f one = 1.0f pure native negate "-" :: Float -> Float - fromInt i = i.float + fromInt i = i.float + fromDouble d = d.float pure native isInfinite java.lang.Float.isInfinite :: Float -> Bool pure native isNaN java.lang.Float.isNaN :: Float -> Bool + -- ################# Double Instances ############# @@ -1574,7 +1577,8 @@ instance Real Double where zero = 0.0 one = 1.0 pure native negate "-" :: Double -> Double - fromInt i = i.double + fromInt i = i.double + fromDouble d = d pure native isInfinite java.lang.Double.isInfinite :: Double -> Bool pure native isNaN java.lang.Double.isNaN :: Double -> Bool diff --git a/shadow/frege/prelude/PreludeMonad.fr b/shadow/frege/prelude/PreludeMonad.fr index 7e337f75..e43d94d7 100644 --- a/shadow/frege/prelude/PreludeMonad.fr +++ b/shadow/frege/prelude/PreludeMonad.fr @@ -92,12 +92,15 @@ class Functor f where --- Map a function over a 'Functor' fmap :: (a -> b) -> f a -> f b - +class Apply (Functor f) => f where + (<*>) :: f (a -> b) -> f a -> f b --- An infix synonym for 'fmap'. Left associative with precedence 4. (<$>) :: Functor f => (a -> b) -> f a -> f b (<$>) = fmap + + {-- A functor with application, providing operations to @@ -135,13 +138,10 @@ class Functor f where Minimal complete definition: 'return' and '<*>'. -} -class Applicative (Functor p) => p where +class Applicative (Apply p) => p where --- Lift a value - return :: a -> p a - - --- Sequential application. - (<*>) :: p (a -> b) -> p a -> p b + return :: a -> p a --- Sequence actions, discarding the value of the first argument. (*>) :: p a -> p b -> p b @@ -154,7 +154,7 @@ class Applicative (Functor p) => p where pa *> pb = return (const id) <*> pa <*> pb pa <* pb = return const <*> pa <*> pb -apply :: (Applicative p) => p (a -> b) -> p a -> p b +apply :: (Apply p) => p (a -> b) -> p a -> p b apply = (<*>) {- @@ -176,6 +176,18 @@ liftA4 f a b c d = f <$> a <*> b <*> c <*> d liftA5 :: Applicative f => (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g liftA5 f a b c d e = f <$> a <*> b <*> c <*> d <*> e +class Bind (Apply f) => f where + --- Sequentially compose two actions, passing any value produced by the first as an argument to the second. + (>>=) :: f a -> (a -> f b) -> f b + +class Alt (Functor f) => f where + (<|>) :: f a -> f a -> f a + +class Plus (Alt f) => f where + pzero :: f a + +class MonadAlt (Plus f, Monad f) => f where + (<+>) :: f a -> f a -> f a {-- The 'Monad' class defines the basic operations over a _monad_, @@ -185,8 +197,6 @@ liftA5 f a b c d e = f <$> a <*> b <*> c <*> d <*> e Frege’s *@do@* expressions provide a convenient syntax for writing monadic expressions. - Minimal complete definition: '>>=' and 'return'. - Instances of Monad should satisfy the following laws: > return a >>= k == k a @@ -204,11 +214,7 @@ liftA5 f a b c d e = f <$> a <*> b <*> c <*> d <*> e satisfy these laws. -} -class Monad (Applicative m) => m where - - --- Sequentially compose two actions, passing any value produced by the first as an argument to the second. - (>>=) :: m a -> (a -> m b) -> m b - +class Monad (Applicative m, Bind m) => m where {-- Sequentially compose two actions, discarding any value produced by the first, this works like sequencing operators (such as the semicolon) in imperative languages.