s-cargot-letbind-0.2.0.0: Enables let-binding and let-expansion for s-cargot defined S-expressions.

Safe HaskellNone
LanguageHaskell2010

Data.SCargot.LetBind

Contents

Description

This is a helper module that enables the use of let-bound variables in your S-expression.

Synopsis

Documentation

This module allows let bindings to be introduced into the S-Expression syntax.

For example, instead of:

   (concat (if (enabled x) (+ (width x) (width y)) (width y))
           " meters")

this can be re-written with let bindings:

   (let ((wy    (width y))
         (wboth (+ (width x) wy))
         (wide  (if (enabled x) wboth wy))
        )
     (concat wide " meters"))

As S-expressions grow larger, let-binding can help readability for those expressions. This module provides the discoverLetBindings function that will convert an S-expression into one containing let-bound variables, and the inverse function letExpand which will expand let-bound variables back into the expression.

   id = letExpand . discoverLetBindings guide

The typical use is to add let bindings before serializing to disk, and then expand the bindings after reading from the disk but before passing to other processing; this process allows the application using the S-Expressions to be unaware of the let-binding compression, although it does not obtain corresponding advantages of the re-use of let-bound variables.

The discoverLetBindings function can be called to automatically assign let bindings based on a weighting algorithm of discovered S-expression phrases. The discovery is guided by parameters provided by the caller in the DiscoveryGuide; this guide also provides the functions used to create the variables and the top-level let statement in the language of the current S-expression.

The weighting function of the DiscoveryGuide can be used to assign weights to various S-expression phrases: the S-expressions with the highest weights will be let-bound to variables (up to the maxLetBinds limit). A weighting value of 0 will cause the sub-expression to be ignored (never let-bound) and a value of >= 1000000 will *always* insert a let-binding, ignoring all other limits.

discoverLetBindings :: (Monoid str, IsString str, Eq str, Eq a, Show a) => DiscoveryGuide a str -> SExpr a -> SExpr a Source #

Called to convert a plain S-expression into one with let-bound variables. The let bindings are "discovered" with the assistance of the guide.

data DiscoveryGuide a str Source #

This object provides guidance to the discoverLetBindings function, establishing various parameters for the discovery process.

Constructors

Guide 

Fields

  • maxLetBinds :: Int -> Int

    Maximum number of let bindings to generate. Given the total number discovered as input to allow the maximum number to be intelligently determined.

  • minExprSize :: Int

    Minimum sexpr size to be considered for a let variable binding. Expressions shorter than this will not be let-bound.

  • allowRecursion :: Bool

    Allow rec bindings, or just direct let bindings?

  • weighting :: SExpr a -> Int -> Int

    Given an SExpr sub-expression and the count of occurrences of that sub-expression, return a weighting value that is used for sorting the discovered let bindings to choose the most weighty maxLetBinds for substitution. A sub-expression with a weight of zero will be ignored (i.e. not let-bound); one with a weight of 1000000 or more will always be bound.

  • letMaker :: IsString str => str -> a

    Called to generate the "let" statement token itself.

  • labelMaker :: (IsString str, Monoid str) => str -> SExpr a -> a

    Called to generate the binding variable name token given the name. Passed the suggested name that will be used for this binding and also the sub-expression that will be referenced. The return will be placed in an SAtom and used as the variable to reference the bound sub-expression.

  • extractStr :: IsString str => a -> Maybe str

    Called to extract a string value. The returned string should be the string that will be written when the enclosing S-expression is printed. This is used to verify that the variables names extracted for let-binding are unique with respect to all other printed references. A return value of Nothing permits continuation without uniqueness verification, but at the risk that variable names will be captured in the result.

nativeGuide :: (str -> a) -> (str -> SExpr a -> a) -> DiscoveryGuide a str Source #

Returns a default DiscoveryGuide.

Expanding

letExpand :: (Eq a, Show a, Eq str, IsString str) => (a -> Maybe str) -> SExpr a -> SExpr a Source #

The letExpand function is passed an S-expression that (may) contain let-bound variables and will return an equivalent S-expression that does not contain any let bindings, where let bindings have been expanded into the expression.