From ffe17dee05f75539cf5e4c59395e4c7400ececaa Mon Sep 17 00:00:00 2001 From: Aditya Siram Date: Thu, 27 Apr 2017 17:02:53 -0500 Subject: [PATCH] Peep hole based on function call counts in the Shen wiki. --- shen-elisp.el | 77 ++----- shen-elisp.html | 513 +++++++++++++++++++++++---------------------- shen-elisp.org | 15 +- shen-primitives.el | 15 +- 4 files changed, 313 insertions(+), 307 deletions(-) diff --git a/shen-elisp.el b/shen-elisp.el index c58b1fc..aa0172e 100644 --- a/shen-elisp.el +++ b/shen-elisp.el @@ -4369,35 +4369,21 @@ (V2823 V2824) V2824) (defun shen/element\? - (V2836 V2837) - (cl-flet - ((tail-trampoline - (V2836 V2837) - (shen/cond - ((shen/internal/predicate->shen - (null V2837)) - 'false) - ((shen/and - (shen/cons\? V2837) - (shen/= - (shen/hd V2837) - V2836)) - 'true) - ((shen/cons\? V2837) - (vector - (list V2836 - (nthcdr 1 V2837)))) - (shen/true - (shen/shen\.f_error 'element\?))))) - (let - ((result - (funcall #'tail-trampoline V2836 V2837))) - (while - (vectorp result) - (setq result - (apply #'tail-trampoline - (aref result 0)))) - result))) + (Element Xs) + (let + ((SearchList Xs) + (Found nil) + (Length + (length Xs)) + (Current 0)) + (while + (and + (not Found) + SearchList) + (setq Found + (shen/internal/= Element + (pop SearchList)))) + (shen/internal/predicate->shen Found))) (defun shen/empty\? (V2843) (shen/cond @@ -14511,32 +14497,13 @@ (list 'stinput))) (shen/true V1537))) (defun shen/shen\.compose - (V1540 V1541) - (cl-flet - ((tail-trampoline - (V1540 V1541) - (shen/cond - ((shen/internal/predicate->shen - (null V1540)) - V1541) - ((shen/cons\? V1540) - (vector - (list - (nthcdr 1 V1540) - (shen/internal/apply-function-expression - (shen/hd V1540) - (list V1541))))) - (shen/true - (shen/shen\.f_error 'shen\.compose))))) - (let - ((result - (funcall #'tail-trampoline V1540 V1541))) - (while - (vectorp result) - (setq result - (apply #'tail-trampoline - (aref result 0)))) - result))) + (Fs X) + (let + ((Result X)) + (dolist + (F Fs Result) + (setq Result + (funcall F Result))))) (defun shen/shen\.compile-macro (V1543) (shen/cond diff --git a/shen-elisp.html b/shen-elisp.html index a26d069..ec7267a 100644 --- a/shen-elisp.html +++ b/shen-elisp.html @@ -232,128 +232,128 @@

Shen Elisp

Table of Contents

-
-

1 Package Details

+
+

1 Package Details

(define-package
@@ -367,11 +367,11 @@ 

1 Package Details

-
-

2 KLambda Primitives

+
+

2 KLambda Primitives

-
-

2.1 License

+
+

2.1 License

;; -*- lexical-binding: t -*-
@@ -381,8 +381,8 @@ 

2.1 License

-
-

2.2 Implementation Constants

+
+

2.2 Implementation Constants

(defconst shen/prefix "shen/")
@@ -390,8 +390,8 @@ 

2.2 Implementation Con

-
-

2.3 Symbols

+
+

2.3 Symbols

Symbols in KLambda (and Shen) are very much like symbols in Elisp : @@ -440,7 +440,7 @@

2.3 Symbols

-To deal with these differences a pass is taken over the KLambda ast (before +To deal with these differences a pass is taken over the KLambda ast (before macroexpansion) that identifies symbols that requires quoting and function calls that need to be applied correctly.

@@ -463,8 +463,8 @@

2.3 Symbols

-
-

2.3.1 Prefixing Utilities

+
+

2.3.1 Prefixing Utilities

Elisp does not have namespaces so to insulate the rest of the user's Emacs image @@ -506,12 +506,12 @@

2.3.1 Prefixing Utilit

-
-

2.4 Assignments

+
+

2.4 Assignments

When setting and getting a variable, the name is prefixed to prevent the user from stomping over one that -already exists in the Emacs image. See 2.3.1 for more on how this works. +already exists in the Emacs image. See 2.3.1 for more on how this works.

(defun shen/set (X Y)
@@ -534,11 +534,11 @@ 

2.4 Assignments

-
-

2.5 KLambda Constants

+
+

2.5 KLambda Constants

-Once the assigning mechanism is in place the spec requires some global variables: +Once the assigning mechanism is in place the spec requires some global variables:

(shen/set '*home-directory* "")
@@ -554,8 +554,8 @@ 

2.5 KLambda Constants<

-
-

2.6 Boolean Operations

+
+

2.6 Boolean Operations

Unlike Elisp in KLambda booleans are false and true, distinct symbols which @@ -600,8 +600,8 @@

2.6 Boolean Operations

-
-

2.7 Lambdas

+
+

2.7 Lambdas

Since Shen supports currying by default KLambda's lambda form is stripped down to only accept one @@ -632,8 +632,8 @@

2.7 Lambdas

-
-

2.8 Lets

+
+

2.8 Lets

KLambda's let in a similar way only takes one assignment: @@ -661,8 +661,8 @@

2.8 Lets

-
-

2.9 Defuns

+
+

2.9 Defuns

The structure of defun in KLambda is identical to Elisp's so a straight @@ -681,11 +681,11 @@

2.9 Defuns

-
-

2.10 Equality

+
+

2.10 Equality

-Using hash-tables for tuples and vectors complicates equality. It also slows +Using hash-tables for tuples and vectors complicates equality. It also slows down equality tests across the board but using hash-tables still results in a substantial net-gain.

@@ -783,8 +783,8 @@

2.10 Equality

-
-

2.11 Other Generic Functions

+
+

2.11 Other Generic Functions

(defmacro shen/freeze (X)
@@ -795,8 +795,8 @@ 

2.11 Other Generic Fun

-
-

2.12 Lists

+
+

2.12 Lists

List construction in KLambda is done with cons exclusively. The KLambda list @@ -808,7 +808,7 @@

2.12 Lists

Elisp also provides a cons so a straightforward translation is possible but -it blows the recursion stack after a certain number of elements. They are rewritten to +it blows the recursion stack after a certain number of elements. They are rewritten to list calls below but a cons is provided to adhere to the standard:

@@ -828,8 +828,8 @@

2.12 Lists

-
-

2.13 Strings

+
+

2.13 Strings

  • @@ -838,7 +838,7 @@

    2.13 Strings

    The only weirdness here is why we print the buffer-name -of a stream. That is explained in the 2.18.: +of a stream. That is explained in the 2.18.:

@@ -887,8 +887,8 @@

2.13 Strings

-
-

2.14 Error Handling

+
+

2.14 Error Handling

Elisp's error and condition-case covers the primitive error handling @@ -908,8 +908,8 @@

2.14 Error Handling

-
-

2.15 Vectors

+
+

2.15 Vectors

Hash tables are used to represent Klambda vectors. This is counter-intuitive @@ -950,8 +950,8 @@

2.15 Vectors

-
-

2.16 Arithmetic Operations

+
+

2.16 Arithmetic Operations

In KLambda there is only number so we have to take care to coerce to between float and @@ -1035,8 +1035,8 @@

2.16 Arithmetic Operat

-
-

2.17 Time

+
+

2.17 Time

The get-time primitive given real or unix returns the current Unix time @@ -1066,8 +1066,8 @@

2.17 Time

-
-

2.18 Streams and I/O

+
+

2.18 Streams and I/O

Streams at the KLambda level are just an abstraction over file I/O. At the Elisp @@ -1144,7 +1144,7 @@

2.18 Streams and I/O A further bit of weirdness is that write-byte switches on a function. This is because -when writing out to the 10 requires calling a function with the character. +when writing out to the 10 requires calling a function with the character.

(defun shen/close (Stream)
@@ -1194,11 +1194,11 @@ 

2.18 Streams and I/O

-
-

3 Utilities

+
+

3 Utilities

-
-

3.1 Lookup

+
+

3.1 Lookup

(defun shen/internal/lookup-with-default (KEY ALIST DEFAULT)
@@ -1207,16 +1207,16 @@ 

3.1 Lookup

-
-

3.2 AST Utilities

+
+

3.2 AST Utilities

The next few sections are about transforming the KLambda AST so we need a few utilites to make the job easier.

-
-

3.2.1 Paths

+
+

3.2.1 Paths

Paths are a way of getting or setting deep inside some tree. For the most part @@ -1234,11 +1234,11 @@

3.2.1 Paths

-
-

3.2.2 AST Getter/Setter

+
+

3.2.2 AST Getter/Setter

-
(defun shen/internal/get-element-at (path ast)
+
(defun shen/internal/get-element-at (path ast)
   (let ((res ast))
     (dolist (current-index (reverse path) res)
       (if (listp current-index)
@@ -1256,7 +1256,7 @@ 

3.2.2 AST Getter/Sette before handing it off to setf.

-
(defun shen/internal/nset-element-at (path ast new-element)
+
(defun shen/internal/nset-element-at (path ast new-element)
   (if (not path)
       (setf ast new-element)
     (let ((place-fn)
@@ -1282,10 +1282,10 @@ 

3.2.2 AST Getter/Sette

-
-

3.2.3 AST Search

+
+

3.2.3 AST Search

-
  1. Find All
    +
    1. Find All

      Search the tree and return paths to all the elements that are equal to the given X.

      @@ -1315,7 +1315,7 @@

      3.2.3 AST Search

-
  • Find Containing List
    +
  • Find Containing List

    In addition to accessing and modifying an element given a path we also need a function that finds the list that contains an element. This following function, @@ -1353,8 +1353,8 @@

    3.2.3 AST Search

  • -
    -

    3.2.4 Path Utilities

    +
    +

    3.2.4 Path Utilities

    (defun shen/internal/get-path-relative-to (parent-path path)
    @@ -1386,8 +1386,8 @@ 

    3.2.4 Path Utilities

    -
    -

    3.2.5 AST Modification

    +
    +

    3.2.5 AST Modification

    Given an ast, some paths, destructively modify the ast with tx-fn. Note @@ -1406,11 +1406,11 @@

    3.2.5 AST Modification

    -
    -

    3.3 List

    +
    +

    3.3 List

    -
    -

    3.3.1 Detect Dotted Pair

    +
    +

    3.3.1 Detect Dotted Pair

    Note this only detects dotted pairs that look like '(a . b), not ones @@ -1423,8 +1423,8 @@

    3.3.1 Detect Dotted Pa

    -
    -

    3.3.2 List Filtering

    +
    +

    3.3.2 List Filtering

    A partition function that returns a pair of lists where @@ -1497,11 +1497,11 @@

    3.3.2 List Filtering

    -
    -

    4 Rewriting The AST

    +
    +

    4 Rewriting The AST

    -
    -

    4.1 Walking The AST

    +
    +

    4.1 Walking The AST

    Before evaluating we walk the tree and return locations that require: @@ -1658,8 +1658,8 @@

    4.1 Walking The AST

    -
    -

    4.2 Function Application

    +
    +

    4.2 Function Application

    Since KLambda supports partial application and Elisp does not function application is @@ -1670,7 +1670,7 @@

    4.2 Function Applicati First we enumerate forms that may never be partially applied:

    -
    (setq shen/*primitive-macros*
    +
    (setq shen/*primitive-macros*
           '(shen/if
             shen/and
             shen/or
    @@ -1798,8 +1798,8 @@ 

    4.2 Function Applicati

    -
    -

    4.3 Finding Tail Calls

    +
    +

    4.3 Finding Tail Calls

    Finding tail calls in a form is complex because: @@ -1821,9 +1821,9 @@

    4.3 Finding Tail Calls

    -
    1. Detecting Recursive Calls
      +
      1. Detecting Recursive Calls

        -The function follows the same basic template as searching for the first +The function follows the same basic template as searching for the first occurrence of something in the AST but instead of stopping at the first encounter keeps a tally of paths to all tail calls.

        @@ -1908,7 +1908,7 @@

        4.3 Finding Tail Calls

    2. -
    3. Detecting Function Application Context
      +
    4. Detecting Function Application Context

      This function captures the surrounding function application context around a tail call. For instance in the function: @@ -1981,7 +1981,7 @@

      4.3 Finding Tail Calls

    -
  • Getting the Tail Calls
    +
  • Getting the Tail Calls

    Now that we can get a list of recursive calls and their surrounding context a proper tail call is simply one without any context, i.e it is the last thing @@ -2004,8 +2004,8 @@

    4.3 Finding Tail Calls

  • -
    -

    4.4 Generating A TCO'ed Function

    +
    +

    4.4 Generating A TCO'ed Function

    Finally we can optimize tail calls into trampolines. The body of the trampoline @@ -2016,7 +2016,7 @@

    4.4 Generating A TCO'e

    An Elisp vector is chosen because KLambda code can never return one and so uniquely identifies an intermediate return value from a recursive function. -KLambda vectors are represented by hash-tables +KLambda vectors are represented by hash-tables

    @@ -2048,16 +2048,16 @@

    4.4 Generating A TCO'e

    -
    -

    4.5 Modifying The AST

    +
    +

    4.5 Modifying The AST

    Now that we have mechanisms for

    we are ready to transform incoming KLambda code into Elisp. @@ -2179,8 +2179,8 @@

    4.5 Modifying The AST<

    -
    -

    4.6 (Unused) Isolating and Filling

    +
    +

    4.6 (Unused) Isolating and Filling

    I was going to do something clever with the function application context but that didn't work @@ -2220,11 +2220,11 @@

    4.6 (Unused) Isolating

    -
    -

    5 Optimizations

    +
    +

    5 Optimizations

    -
    -

    5.1 Consolidate Call Chains

    +
    +

    5.1 Consolidate Call Chains

    KLambda code is rife with argument chains such as (cons x (cons y @@ -2261,8 +2261,8 @@

    5.1 Consolidate Call C

    -
    -

    5.2 Consolidate Cons

    +
    +

    5.2 Consolidate Cons

    Convert (cons a (cons b (blah))) into (append (list 'a 'b) (blah)) @@ -2287,8 +2287,8 @@

    5.2 Consolidate Cons

    -
    -

    5.3 Consolidate @s

    +
    +

    5.3 Consolidate @s

    Convert (@s "a" (@s "b" (blah))) into (concat (concat "a" "b") (blah)) @@ -2311,8 +2311,8 @@

    5.3 Consolidate @s

    -
    -

    5.4 Consolidate tl

    +
    +

    5.4 Consolidate tl

    Convert (tl (tl (tl Xs))) to (nthcdr 3 Xs) @@ -2335,8 +2335,8 @@

    5.4 Consolidate tl

    -
    -

    5.5 Add 1+'s

    +
    +

    5.5 Add 1+'s

    Convert (+ X 1) or (+ 1 X) to (1+ X) @@ -2362,8 +2362,8 @@

    5.5 Add 1+'s

    -
    -

    5.6 Nil Comparisons To Null

    +
    +

    5.6 Nil Comparisons To Null

    (defun shen/internal/nil-to-null (ast)
    @@ -2387,16 +2387,16 @@ 

    5.6 Nil Comparisons To

    -
    -

    6 Overrides

    +
    +

    6 Overrides

    There are four types of overrides, those which:

      -
    1. boost performance
    2. -
    3. are necessary because Klambda functions are prefixed.
    4. -
    5. fix klambda bugs.
    6. +
    7. boost performance
    8. +
    9. are necessary because Klambda functions are prefixed.
    10. +
    11. fix klambda bugs.

    @@ -2405,8 +2405,8 @@

    6 Overrides

    cdr of the form.

    -
    -

    6.1 Performance

    +
    +

    6.1 Performance

    Peephole optimizations that provide native implementations of commonly used functions and the dictionary API. @@ -2438,7 +2438,20 @@

    6.1 Performance

    (shen.mod . (defun shen/shen.mod (N Div) (mod N Div))) (integer? . (defun shen/integer? (N) (shen/internal/predicate->shen (integerp N)))) (abs . (defun shen/shen.abs (N) (abs N))) - (nth . (defun shen/nth (I Xs) (nth I Xs))))) + (nth . (defun shen/nth (I Xs) (nth I Xs))) + (element? . (defun shen/element? (Element Xs) + (let ((SearchList Xs) + (Found nil) + (Length (length Xs)) + (Current 0)) + (while (and (not Found) SearchList) + (setq Found (shen/internal/= Element (pop SearchList)))) + (shen/internal/predicate->shen Found)))) + (shen.compose . (defun shen/shen.compose + (Fs X) + (let ((Result X)) + (dolist (F Fs Result) + (setq Result (funcall F Result))))))))
    @@ -2540,8 +2553,8 @@

    6.1 Performance

    -
    -

    6.2 Namespacing

    +
    +

    6.2 Namespacing

    (setq shen/internal/*namespacing-overrides*
    @@ -2552,8 +2565,8 @@ 

    6.2 Namespacing

    -
    -

    6.3 Bug Fixes

    +
    +

    6.3 Bug Fixes

    (setq shen/internal/*bugfix-overrides*
    @@ -2576,11 +2589,11 @@ 

    6.3 Bug Fixes

    -
    -

    7 Evaluate KLambda

    +
    +

    7 Evaluate KLambda

    -Now that the mechanisms for applying functions, and quoting/namespacing are in place +Now that the mechanisms for applying functions, and quoting/namespacing are in place converting KLambda to Elisp is just a couple of function calls.

    @@ -2609,14 +2622,14 @@

    7 Evaluate KLambda

    -
    -

    7.1 Generate From Seed KLambda Files

    +
    +

    7.1 Generate From Seed KLambda Files

    Generating shen-elisp.el, the file that contains the Elisp compiled from the bootstrap KLambda files, requires a slightly different approach because we -override the default generated Elisp with custom implementations. The overrides -from above are read into a hash table and will be spliced in below. +override the default generated Elisp with custom implementations. The overrides +from above are read into a hash table and will be spliced in below.

    (defun shen/internal/add-overrides (overrides table)
    @@ -2640,11 +2653,11 @@ 

    7.1 Generate From Seed

    -
    -

    7.1.1 Evaluating Bootstrapped KLambda

    +
    +

    7.1.1 Evaluating Bootstrapped KLambda

    -When bootstrapping from the seed KLambda files we first need to patch the +When bootstrapping from the seed KLambda files we first need to patch the incoming code with overrides before parsing the AST:

    @@ -2682,8 +2695,8 @@

    7.1.1 Evaluating Boots

    -
    -

    8 Providing The Primitives

    +
    +

    8 Providing The Primitives

    (provide 'shen-primitives)
    @@ -2691,15 +2704,15 @@ 

    8 Providing The Primit

    -
    -

    9 Overlays

    +
    +

    9 Overlays

    Override of some of Shen's default implementations.

    -
    -

    9.1 License

    +
    +

    9.1 License

    ;; Copyright (c) 2015-2016 Aditya Siram. All Rights Reserved.
    @@ -2708,11 +2721,11 @@ 

    9.1 License

    -
    -

    9.2 Repl

    +
    +

    9.2 Repl

    -
    -

    9.2.1 Questions

    +
    +

    9.2.1 Questions

    Overlay the routines that take input from the user in the REPL session to use the mini-buffer @@ -2738,8 +2751,8 @@

    9.2.1 Questions

    -
    -

    9.2.2 Changing Directories

    +
    +

    9.2.2 Changing Directories

    When changing directories in the REPL, for convenience, also change Emacs' working directory. @@ -2758,8 +2771,8 @@

    9.2.2 Changing Directo

    -
    -

    9.3 Provide it

    +
    +

    9.3 Provide it

    (provide 'shen-overlays)
    @@ -2768,8 +2781,8 @@ 

    9.3 Provide it

    -
    -

    10 Shen REPL

    +
    +

    10 Shen REPL

    ;; -*- lexical-binding: t -*-
    @@ -2786,8 +2799,8 @@ 

    10 Shen REPL

    -
    -

    10.1 Credits

    +
    +

    10.1 Credits

    The credits that appear at the top of each REPL session. @@ -2804,8 +2817,8 @@

    10.1 Credits

    -
    -

    10.2 Prompt

    +
    +

    10.2 Prompt

    The Shen REPL prompt looks like (0-) and (100+) where the number is a @@ -2842,8 +2855,8 @@

    10.2 Prompt

    -
    -

    10.3 Input Events

    +
    +

    10.3 Input Events

    In addition to evaluating input, the REPL also provides some rudimentary @@ -2922,8 +2935,8 @@

    10.3 Input Events

    -
    -

    10.4 Sending Input

    +
    +

    10.4 Sending Input

    (defvar shen/repl-input)
    @@ -2945,8 +2958,8 @@ 

    10.4 Sending Input

    -
    -

    10.5 Evaluating User Input

    +
    +

    10.5 Evaluating User Input

    The following is a cut-and-paste of ielm-standard-output-impl which apparently @@ -3024,8 +3037,8 @@

    10.5 Evaluating User I

    -
    -

    10.6 The REPL Mode

    +
    +

    10.6 The REPL Mode

    (defconst shen/syntax-table
    @@ -3077,8 +3090,8 @@ 

    10.6 The REPL Mode

    -
    -

    10.7 Starting the REPL

    +
    +

    10.7 Starting the REPL

    ;;;###autoload
    @@ -3103,8 +3116,8 @@ 

    10.7 Starting the REPL

    -
    -

    10.8 Provide it

    +
    +

    10.8 Provide it

    (provide 'shen-repl)
    @@ -3113,8 +3126,8 @@ 

    10.8 Provide it

    -
    -

    11 Bootstrap

    +
    +

    11 Bootstrap

    Bootstrapping a Shen environment involves @@ -3126,8 +3139,8 @@

    11 Bootstrap

  • providing a runner that kicks off the process
  • -
    -

    11.1 Collecting KLambda files

    +
    +

    11.1 Collecting KLambda files

    In order to bootstrap the environment we specify the location of all the KLambda files @@ -3152,8 +3165,8 @@

    11.1 Collecting KLambd

    -
    -

    11.2 Modifying The Elisp Reader For KLambda

    +
    +

    11.2 Modifying The Elisp Reader For KLambda

    In KLambda semicolons, colons, commas, ticks and backquotes are valid symbols. Since they have @@ -3345,8 +3358,8 @@

    11.2 Modifying The Eli

    -
    -

    11.3 Iterating over KLambda Files

    +
    +

    11.3 Iterating over KLambda Files

    Now we can finally collect, and parse all the s-expressions in the @@ -3410,8 +3423,8 @@

    11.3 Iterating over KL

    -
    -

    12 The Runner

    +
    +

    12 The Runner

    (defun compile-and-load (F)
    diff --git a/shen-elisp.org b/shen-elisp.org
    index 99af663..14203a5 100644
    --- a/shen-elisp.org
    +++ b/shen-elisp.org
    @@ -1587,7 +1587,20 @@ function name or form which when found in Klambda code is replaces with the
              (shen.mod . (defun shen/shen.mod (N Div) (mod N Div)))
              (integer? . (defun shen/integer? (N) (shen/internal/predicate->shen (integerp N))))
              (abs . (defun shen/shen.abs (N) (abs N)))
    -         (nth . (defun shen/nth (I Xs) (nth I Xs)))))
    +         (nth . (defun shen/nth (I Xs) (nth I Xs)))
    +         (element? . (defun shen/element? (Element Xs)
    +                       (let ((SearchList Xs)
    +                             (Found nil)
    +                             (Length (length Xs))
    +                             (Current 0))
    +                         (while (and (not Found) SearchList)
    +                           (setq Found (shen/internal/= Element (pop SearchList))))
    +                         (shen/internal/predicate->shen Found))))
    +         (shen.compose . (defun shen/shen.compose
    +                             (Fs X)
    +                           (let ((Result X))
    +                             (dolist (F Fs Result)
    +                               (setq Result (funcall F Result))))))))
     #+END_SRC
     #+BEGIN_SRC elisp :tangle shen-primitives.el
       (setq shen/internal/*dict-overrides*
    diff --git a/shen-primitives.el b/shen-primitives.el
    index c7d7c06..1c01d2b 100644
    --- a/shen-primitives.el
    +++ b/shen-primitives.el
    @@ -1152,7 +1152,20 @@
            (shen.mod . (defun shen/shen.mod (N Div) (mod N Div)))
            (integer? . (defun shen/integer? (N) (shen/internal/predicate->shen (integerp N))))
            (abs . (defun shen/shen.abs (N) (abs N)))
    -       (nth . (defun shen/nth (I Xs) (nth I Xs)))))
    +       (nth . (defun shen/nth (I Xs) (nth I Xs)))
    +       (element? . (defun shen/element? (Element Xs)
    +                     (let ((SearchList Xs)
    +                           (Found nil)
    +                           (Length (length Xs))
    +                           (Current 0))
    +                       (while (and (not Found) SearchList)
    +                         (setq Found (shen/internal/= Element (pop SearchList))))
    +                       (shen/internal/predicate->shen Found))))
    +       (shen.compose . (defun shen/shen.compose
    +                           (Fs X)
    +                         (let ((Result X))
    +                           (dolist (F Fs Result)
    +                             (setq Result (funcall F Result))))))))
     ;; Performance:1 ends here
     
     ;; [[file:~/Lisp/shen-elisp/shen-elisp.org::*Performance][Performance:2]]