Permalink
Browse files

Merge branch 'master' of github.com:johang88/haskellinjavascript

  • Loading branch information...
2 parents 03e66ca + e702efb commit d175d1375c93dab6d1c6661d4bd862ac53cb6b39 Mattis Jeppsson committed May 17, 2010
View
@@ -671,7 +671,7 @@
var gdrhs_fix_list_action = function(p) {
return action(p, function(ast) {
- return ast[0];
+ return ast;
});
};
@@ -691,7 +691,7 @@
};
var rhs = choice( decl_rhs_action(sequence(expect(ws('=')), ws(exp), optional(sequence(expect(ws("where")), ws(decls))))),
- sequence(ws(gdrhs), optional(sequence(expect(ws("where")), ws(decls))))
+ rhs_gurad_action(sequence(ws(gdrhs), optional(sequence(expect(ws("where")), ws(decls)))))
);
// todo: Should be quite a lot of choices here, but those are for
View
@@ -29,6 +29,7 @@ otherwise = True
id x = x
+
map f xs = case xs of
[] -> []
(x:xs) -> f x : map f xs
@@ -43,11 +44,9 @@ foldr1 f xs = case xs of
[x] -> x
(x:xs) -> f x $ foldr1 f xs
-filter f xs = case xs of
- [] -> []
- (x:xs) -> case f x of
- True -> x : filter f xs
- False -> filter f xs
+filter _ [] = []
+filter f (x:xs ) | f x = x : filter f xs
+ | otherwise = filter f xs
iterate f x = f x : iterate f x
@@ -1,9 +1,9 @@
\renewcommand{\abstractname}{Abstract}
\begin{abstract}
Haskell is not a widely used programming language, nor very known to the average programmer. By implementing a subset of the Haskell 98 specification in Javascript our intention is to make it possible to run Haskell in a web browser, thus making it easier for beginners to try Haskell by eliminating the need of downloading Haskell compilers such as GHC.
+In this paper we describe the process and result from the project of implementing Haskell in Javascript.
\\
\\
-In this paper we describe the process and result from the project of implementing Haskell in Javascript.
Our result consists of a parser, type checker, interpreter and a front end similar to GHCi.
The parser process the text input, creating an internal structure called abstract syntax tree (AST). The type checker then analyse the AST to confirm that there are no type errors. If no errors have been detected, the AST is sent to the interpreter. The interpreter then interpret the AST in an well defined way.
\\
@@ -8,6 +8,9 @@ \section{Diskussion}
Vi har inte implementerat NPlusK-pattern i parsern och då de är borttagna i Haskell 2010 \citep{haskell2010} känner vi att det inte behövs.
+% TODO typcheckaren kom aldrig in i den slutgiltliga versionen. Ö:
+
+
\subsection{Framtida förbättringar}
@@ -6,7 +6,6 @@ \subsection{Bakgrund och motivation}
En fördel med att ha tolken på webben är att det enda som behövs för att använda den är en javascriptkompatibel webbläsare, något som följer med i princip i alla moderna operativsystem. Detta betyder att de användare som befinner sig inom vår målgrupp redan har den programvaran som behövs på sina hemdatorer för att använda sig av vårt program.
-
% TODO detta e out of context`
Haskell är ett starkt statiskt typcheckat och funktionellt programmeringsspråk med lat evaluering. % TODO: Citera, skriv om ifall det är direktöversatt
% jag bytte från strikt semantik till lat evaluering:p
@@ -46,15 +45,14 @@ \subsection{Metod}
%Vi kommer att integrera jQuery \citep{jquery} för att få ett unisont stöd för samtliga webbläsare. jQuery kommer även underlätta arbetet med att skapa ett enkelt och stilrent interaktivt gränssnitt.
\subsubsection{Avgränsningar}
-Att tolka Haskell i Javascript är inget trivialt projekt och därför kommer inte hela Haskell att implementeras. Vi kommer implementera en delmängd av den version av Haskell som kallas Haskell 98.
-De delar som prioriteras är
+Att tolka Haskell i Javascript är inget trivialt projekt och därför valde vi att avgränsa implementationen till de mest centrala och viktiga delarna i haskellspecifikationen. De delar vi valde att fokusera på är:
\begin{enumerate}
\item{Lambda-funktioner, namngivna funktioner}
\item{Typer, generella typer, algebraiska datatyper}
\item{Typklasser}
\item{Pattern matching}
\item{Guards}
\end{enumerate}
-Med dessa delar implementerade kan de flesta enklare haskellprogram köras och bör vara tillräckligt för det stora flertalet nybörjare. Vi kommer ej lägga någon tid på att skapa en användarvänlig webbsida utan fokus kommer ligga på att skapa haskelltolken. Dock kommer en kommandotolk som körs på en webbsida utvecklas för att kunna kommunicera med haskelltolken.
-Vi kommer inte lägga någon nämnvärd tid på att optimera haskelltolken utan målet är att göra en fungerande implementation.
+Med dessa delar implementerade kan de flesta enklare haskellprogram köras och bör vara tillräckligt för det stora flertalet nybörjare. Vi beslutade att ej lägga någon större tid på att skapa en användarvänlig webbsida, utan fokus låg på att skapa haskelltolken. Dock valde vi att utveckla en kommandotolk som skulle köras på en webbsida för att kunna kommunicera med haskelltolken.
+SLutligen beslutades det att inte optimera haskelltolken utan målet är att göra en fungerande implementation.
@@ -25,7 +25,7 @@ \subsection{Genomförande}
Arbetssättet präglades av en iterativ utvecklingsmetodik med korta utvecklingscyklar. Arbetet delades upp med huvudansvarstagande över var sin modul och utfördes parallellt med varandra. Arbetet skedde dock framförallt i samlad grupp på grund av att det var många designrelaterade problem vi var tvugna att ta ställning till under projektet, till exempel hur vårat abstrakta syntaxträd skulle se ut, och för att det skulle bli enklare när vi skulle börja sammanfoga våra olika moduler med varandra.
-Det var också ett bra sätt att snabbt få hjälp av varandra eftersom vi ej visste exakt hur modulerna skulle se ut när vi påbörjade arbetet. Vi fann det därför praktiskt att använda en iterativ modell för att bit för bit utvigda våra moduler.
+Det var också ett bra sätt att snabbt få hjälp av varandra eftersom vi ej visste exakt hur modulerna skulle se ut när vi påbörjade arbetet. Vi fann det därför praktiskt att använda en iterativ modell för att bit för bit utvigda våra moduler. Dock valde vi att implementera typcheckaren i ett steg då vi ansåg att det skulle vara enklare. Detta främst för att vi trodde typklasser var så centralt i typcheckaren att det skulle vara svårt att lägga till det i en andra iteration.
Eftersom vi arbetade parallellt med olika moduler var vi beroende av ett bra versionshanteringssystem. Bra i vårt fall innebar att det skulle vara enkelt att arbeta i olika grenar, en gren för varje modul, och att det skulle gå snabbt och enkelt att slå ihop dessa förgreningar när vi behövde länka samman två utvecklares arbeten. I början av projektet använda vi oss av SVN (Subversion). Detta berodde framförallt på att det var det versionshanteringssystem som alla i gruppen hade erfarenhet från tidigare. Dock insåg vi att SVN inte var praktiskt att använda när man arbetar i flera olika grenar i projektet samtidigt. Därför gick valet till att använda Git som är designat från grunden för att på ett enkelt sätt skapa nya och slå samman förgreningar under utvecklingens gång. Vi kunde därmed skapa en förgrening för varje modul och under arbetets gång sammanlänka allas arbeten på ett effektivt sätt.
@@ -6,13 +6,16 @@ \section{Resultat}
\subsection{Parser}
Parserns uppgift är att ta användarens indata och konvertera den till en datastruktur
som är lättare att hantera internt. Denna datastruktur kallas Abstract Syntax Tree (AST).
-haskellstandarden definerat upp en grammatik, ett antal regler, som definerar hur korrekt haskellkod ser ut och hur den ska tolkas.
+Haskellstandarden har definerat upp en grammatik, ett antal regler, som definerar hur korrekt haskellkod ser ut och hur den ska tolkas.
+
+Haskell är ett svårt språk att parsa då det inte är kontextfritt på grund av att kodens mening beror på blanksteg,
+Haskell tillåter även egendefinerade operatorer vilket också kan påverka kodens mening.
För att parsa indatan använder vi ett bibliotek för att bygga parsers kallat JSParse \citep{jsparse}.
JSParse ger oss ett antal funktioner som vi använder för att definera grammatiken och konvetera den till vår interna struktur.
-Som figur \ref{fig:parser_steg} visar, består parsern av tre mindre parsers, den första är en parser som hittar kommentarer och tar bort dessa.
-Den andra identifierar haskellkod som inte är kontextfri och gör om till kontextfri kod. Den tredje gör om den kontextfria koden till vår AST.
+Som figur \ref{fig:parser_steg} visar, består parsern av tre mindre parsers, den första är en parser som hittar kommentarer och tar bort dessa.
+Det andra tar hand om kodens layout och gör om den till kontextfri kod. Den tredje gör om den kontextfria koden till vår AST.
\begin{figure}[H]
\begin{center}
@@ -75,11 +78,13 @@ \subsubsection{Steg 2 - Konvertera till kontextfri}
Ett annat exempel är:
\begin{lstlisting}
-let x = 5 in x
+let x = 5
+ y = 4
+in x + y
\end{lstlisting}
Den korrekta översättningen är:
\begin{lstlisting}
-let { x = 5 } in x
+let { x = 5; y = 4 } in x + y
\end{lstlisting}
För att översätta detta korrekt kommer parsern ihåg den aktuella nästlingsnivån av "let"-uttryck och var deras repsektive "in"-uttryck befinner sig.
Den avslutande måsvingen sätts in där ett matchande "in"-uttryck påträffas.
@@ -126,7 +131,12 @@ \subsubsection{Steg 3 - Skapa AST}
);
\end{lstlisting}
+Här används \emph{choice} för att tolka de två olika alternativen i \emph{rhs} och om vi tittar närmare på \emph{gdrhs}
+ser vi att det är en rekursiv funktionen vilket vi implementerar med \emph{repeat1} för att få en lista med minst en uppreprning,
+\emph{gdrhs\_action}, \emph{gdrhs\_fix\_list\_action} och \emph{decl\_rhs\_action} används för att generera AST.
+
Parsern använder den metod som är specifierad i Haskell 2010 \citep{haskell2010} för att lösa företrädesreglerna (precedence levels) för operatorer då denna metoden är enklare än den som är definerad i Haskell 98.
+Anledningen till att företrädesreglerna inte kan defineras direkt i parsern är att Haskell använder sig av användardefinerade företrädesregler.
Metoden fungerar så att den löser företrädesreglerna först efter ett uttryck har parsats till en lista med operatorer
och uttryck, när en operator påträffas i listan slås dess företrädesnivå upp i en tabell och ett träd med
operatorer och uttryck skapas. Sista används trädet för att generera en AST för uttrycken.
@@ -144,9 +154,29 @@ \subsubsection{JSParse}
-\subsection{Interpretator}
+\subsection{Interpretatorns struktur}
Interpretatorns uppgift är att tolka det abstrakta syntaxträdet. Under interpreteringen används flera datastrukturer vars uppgift och struktur anges här.
+\subsubsection{HeapPtr}
+De flesta implementationer av Haskell använder sig av Lazy Evaluation vilket innebär att en Thunk, ett uttryck, kommer att tvingas maximalt en gång. I vår implementation används HeapPtr som en wrapper runt en Thunk, när en HeapPtr dereferenceras kommer Thunk att tvingas till en Weak Head Normal Form (WHNF) och HeapPtr uppdateras att peka till denna. Eftersom att tvingandet av en Thunk kan resultera i en ny Thunk så tvingas thunken i en loop till dess att resultatet är en WHNF.
+
+\begin{lstlisting}
+this.dereference = function() {
+ if (this.weakHead == undefined) {
+ // We'll drive the execution here instead of recursing
+ // in the force method
+ var continuation = this.thunk;
+ while (continuation instanceof interpreter.Thunk) {
+ continuation = continuation.force();
+ }
+ this.weakHead = continuation;
+ this.thunk = null;
+ }
+ return this.weakHead;
+};
+\end{lstlisting}
+En HeapPtr är ett vanligt Javascript-objekt som innehåller funktionen dereference. Dereference körs när anroparen vill använda den WHNF som HeapPtr pekar mot. Om HeapPtr inte har blivit dereferenserad innan så kommer dess Thunk att tvingas tills det att resultatet är en WHNF och HeapPtr objectet uppdateras till att peka mot denna.
+
\subsubsection{Thunk}
En Thunk är en avstannad beräkning, en continuation. En Thunk består av en Env och en Expression.
@@ -175,25 +205,6 @@ \subsubsection{Weak Head Normal Form}
En Primitiv är ett Javascript-värde, till exempel en integer eller en double.
-\subsubsection{HeapPtr}
-De flesta implementationer av Haskell använder sig av Lazy Evaluation, vilket innebär att en Thunk kommer att tvingas maximalt en gång. I vår implementation används HeapPtr som en wrapper runt en Thunk, när en HeapPtr dereferenceras kommer Thunk att tvingas till en WHNF och HeapPtr uppdateras att peka till denna. Eftersom att tvingandet av en Thunk kan resultera i en ny Thunk så tvingas thunken i en loop till dess att resultatet är en WHNF.
-
-\begin{lstlisting}
-this.dereference = function() {
- if (this.weakHead == undefined) {
- // We'll drive the execution here instead of recursing
- // in the force method
- var continuation = this.thunk;
- while (continuation instanceof interpreter.Thunk) {
- continuation = continuation.force();
- }
- this.weakHead = continuation;
- this.thunk = null;
- }
- return this.weakHead;
-};
-\end{lstlisting}
-
\subsubsection{Env}
Env är en stack av Javascript hashes, hasharna består av en bindning mellan en Identifier och antingen en HeapPtr eller ett (Pattern, HeapPtr) par. Den andra bindingstypen är resultatet av en VariableDeclaration där man måste utföra en pattern match för att avgöra vilken HeapPtr som hör till vilken Identifier. När man läser ut en Identifier som är bunden enligt den andra typen av binding, kommer en pattern match att utföras och alla identifiers i det pattern som matchas kommer att bindas om som den första typen alternativt en pattern match fail inträffar och ett exception genereras.
@@ -209,7 +220,7 @@ \subsubsection{Env}
}
\end{lstlisting}
-\subsection{Abstrakt syntaxträd}
+\subsection{Abstrakt syntaxträd och evaluering}
Vår AST representeras av javascript-objekt men dess strukturella uppbyggnad ges här av Haskells datadefinitioner.
\subsubsection{Declaration}
@@ -266,6 +277,8 @@ \subsubsection{Expression}
throw new Error("No matching clause");
};
\end{lstlisting}
+Detta är eval metoden för en Case expression. Här syns hur en ny Env används vid varje alternativ i Case satsen och hur granskaren delas mellan de olika alternativen.
+
Att evaluera en VariableLookup under en Env är det samma som att leta upp en Identifier i Env-objektet.
Do, List och ArithmeticSequence är inte evaluerade direkt utan de är avsockrade och sedan evalueras det avsockrade uttrycket. Avsockringsreglerna ges i Haskell 98 standarden \citep{haskell98chap3}.
@@ -450,3 +463,32 @@ \subsection{HIJi}
HIJi är skapat för att likna GHCi i så stor utsträckning som möjligt.
Genom att efterlikna GHCi kommer användare känna igen sig när de tar steget från HIJi till GHCi. Det blir för dem ett naturligt steg och kortar inlärningströskeln. Även för haskellprogrammerare som är vana användare av GHCi blir det lättare att använda sig av HIJi, de behöver inte fundera hur verktyget ska användas.
+
+\subsection{Prelude}
+I våra avgränsningar angav vi vilka delar av haskellspecifikationen vi skulle fokusera på. De delar som vi har fullt stöd för är lambda-funktioner, namngivna funktioner, algebraiska datatyper, pattern matching och guards.
+I HIJis förladdade modul, Prelude, har vi definerat upp ett antal funktioner som visar på att vi har implementerat dessa egenskaper från specifikationen.
+Alla funktioner som är definerade i Prelude är namngivna funktioner. Ett exempel på en namngiven funktion är \emph{id}.
+Algebraiska datatyper stöds och i Prelude har vi definerat upp datatypen Bool och ett par funktioner, däribland (||), som använder sig utav den här datatypen. Funktionen (||) använder sig av pattern matching. Resultatet av \emph{case x of} kommer matcha antingen mot \emph{True} eller \emph{False}.
+Funktionen \emph{filter} från Prelude är ett exempel på att guards fungerar. Filter är också ett exempel på att pattern matching och rekursiva funktioner är implementerade.
+
+\begin{lstlisting}
+-- Utdrag ur Prelude.hs
+
+-- en namngiven funktion
+id x = x
+
+-- datatypen Bool
+data Bool = True | False
+
+-- exempel av pattern match
+(||) x y = case x of
+ True -> True
+ False -> y
+
+-- exempel av pattern match,
+-- guards och rekursiva funktioner
+filter _ [] = []
+filter f (x:xs ) | f x = x : filter f xs
+ | otherwise = filter f xs
+\end{lstlisting}
+
@@ -2,14 +2,14 @@
\begin{abstract}
- Haskell är ett programmeringsspråk med hög inlärningströskel med en begränsad användarbas. Vår förhoppning är att göra det enklare för programmerare att lära sig Haskell genom att implementera språket I Javascript. På så vis blir det möjligt att köra Haskell I en webbläsare utan att behöva ladda ner en haskellkompilator som till exempel GHC.
- I den här rapporten beskriver vi vårt arbete och resultat av att implementera Haskell I Javascript.
+Haskell är ett programmeringsspråk med en begränsad användarbas. Vår förhoppning är att göra det enklare för programmerare att lära sig Haskell genom att implementera språket i Javascript. På så vis blir det möjligt att köra Haskell i en webbläsare utan att behöva ladda ner en haskellkompilator, som till exempel GHC.
+ I den här rapporten beskriver vi vårt arbete och resultat av att implementera Haskell i Javascript.
\\
\\
Resultatet består av en parser, typcheckare, interpretator och ett användargränssnitt liknande GHCi.
- Parsern tar användaren indata och konverterar den till en intärn datastruktur, kallat abstrakt syntaxträd. Typcheckaren analyserar sedan det abstrakta syntaxträdet för att kontrollera att det ej förekommer några syntaxfel. Om inga fel påträffats så skickas det trädet vidare till interpretatorn som tolkar trädet på ett väldefinerat vis.
+ Parsern tar användaren indata och konverterar den till en intärn datastruktur, kallat abstrakt syntaxträd. Typcheckaren analyserar sedan det abstrakta syntaxträdet för att kontrollera att det ej förekommer några typfel. Om inga fel har påträffats så skickas trädet vidare till interpretatorn som tolkar trädet på ett väldefinerat vis.
\\
\\
- Resultatet visar att det är möjligt att implementera Haskell I Javascript, men det behövs mycket mer arbete för att skapa en nybörjarvänlig miljö att lära sig Haskell I.
+ Resultatet visar att det är möjligt att implementera Haskell i Javascript, men det behövs mycket mer arbete för att skapa en nybörjarvänlig miljö att lära sig Haskell i.
\end{abstract}

0 comments on commit d175d13

Please sign in to comment.