diff --git a/hs/Prelude.hs b/hs/Prelude.hs index 060f11d..e6a91a0 100644 --- a/hs/Prelude.hs +++ b/hs/Prelude.hs @@ -29,6 +29,7 @@ otherwise = True id x = x + map f xs = case xs of [] -> [] (x:xs) -> f x : map f xs diff --git a/rapport/kapitel/abstract.tex b/rapport/kapitel/abstract.tex index 0e8a1a1..e310f7a 100644 --- a/rapport/kapitel/abstract.tex +++ b/rapport/kapitel/abstract.tex @@ -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. \\ diff --git a/rapport/kapitel/diskussion.tex b/rapport/kapitel/diskussion.tex index 700fa1a..28bcabb 100644 --- a/rapport/kapitel/diskussion.tex +++ b/rapport/kapitel/diskussion.tex @@ -9,7 +9,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.. +% TODO typcheckaren kom aldrig in i den slutgiltliga versionen. Ö: + + \subsection{Framtida förbättringar} diff --git a/rapport/kapitel/inledning.tex b/rapport/kapitel/inledning.tex index 053a99c..1ca5e66 100644 --- a/rapport/kapitel/inledning.tex +++ b/rapport/kapitel/inledning.tex @@ -45,8 +45,7 @@ \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} @@ -54,6 +53,6 @@ \subsubsection{Avgränsningar} \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. diff --git a/rapport/kapitel/resultat.tex b/rapport/kapitel/resultat.tex index 13f08a2..5662018 100644 --- a/rapport/kapitel/resultat.tex +++ b/rapport/kapitel/resultat.tex @@ -154,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. @@ -185,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. @@ -219,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} @@ -276,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}. @@ -464,3 +467,26 @@ \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{Language feutoeeras} + +I våra avgränsningar angav vi vilka delar av haskellspecifikationen vi valde att fokusera på. +I vår modul Prelude har vi definerat upp en rad funktioner som visar på exempel på att vi lyckats implemetera det vi fokuserat på. + +Vi har stöd för namngivna funktioner och lambda-funktioner. Ett exempel på en namngiven funktion är id. +\begin{lstlisting} +id x = x +\end{lstlisting} + +Algebraiska datatyper stöds också. I Prelude har vi definerat upp datatypen Bool och ett par exempel på när vi använder den. I funktionen \emph{(||) x y} har vi också ett exempel på pattern matching. Resultatet av x \emph{case x of} kommer matcha antingen mot \emph{True} eller \emph{False}. +\begin{lstlisting} +data Bool = True | False + +(||) x y = case x of + True -> True + False -> y +\end{lstlisting} + + +Guards %TODO filter från johan + diff --git a/rapport/kapitel/sammanfattning.tex b/rapport/kapitel/sammanfattning.tex index 4e663cb..e4f5503 100644 --- a/rapport/kapitel/sammanfattning.tex +++ b/rapport/kapitel/sammanfattning.tex @@ -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}