Perl6-Pugs
view release on metacpan or search on metacpan
docs/talks/hw2005.tex view on Meta::CPAN
evl exp
\end{lstlisting}
This makes use of the envEval field in the Env structure, which defines the
active evaluator of type \code{(Exp $\to$ Eval Val)}. This allows the user to
change the reduction logic during evaluation, such as by adding watch points or
profiling instruments.
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% 5.
\section{Experimental Features}
\label{sec:ExperimentalFeatures}
Pugs depends on the Glasgow Haskell Compiler (GHC), because GHC is the only
widely available Haskell implementation, of which we are aware, which offers
reasonable performance as a host language. Because of that, we are able to
improve clarity and efficiency in the Pugs source code with GHC-specific
extensions, such as pattern guards, liberalized type synonyms and generalized
derived instances for newtypes.
GHC 6.4 was released in March 2005, one month after Pugs's inception. Pugs
dropped support for GHC 6.2 in the same month, as we found it difficult to
keep source code portable between GHC 6.2 and GHC 6.4. This was due to
incompatible changes in Template Haskell, as well as new module interfaces
for Data.Map and Data.Set.
During the three months that followed, we explored GHC's new features to
clarify and expand on Perl 6's current design, as demonstrated with prototype
implementations in Pugs. Below we discuss three such uses of GHC's
experimental features.
% 5.1.
\subsection{"Tied" Variables with GADTs}
\label{sec:TiedVariableswithGADTs}
Perl 6 distinguishes \emph{value types} from \emph{implementation types}. A
container's implementation type is the type of object that implements the
container. This design is a generalization of Perl 5's \code{tie} function,
which binds a container to an object that handles all future access to the
container.
For example, consider this Haskell code:
\begin{lstlisting}
import Data.HashTable (insert)
-- Insert ("PATH", "/tmp") into x
insert x "PATH" "/tmp"
-- Do the same to y
insert y "PATH" "/tmp"
\end{lstlisting}
Here both \code{x} and \code{y} must bind to a value of the \code{(HashTable
String String)} type; the \code{insert} for both of them refers to the same
function. In contrast, the two lines below do different things in Perl 6:
\begin{lstlisting}
# modify an in-memory storage
%foo{"PATH"} = "/tmp";
# calls setenv() to change the environment
%ENV{"PATH"} = "/tmp";
\end{lstlisting}
Here the operation is polymorphic: Perl looks up the containers that
\code{\%foo} and \code{\%ENV} bind to, then check if they have associated
\emph{implementation objects}. If they are, Perl then calls the \code{STORE}
method on them, passing the key and value as arguments.
There is a level of indirection between containers and implementation objects,
as the \code{tie} function can change a container's implementation at runtime.
As such, a reference in Perl always points to a container, instead of to a
specific implementation object or a value.
Thanks to GADTs~\cite{Jones}, Pugs can conveniently represent these levels of
indirection, as well as generic get/set operations on containers:
\begin{lstlisting}
type VHash = Map VStr Val
data VRef where
MkRef :: (Typeable a) => !(IVar a) -> VRef
data (Typeable v) => IVar v where
IHash :: HashClass a => !a -> IVar VHash
IArray :: ArrayClass a => !a -> IVar VArray
IScalar :: ScalarClass a => !a -> IVar VScalar
-- ...more implementation types...
readIVar :: IVar v -> Eval v
writeIVar :: IVar v -> v -> Eval ()
\end{lstlisting}
Intuitively, \code{(IVar VHash)} is a container that can store a \code{VHash}.
However, instead of implementing all operations in terms of \code{readIVar} and
\code{writeIVar}, the \code{HashClass} interface defines more methods, with their
fallback definitions:
\begin{lstlisting}
type HashIndex = VStr
class (Typeable a) => HashClass a where
hash_iType :: a -> Type
hash_fetch :: a -> Eval VHash
hash_fetchKeys :: a -> Eval [HashIndex]
hash_deleteElem :: a -> HashIndex -> Eval ()
-- ...more methods...
\end{lstlisting}
With this, we can use a singleton data type \code{IHashEnv} to represent the
implementation type of the builtin variable \code{\%ENV}:
\begin{lstlisting}
data IHashEnv = MkHashEnv deriving (Typeable)
instance HashClass IHashEnv where
hash_iType = const $ mkType "Hash::Env"
hash_fetch _ = do
envs <- liftIO getEnvironment
return . Map.map VStr $ Map.fromList envs
hash_deleteElem _ key = liftIO $ unsetEnv key
-- ...more implementations...
\end{lstlisting}
Although it is possible to use existential quantification to achieve the same
result, GADTs allow for a much more straightforward definition for the
( run in 1.060 second using v1.01-cache-2.11-cpan-6aa56a78535 )