#!/bin/relish ;; relish: versatile lisp shell ;; Copyright (C) 2021 Aidan Hahn ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;; USERLIB ;; This file contains useful features that are not shipped in the STL ;; this would be way faster as code in stl ;; but stl already suffers scope creep (def prepend 'takes a list and appends an element to the back of it. returns prepended list' (elem list) (reverse (cons (reverse list) elem))) ;; please dont misuse this tool (def set 'sets an existing variable without touching its docstring. WARNING: abandon hope all ye who declare and then modify global variables! If you find yourself struggling to debug a complex error in state access, or you are having issues re-running commands in the shell consider the following advice: It is very much an anti pattern to mutate global variable that contain state refactor your program: put iterators, counters, procedurally generated code, and all other mutable state into a let loop. A zen script in relish is one where each root level form (or eval at repl) is self contained, and does not permanently modify any other one. See the userlib tests for an easy to follow example of this.' (var val) (let ((doc (get-doc var))) (def (eval var) doc val))) (def map 'Takes two arguments: a function and a list. for each element in the list, the function is applied and the result is added to a new list. Returns the new list.' (func list) (let ((list-iter (pop list)) (result ())) (while (gt? (len list-iter) 1) (let ((current (car list-iter)) (remaining (cdr list-iter)) (current-res (func current))) (set (q result) (cons result current-res)) (set (q list-iter) (pop remaining)))) result)) (def reduce 'Takes two arguments: a function and a list. The function is expected to take two arguments: * the current list item * the previous result Initially the function will take element1 and element2, outputting result1. Then the function will take result1 and element3, outputting result2. this will continue iuntil the list is exhausted.' (func list) (let ((list-iter (pop list)) (result (car list-iter))) (set (q list-iter) (pop (cdr list-iter))) (if (lt? (len list) 2) (echo "list too short!") (while (gt? (len list-iter) 1) (let ((current (car list-iter)) (remaining (cdr list-iter))) (set (q result) (func result current)) (set (q list-iter) (pop remaining))))) result)) (def contains? 'Takes two arguments: a list and an element. Returns true if the list contains the element.' (list elem) (let ((found false) (list-iter (pop list))) (while (and (gt? (len list-iter) 1) (not found)) (let ((current (car list-iter)) (remaining (cdr list-iter))) (if (eq? current elem) (set (q found) true) (set (q list-iter) (pop remaining))))) found)) (def get-paths 'returns each individual directory in PATH' () (split PATH ':')) (def add-path 'adds a directory to PATH' (path) (set (q PATH) (concat PATH ':' path)))