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 )