├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── include ├── compose.lfe ├── predicates.lfe └── seq.lfe ├── lfe.config ├── priv ├── images │ └── clojure.png ├── make │ ├── code.mk │ └── docs.mk └── scripts │ └── setup_test_env.sh ├── rebar.config ├── rebar.lock ├── src ├── clj-comp.lfe ├── clj-p.lfe ├── clj-seq.lfe ├── clj-util.lfe └── clj.app.src └── test ├── clj-comp-tests.lfe ├── clj-p-tests.lfe ├── clj-seq-tests.lfe ├── include-compose-tests.lfe ├── include-predicates-tests.lfe └── include-seq-tests.lfe /.gitignore: -------------------------------------------------------------------------------- 1 | deps 2 | *.sublime-project 3 | *.sublime-workspace 4 | *.beam 5 | .eunit 6 | bin/expm 7 | ebin/*.app 8 | ebin/*.beam 9 | .rebar 10 | erl_crash.dump 11 | *.sw[po] 12 | _build/* 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | install: true 3 | before_script: 4 | - wget https://s3.amazonaws.com/rebar3/rebar3 5 | - chmod +x rebar3 6 | env: PATH=".:$PATH" 7 | script: make check 8 | otp_release: 9 | - 18.3 10 | - 17.5 11 | - R16B03-1 12 | - R15B03 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = clj 2 | ROOT_DIR = $(shell pwd) 3 | REPO = $(shell git config --get remote.origin.url) 4 | LFE = _build/dev/lib/lfe/bin/lfe 5 | 6 | include priv/make/code.mk 7 | include priv/make/docs.mk 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clj 2 | 3 | **DEPRECATED**: This library is no longer maintained! Nor is it useful, since the functionality it provides has been moved into LFE-proper (see the `clj` module). 4 | 5 | [![][kla-logo]][kla-logo-large] 6 | 7 | [kla-logo]: priv/images/clojure.png 8 | [kla-logo-large]: priv/images/clojure.png 9 | 10 | *Clojure functions and macros for LFE* 11 | 12 | ##### Contents 13 | 14 | * [Introduction](#introduction-) 15 | * [Dependencies](#dependencies-) 16 | * [Installation](#installation-) 17 | * [Usage](#usage-) 18 | * [Future](#future-) 19 | 20 | 21 | ## Introduction [↟](#contents) 22 | 23 | The clj library offers a collection of functions and macros that you may find useful 24 | or enjoyable in LFE if you've come from a Clojure background. 25 | 26 | This library is in the process of extracting the Clojure functionality that made its 27 | way into the [lutil](https://github.com/lfex/lutil#contents) LFE library 28 | 29 | 30 | ## Dependencies [↟](#contents) 31 | 32 | As of version 0.3.0, this project assumes that you have 33 | [rebar3](https://github.com/rebar/rebar3) installed somwhere in your ``$PATH``. 34 | It no longer uses the old version of rebar. If you do not wish to use rebar3, 35 | you may use the most recent rebar2-compatible release of clj: 0.2.1. 36 | 37 | 38 | ## Installation [↟](#contents) 39 | 40 | In your ``rebar.config`` file, update your ``deps`` section to include 41 | ``clj``: 42 | 43 | ```erlang 44 | {deps, [ 45 | ... 46 | {clj, ".*", 47 | {git, "git@github.com:lfex/clj.git", {tag, "0.3.0"}}} 48 | ]}. 49 | ``` 50 | 51 | 52 | ## Usage [↟](#contents) 53 | 54 | TBD 55 | 56 | (We are changing the functions and macros from what they were in lutil, so usage has 57 | not yet stabilized. If you want to be an alpha tester/user, be sure to look at the 58 | unit tests and code comments, both in the modules and in the include files.) 59 | 60 | ## Future [↟](#contents) 61 | 62 | The future of the clj library is quite bright :-) In a couple posts on the LFE mail list, Robert Virding has offered to bring Clojure functionality into LFE-proper: 63 | * https://groups.google.com/d/msg/lisp-flavoured-erlang/668_n6F6qHU/FE61waXoDAAJ 64 | * https://groups.google.com/d/msg/lisp-flavoured-erlang/j_PO4Ol5Rkw/OotEtbjoEQAJ 65 | 66 | The rest is up to us :-) As such, I will be creating a series of tickets in this repo targeted against a branch of Robert's LFE repo. Anyone in the community may make a contribution to this branch -- simply sumbit a PR. Once we have critical mass on Clojure-inspired functions and macros, I will submit a PR to upstream LFE, and all of our work will be included :-) 67 | 68 | Here's the branch: 69 | * https://github.com/oubiwann/lfe/tree/add-clojure-lib 70 | 71 | Here are the tickets you can chose from to implement your favourite Clojure bits in LFE (if you don't see the one you want, add it!): 72 | * https://github.com/lfex/clj/labels/Clojure%20Lib%20for%20LFE 73 | 74 | **IMPORTANT**: Even though these tickets are in the lfex/clj repo, you will be working against a branch of oubiwann/lfe! Do not submit PRs against lfex/clj -- submit them against the add-clojure-lib branch of oubiwann/lfe. 75 | 76 | Now go forth, and help these two worlds to collide :-D 77 | -------------------------------------------------------------------------------- /include/compose.lfe: -------------------------------------------------------------------------------- 1 | ;; Threads the sexp through the sexps. Inserts x as the second item in 2 | ;; the first sexp, making a list of it if it is not a list already. If 3 | ;; there are more sexps, inserts the first sexp as the second item in 4 | ;; second sexp, etc. 5 | ;; 6 | ;; Copied from Tim Dysinger's lfesl repo here: 7 | ;; https://github.com/lfex/lfesl/blob/master/include/thread.lfe 8 | ;; 9 | ;; Example usage, demonstrating ordering: 10 | ;; 11 | ;; > (set o '(#(a 1) #(b 2) #(c 3))) 12 | ;; (#(a 1) #(b 2) #(c 3)) 13 | ;; > (-> o 14 | ;; (++ '(#(d 4))) 15 | ;; (++ '(#(e 5))) 16 | ;; (++ '(#(f 6)))) 17 | ;; (#(a 1) #(b 2) #(c 3) #(d 4) #(e 5) #(f 6)) 18 | ;; 19 | ;; Note that usage of this macro with this examples results in each successive 20 | ;; value being APPENDED to the input list. 21 | ;; 22 | ;; Another example showing how this: 23 | ;; 24 | ;; > (lists:sublist 25 | ;; (lists:reverse 26 | ;; (lists:sort 27 | ;; (lists:merge 28 | ;; (string:tokens 29 | ;; (string:to_upper "a b c d e") 30 | ;; " ") 31 | ;; '("X" "F" "L")))) 32 | ;; 2 3) 33 | ;; ("L" "F" "E") 34 | ;; 35 | ;; Can be rewritten as this: 36 | ;; 37 | ;; > (-> "a b c d e" 38 | ;; (string:to_upper) 39 | ;; (string:tokens " ") 40 | ;; (lists:merge '("X" "F" "L")) 41 | ;; (lists:sort) 42 | ;; (lists:reverse) 43 | ;; (lists:sublist 2 3)) 44 | ;; ("L" "F" "E") 45 | ;; 46 | (defmacro -> 47 | ((x) x) 48 | ((x sexp) (when (is_list sexp)) 49 | `(,(car sexp) ,x ,@(cdr sexp))) 50 | ((x sexp) 51 | `(list ,sexp ,x)) 52 | ((x sexp . sexps) 53 | `(-> (-> ,x ,sexp) ,@sexps))) 54 | 55 | ;; Threads the sexp through the sexps. Inserts x as the last item in 56 | ;; the first sexp, making a list of it if it is not a list already. If 57 | ;; there are more sexps, inserts the first sexp as the last item in 58 | ;; second sexp, etc. 59 | ;; 60 | ;; Copied from Tim Dysinger's lfesl repo here: 61 | ;; https://github.com/lfex/lfesl/blob/master/include/thread.lfe 62 | ;; 63 | ;; Example usage, demonstrating ordering: 64 | ;; 65 | ;; > (set o '(#(a 1) #(b 2) #(c 3))) 66 | ;; (#(a 1) #(b 2) #(c 3)) 67 | ;; > (->> o 68 | ;; (++ '(#(d 4))) 69 | ;; (++ '(#(e 5))) 70 | ;; (++ '(#(f 6)))) 71 | ;; (#(f 6) #(e 5) #(d 4) #(a 1) #(b 2) #(c 3)) 72 | ;; 73 | ;; Note that usage of this macro with this examples results in each successive 74 | ;; value being PREPENDED to the input list. 75 | ;; 76 | ;; Another example showing how this: 77 | ;; 78 | ;; > (lists:foldl #'+/2 0 79 | ;; (take 10 80 | ;; (lists:filter 81 | ;; (compose #'even?/1 #'round/1) 82 | ;; (lists:map 83 | ;; (lambda (x) 84 | ;; (math:pow x 2)) 85 | ;; (seq 42))))) 86 | ;; 1540.0 87 | ;; 88 | ;; Can be rewritten as this: 89 | ;; 90 | ;; > (->> (seq 42) 91 | ;; (lists:map (lambda (x) (math:pow x 2))) 92 | ;; (lists:filter (compose #'even?/1 #'round/1)) 93 | ;; (take 10) 94 | ;; (lists:foldl #'+/2 0)) 95 | ;; 1540.0 96 | ;; 97 | (defmacro ->> 98 | ((x) x) 99 | ((x sexp) (when (is_list sexp)) 100 | `(,(car sexp) ,@(cdr sexp) ,x)) 101 | ((x sexp) 102 | `(list ,sexp ,x)) 103 | ((x sexp . sexps) 104 | `(->> (->> ,x ,sexp) ,@sexps))) 105 | 106 | ;;; The following allow developers to use (include-lib ...) on this file and 107 | ;;; pull in the functions from the passed module, making them available to 108 | ;;; call as if they were part of the language. 109 | (defmacro generate-compose-wrappers () 110 | `(progn ,@(kla:wrap-mod-funcs 'clj-comp))) 111 | 112 | (generate-compose-wrappers) 113 | 114 | (defun loaded-compose () 115 | "This is just a dummy function for display purposes when including from the 116 | REPL (the last function loaded has its name printed in stdout). 117 | 118 | This function needs to be the last one in this include." 119 | 'ok) 120 | -------------------------------------------------------------------------------- /include/predicates.lfe: -------------------------------------------------------------------------------- 1 | (defmacro in? (item collection) 2 | `(orelse ,@(lists:map 3 | (lambda (x) 4 | `(=:= (quote ,x) ,item)) 5 | `(,@(cadr collection))))) 6 | 7 | (defmacro not-in? (item collection) 8 | `(not (in? ,item ,collection))) 9 | 10 | ;;; The following allow developers to use (include-lib ...) on this file and 11 | ;;; pull in the functions from the passed module, making them available to 12 | ;;; call as if they were part of the language. 13 | (defmacro generate-predicate-wrappers () 14 | `(progn ,@(kla:wrap-mod-funcs 'clj-p))) 15 | 16 | (generate-predicate-wrappers) 17 | 18 | (defun loaded-predicates () 19 | "This is just a dummy function for display purposes when including from the 20 | REPL (the last function loaded has its name printed in stdout). 21 | 22 | This function needs to be the last one in this include." 23 | 'ok) 24 | -------------------------------------------------------------------------------- /include/seq.lfe: -------------------------------------------------------------------------------- 1 | (defmacro get-in args 2 | (let* ((rargs (lists:reverse args)) 3 | (data (car rargs)) 4 | (keys (lists:reverse (cdr rargs)))) 5 | `(apply #'clj-seq:get-in/2 (list ,data (list ,@keys))))) 6 | 7 | ;;; The following allow developers to use (include-lib ...) on this file and 8 | ;;; pull in the functions from the passed module, making them available to 9 | ;;; call as if they were part of the language. 10 | (defmacro generate-sequence-wrappers () 11 | `(progn ,@(kla:wrap-mod-funcs 'clj-seq))) 12 | 13 | (generate-sequence-wrappers) 14 | 15 | (defun loaded-seq () 16 | "This is just a dummy function for display purposes when including from the 17 | REPL (the last function loaded has its name printed in stdout). 18 | 19 | This function needs to be the last one in this include." 20 | 'ok) 21 | -------------------------------------------------------------------------------- /lfe.config: -------------------------------------------------------------------------------- 1 | #(project 2 | (#(meta 3 | (#(name kla) 4 | #(description "Clojure functions and macros for LFE") 5 | #(version "0.4.1") 6 | #(keywords ("LFE" "Lisp" "Library" "Utility" "Clojure")) 7 | #(maintainers 8 | ((#(name "Duncan McGreggor") #(email "oubiwann@gmail.com")))) 9 | #(repos 10 | (#(github "lfex/clj"))))) 11 | #(app 12 | (#(mod #(clj ())))))) 13 | -------------------------------------------------------------------------------- /priv/images/clojure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfe-deprecated/clj/7c07d76e5402b8f316a65ddc1a24677e48770fcd/priv/images/clojure.png -------------------------------------------------------------------------------- /priv/make/code.mk: -------------------------------------------------------------------------------- 1 | compile: 2 | rebar3 compile 3 | 4 | check: compile 5 | -@rebar3 as default+test compile 6 | @./priv/scripts/setup_test_env.sh 7 | @rebar3 as default+test eunit 8 | 9 | repl: 10 | @rebar3 as dev compile 11 | @$(LFE) -pa `rebar3 as dev path -s " -pa "` 12 | 13 | shell: 14 | @rebar3 shell 15 | 16 | clean: 17 | @rebar3 clean 18 | @rm -rf ebin/* _build/default/lib/$(PROJECT) 19 | 20 | clean-all: clean 21 | @rebar3 as dev lfe clean 22 | -------------------------------------------------------------------------------- /priv/make/docs.mk: -------------------------------------------------------------------------------- 1 | DOCS_DIR = $(ROOT_DIR)/docs 2 | GUIDE_DIR = $(DOCS_DIR)/user-guide 3 | GUIDE_BUILD_DIR = $(GUIDE_DIR)/build 4 | DOCS_PROD_DIR = $(DOCS_DIR)/master 5 | API_PROD_DIR = $(DOCS_PROD_DIR)/current/api 6 | GUIDE_PROD_DIR = $(DOCS_PROD_DIR)/current/user-guide 7 | SLATE_GIT_HACK = $(DOCS_DIR)/.git 8 | LOCAL_DOCS_HOST = localhost 9 | LOCAL_DOCS_PORT = 5099 10 | 11 | $(SLATE_GIT_HACK): 12 | @ln -s $(ROOT_DIR)/.git $(DOCS_DIR) 13 | 14 | docs-setup: 15 | @echo "\nInstalling and setting up dependencies ..." 16 | @cd $(DOCS_DIR) && bundle install 17 | 18 | docs-clean: 19 | @echo "\nCleaning build directories ..." 20 | @rm -rf $(GUIDE_BUILD_DIR) $(API_PROD_DIR) $(GUIDE_PROD_DIR) 21 | 22 | docs-lodox: 23 | @echo 24 | @rebar3 lfe lodox 25 | 26 | docs-slate: 27 | @echo 28 | @cd $(GUIDE_DIR) && bundle exec middleman build --clean 29 | @mkdir $(GUIDE_PROD_DIR) 30 | @cp -r $(GUIDE_BUILD_DIR)/* $(GUIDE_PROD_DIR)/ 31 | 32 | docs: clean compile docs-clean $(SLATE_GIT_HACK) 33 | @echo "\nBuilding docs ...\n" 34 | @make docs-lodox 35 | @make docs-slate 36 | 37 | devdocs: docs 38 | @echo 39 | @echo "Running docs server on http://$(LOCAL_DOCS_HOST):$(LOCAL_DOCS_PORT) ... (To quit, hit ^c twice)" 40 | @echo 41 | @erl -s inets -noshell -eval 'inets:start(httpd,[{server_name,"devdocs"},{document_root, "$(DOCS_PROD_DIR)"},{server_root, "$(DOCS_PROD_DIR)"},{port, $(LOCAL_DOCS_PORT)},{mime_types,[{"html","text/html"},{"htm","text/html"},{"js","text/javascript"},{"css","text/css"},{"gif","image/gif"},{"jpg","image/jpeg"},{"jpeg","image/jpeg"},{"png","image/png"}]}]).' 42 | 43 | setup-temp-repo: $(SLATE_GIT_HACK) 44 | @echo "\nSetting up temporary git repos for gh-pages ...\n" 45 | @rm -rf $(DOCS_PROD_DIR)/.git $(DOCS_PROD_DIR)/*/.git 46 | @cd $(DOCS_PROD_DIR) && git init 47 | @cd $(DOCS_PROD_DIR) && git add * > /dev/null 48 | @cd $(DOCS_PROD_DIR) && git commit -a -m "Generated content." > /dev/null 49 | 50 | teardown-temp-repo: 51 | @echo "\nTearing down temporary gh-pages repos ..." 52 | @rm $(DOCS_DIR)/.git $(GUIDE_DIR)/Gemfile.lock 53 | @rm -rf $(DOCS_PROD_DIR)/.git $(DOCS_PROD_DIR)/*/.git 54 | 55 | publish-docs: docs setup-temp-repo 56 | @echo "\nPublishing docs ...\n" 57 | @cd $(DOCS_PROD_DIR) && git push -f $(REPO) master:gh-pages 58 | @make teardown-temp-repo 59 | 60 | .PHONY: docs 61 | -------------------------------------------------------------------------------- /priv/scripts/setup_test_env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | REBAR=$(readlink -f $(PATH=.:$PATH which rebar3)) 4 | LFE_TEST_BUILD=`pwd`/_build/test 5 | cd ${LFE_TEST_BUILD}/lib/lutil && \ 6 | mkdir -p _build && \ 7 | (test -e _build/default || \ 8 | ln -s ${LFE_TEST_BUILD} _build/default) 9 | cd ${LFE_TEST_BUILD}/lib/lutil && \ 10 | $REBAR compile || echo "Already compiled." 11 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {lfe_first_files, ["src/clj-p.lfe"]}. 2 | 3 | {deps, [ 4 | {kla, {git, "https://github.com/lfex/kla.git", {tag, "0.7.0"}}} 5 | ]}. 6 | 7 | {plugins, [ 8 | {'lfe-compile', {git, "https://github.com/lfe-rebar3/compile.git", {tag, "0.5.0"}}} 9 | ]}. 10 | 11 | {provider_hooks, [ 12 | {pre, [{compile, {lfe, compile}}]} 13 | ]}. 14 | 15 | {profiles, [ 16 | {dev, 17 | [{deps, 18 | [{lfe, {git, "https://github.com/rvirding/lfe.git", {tag, "v1.1.1"}}}]} 19 | ]}, 20 | {default, []}, 21 | {test, 22 | [{deps, 23 | [{clj, {git, "https://github.com/lfex/clj.git", {tag, "0.5.0"}}}, 24 | {lutil, {git, "https://github.com/lfex/lutil.git", {tag, "0.9.0"}}}, 25 | {ltest, {git, "https://github.com/lfex/ltest.git", {tag, "0.9.0"}}} 26 | ]}, 27 | {eunit_opts, [verbose]}, 28 | {eunit_compile_opts, [ 29 | {src_dirs, ["src", "test"]} 30 | ]} 31 | ]} 32 | ]}. 33 | -------------------------------------------------------------------------------- /rebar.lock: -------------------------------------------------------------------------------- 1 | [{<<"kla">>, 2 | {git,"https://github.com/lfex/kla.git", 3 | {ref,"495cfa95682a3962ddd527c935a5afa6b808f848"}}, 4 | 0}, 5 | {<<"lfe-version">>, 6 | {git,"https://github.com/lfe-rebar3/version.git", 7 | {ref,"94140845563f96d2a6fb356524d867b906088b20"}}, 8 | 1}]. 9 | -------------------------------------------------------------------------------- /src/clj-comp.lfe: -------------------------------------------------------------------------------- 1 | (defmodule clj-comp 2 | (export all)) 3 | 4 | ;; Compose 5 | ;; 6 | ;; Usage: 7 | ;; 8 | ;; > (include-file "clj/include/compose.lfe") 9 | ;; compose 10 | ;; > (funcall (compose #'math:sin/1 #'math:asin/1) 11 | ;; 0.5) 12 | ;; 0.49999999999999994 13 | ;; > (funcall (compose `(,#'math:sin/1 14 | ;; ,#'math:asin/1 15 | ;; ,(lambda (x) (+ x 1)))) 16 | ;; 0.5) 17 | ;; 1.5 18 | ;; 19 | ;; Or used in another function call: 20 | ;; 21 | ;; > (lists:filter (compose #'not/1 #'zero?/1) 22 | ;; '(0 1 0 2 0 3 0 4)) 23 | ;; (1 2 3 4) 24 | ;; 25 | ;; The usage above is best when 'compose' will be called from in 26 | ;; functions like '(lists:foldl ...)' or '(lists:filter ...)', etc. 27 | ;; However, one may also call compose in the following manner, best 28 | ;; suited for direct usage: 29 | ;; 30 | ;; > (compose #'math:sin/1 #'math:asin/1 0.5) 31 | ;; 0.49999999999999994 32 | ;; > (compose `(,#'math:sin/1 33 | ;; ,#'math:asin/1 34 | ;; ,(lambda (x) (+ x 1))) 0.5) 35 | ;; 1.5 36 | ;; 37 | (defun compose 38 | ((func-1 func-2) (when (is_function func-2)) 39 | (lambda (x) 40 | (funcall func-1 41 | (funcall func-2 x)))) 42 | ((funcs x) 43 | (funcall (compose funcs) x))) 44 | 45 | (defun compose (f g x) 46 | (funcall (compose f g) x)) 47 | 48 | (defun compose (funcs) 49 | (lists:foldl #'compose/2 (lambda (x) x) funcs)) 50 | 51 | ;; Partial 52 | ;; 53 | ;; Usage: 54 | ;; 55 | ;; > (set f (partial #'+/2 1)) 56 | ;; #Fun 57 | ;; > (funcall f 2) 58 | ;; 3 59 | ;; > (set f (partial #'+/3 1)) 60 | ;; #Fun 61 | ;; > (funcall f '(2 3)) 62 | ;; 6 63 | ;; > (set f (partial #'+/3 '(2 3))) 64 | ;; #Fun 65 | ;; > (funcall f 4) 66 | ;; 9 67 | ;; > (set f (partial #'+/4 '(2 3))) 68 | ;; #Fun 69 | ;; > (funcall f '(4 5)) 70 | ;; 14 71 | ;; 72 | (defun partial 73 | "The partial function is arity 2 where the first parameter must be a 74 | function and the second parameter may either be a single item or a list of 75 | items. 76 | 77 | When funcall is called against the result of the partial call, a second 78 | parameter is applied to the partial function. This parameter too may be 79 | either a single item or a list of items." 80 | ((func args-1) (when (is_list args-1)) 81 | (match-lambda 82 | ((args-2) (when (is_list args-2)) 83 | (apply func (++ args-1 args-2))) 84 | ((arg-2) 85 | (apply func (++ args-1 `(,arg-2)))))) 86 | ((func arg-1) 87 | (match-lambda 88 | ((args-2) (when (is_list args-2)) 89 | (apply func (++ `(,arg-1) args-2))) 90 | ((arg-2) 91 | (funcall func arg-1 arg-2))))) 92 | -------------------------------------------------------------------------------- /src/clj-p.lfe: -------------------------------------------------------------------------------- 1 | (defmodule clj-p 2 | (export all)) 3 | 4 | (defun string? (data) 5 | (io_lib:printable_list data)) 6 | 7 | (defun unicode? (data) 8 | (io_lib:printable_unicode_list data)) 9 | 10 | (defun list? (data) 11 | (and (is_list data) (not (string? data)))) 12 | 13 | (defun tuple? (data) 14 | (is_tuple data)) 15 | 16 | (defun atom? (data) 17 | (is_atom data)) 18 | 19 | (defun binary? (data) 20 | (is_binary data)) 21 | 22 | (defun bitstring? (data) 23 | (is_bitstring data)) 24 | 25 | (defun bool? (data) 26 | (is_boolean data)) 27 | 28 | (defun float? (data) 29 | (is_float data)) 30 | 31 | (defun function? (data) 32 | (is_function data)) 33 | 34 | (defun function? (data arity) 35 | (is_function data arity)) 36 | 37 | (defun func? (data) 38 | (is_function data)) 39 | 40 | (defun func? (data arity) 41 | (is_function data arity)) 42 | 43 | (defun integer? (data) 44 | (is_integer data)) 45 | 46 | (defun int? (data) 47 | (is_integer data)) 48 | 49 | (defun number? (data) 50 | (is_number data)) 51 | 52 | (defun record? (data record-tag) 53 | (is_record data record-tag)) 54 | 55 | (defun record? (data record-tag size) 56 | (is_record data record-tag size)) 57 | 58 | (defun reference? (data) 59 | (is_reference data)) 60 | 61 | (defun map? (data) 62 | (if (erl_internal:bif 'is_map 1) 63 | (call 'erlang 'is_map data) 64 | 'false)) 65 | 66 | (defun set? (x) 67 | (or (sets:is_set x) 68 | (ordsets:is_set x))) 69 | 70 | (defun dict? 71 | ((data) (when (=:= 'dict (element 1 data))) 72 | 'true) 73 | ((_) 74 | 'false)) 75 | 76 | (defun proplist? 77 | ((data) (when (is_list data)) 78 | (if (lists:all #'proplist-kv?/1 data) 79 | 'true 80 | 'false)) 81 | ((_) 82 | 'false)) 83 | 84 | (defun proplist-kv? 85 | ((`#(,key ,_)) (when (is_atom key)) 86 | 'true) 87 | ((bool-key) (when (is_atom bool-key)) 88 | 'true) 89 | ((_) 90 | 'false)) 91 | 92 | (defun undefined? (x) 93 | (=:= x 'undefined)) 94 | 95 | (defun undef? (x) 96 | (=:= x 'undefined)) 97 | 98 | (defun nil? (x) 99 | (or (=:= x 'nil) 100 | (=:= x '()))) 101 | 102 | (defun true? (x) 103 | (=:= x 'true)) 104 | 105 | (defun false? (x) 106 | (=:= x 'false)) 107 | 108 | (defun odd? (x) 109 | (=:= 1 (rem x 2))) 110 | 111 | (defun even? (x) 112 | (=:= 0 (rem x 2))) 113 | 114 | (defun zero? (x) 115 | (=:= 0 x)) 116 | 117 | (defun pos? (x) 118 | (> x 0)) 119 | 120 | (defun neg? (x) 121 | (< x 0)) 122 | 123 | (defun identical? (x y) 124 | (=:= x y)) 125 | 126 | (defun empty? (x) 127 | (=:= x '())) 128 | 129 | (defun every? (pred x) 130 | (lists:all pred x)) 131 | 132 | (defun all? (pred x) 133 | (lists:all pred x)) 134 | 135 | (defun any? (pred x) 136 | (lists:any pred x)) 137 | 138 | (defun not-any? (pred x) 139 | (not (lists:any pred x))) 140 | 141 | (defun element? 142 | ((element x) (when (is_list x)) 143 | (any? (lambda (y) (identical? element y)) x)) 144 | ((element x) 145 | (cond 146 | ((sets:is_set x) 147 | (sets:is_element element x)) 148 | ((ordsets:is_set x) 149 | (ordsets:is_element element x)) 150 | ('true 'false)))) -------------------------------------------------------------------------------- /src/clj-seq.lfe: -------------------------------------------------------------------------------- 1 | ;;;; Various macros and functions that relate to sequences 2 | ;;;; 3 | (defmodule clj-seq 4 | (export all)) 5 | 6 | (include-lib "clj/include/predicates.lfe") 7 | 8 | ;; List sequence wrapper functions 9 | ;; 10 | ;; Usage: 11 | ;; 12 | ;; > (seq 10) 13 | ;; (1 2 3 4 5 6 7 8 9 10) 14 | ;; 15 | (defun seq (end) 16 | (lists:seq 1 end)) 17 | 18 | (defun seq (start end) 19 | (lists:seq start end)) 20 | 21 | (defun seq (start end step) 22 | (lists:seq start end step)) 23 | 24 | ;; Infinite series functions 25 | ;; 26 | ;; The following are identical: 27 | ;; > (take 21 (range)) 28 | ;; (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21) 29 | ;; > (take 21 (next #'+/2 1 1)) 30 | ;; (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21) 31 | ;; > (take 21 (next (lambda (x y) (+ x y)) 1 1)) 32 | ;; (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21) 33 | ;; 34 | ;; More usage: 35 | ;; 36 | ;; > (take 10 (next (lambda (x y) (* 3 (+ x y))) 1 1)) 37 | ;; (1 6 21 66 201 606 1821 5466 16401 49206) 38 | ;; > (take 17 (next (lambda (x _) (* 2 x)) 1 1)) 39 | ;; (1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536) 40 | ;; > (take 7 (next (lambda (x _) (math:pow (+ x 1) 2)) 1 1)) 41 | ;; (1 4.0 25.0 676.0 458329.0 210066388900.0 4.4127887745906175e22) 42 | ;; 43 | (defun next (func) 44 | (next func 1 1)) 45 | 46 | (defun next (func start) 47 | (next start 1)) 48 | 49 | (defun next (func start step) 50 | (lambda () 51 | (cons start (next func 52 | (funcall func start step) 53 | step)))) 54 | 55 | ;; Range functions 56 | ;; 57 | ;; Usage: 58 | ;; 59 | ;; > (range) 60 | ;; #Fun 61 | ;; > (funcall (range)) 62 | ;; (1 . #Fun) 63 | ;; > (funcall (range 100)) 64 | ;; (100 . #Fun) 65 | ;; 66 | ;; Some more: 67 | ;; 68 | ;; > (funcall (range)) 69 | ;; (1 . #Fun) 70 | ;; > (funcall (cdr (funcall (range)))) 71 | ;; (2 . #Fun) 72 | ;; > (funcall (cdr (funcall (cdr (funcall (range)))))) 73 | ;; (3 . #Fun) 74 | ;; > (funcall (cdr (funcall (cdr (funcall (cdr (funcall (range)))))))) 75 | ;; (4 . #Fun) 76 | ;; 77 | (defun range () 78 | (range 1 1)) 79 | 80 | (defun range (start) 81 | (range start 1)) 82 | 83 | (defun range (start step) 84 | (next #'+/2 start step)) 85 | 86 | ;; Drop function 87 | ;; 88 | ;; Usage: 89 | ;; 90 | ;; > (drop 5 '(1 2 3 4 5 6 7 8 9 10 11 12)) 91 | ;; (6 7 8 9 10 11 12) 92 | ;; > (drop 'all '(1 2 3 4 5 6 7 8 9 10 11 12)) 93 | ;; () 94 | ;; 95 | (defun drop 96 | ((_ '()) 97 | '()) 98 | (('all data) (when (is_list data)) 99 | '()) 100 | ((x data) (when (is_list data)) 101 | (lists:nthtail x data))) 102 | 103 | ;; Take functions 104 | ;; 105 | ;; Usage: 106 | ;; 107 | ;; > (take 4 (range)) 108 | ;; (1 2 3 4) 109 | ;; > (take 5 '(1 2 3 4 5 6 7 8 9 10 11 12)) 110 | ;; (1 2 3 4 5) 111 | ;; > (take 'all '(1 2 3 4 5 6 7 8 9 10 11 12)) 112 | ;; (1 2 3 4 5 6 7 8 9 10 11 12) 113 | ;; 114 | (defun take 115 | (('all data) (when (is_list data)) 116 | data) 117 | ((x data) (when (is_list data)) 118 | (lists:sublist data x)) 119 | ((x func) (when (is_function func) (is_integer x) (>= x 0)) 120 | (take x '() (funcall func)))) 121 | 122 | (defun take 123 | ((0 acc _) 124 | (lists:reverse acc)) 125 | ((x acc (cons item func)) 126 | (take (- x 1) (cons item acc) (funcall func)))) 127 | 128 | ;; Partitioning functions 129 | ;; 130 | ;; Usage: 131 | ;; 132 | ;; > (split-at 3 '(1 2 3 4 5 6 7 8 9 10 11 12)) 133 | ;; '((1 2 3) (4 5 6 7 8 9 10 11 12)) 134 | ;; 135 | ;; > (split-by 2 '(1 2 3 4 5 6 7 8 9 10 11 12)) 136 | ;; ((1 2) (3 4) (5 6) (7 8) "\t\n" "\v\f") 137 | ;; > (split-by 5 '(1 2 3 4 5 6 7 8 9 10 11 12)) 138 | ;; ((1 2 3 4 5) (6 7 8 9 10) "\v\f") 139 | ;; > (split-by 7 '(1 2 3 4 5 6 7 8 9 10 11 12)) 140 | ;; ((1 2 3 4 5 6 7) "\b\t\n\v\f") 141 | ;; > (split-by 11 '(1 2 3 4 5 6 7 8 9 10 11 12)) 142 | ;; ((1 2 3 4 5 6 7 8 9 10 11) "\f") 143 | ;; > (split-by 12 '(1 2 3 4 5 6 7 8 9 10 11 12)) 144 | ;; ((1 2 3 4 5 6 7 8 9 10 11 12)) 145 | ;; 146 | ;; > (split-into 5 '(1 2 3 4 5 6 7 8 9 10 11 12)) 147 | ;; 148 | (defun split-at (x data) 149 | (list (lists:sublist data x) (lists:nthtail x data))) 150 | 151 | (defun split-by 152 | ((0 data) 153 | data) 154 | ((_ '()) 155 | '()) 156 | ((x data) (when (> x (length data))) 157 | (split-by (length data) data)) 158 | ((x data) 159 | (cons (lists:sublist data x) 160 | (split-by x (lists:nthtail x data))))) 161 | 162 | ;; XXX finish implementation for this 163 | ;;(defun split-into 164 | ;; ((_ '()) '()) 165 | 166 | ;; Interleave 167 | ;; 168 | ;; Usage: 169 | ;; 170 | ;; > (set l1 '(a b c d e f g)) 171 | ;; (a b c d e f g) 172 | ;; > (set l2 '(1 2 3 4 5 6 7)) 173 | ;; (1 2 3 4 5 6 7) 174 | ;; > (interleave l1 l2) 175 | ;; (a 1 b 2 c 3 d 4 e 5 f 6 g 7) 176 | (defun interleave (list-1 list-2) 177 | (lists:flatten 178 | (lists:map 179 | #'tuple_to_list/1 180 | (lists:zip list-1 list-2)))) 181 | 182 | ;; Get-In 183 | ;; 184 | ;; This macro is inspired by the Clojure function 'get-in'. Unlike the 185 | ;; Clojure function, however, the LFE version handles both lists as well 186 | ;; as proplists, dicts, orddicts, and maps. 187 | ;; 188 | ;; List-based usage: 189 | ;; 190 | ;; Given the following data structure assigned to the variable 'data': 191 | ;; 192 | ;; '((1) 193 | ;; (1 2 3) 194 | ;; (1 2 (3 4 (5 6 (7 8 9))))) 195 | ;; 196 | ;; > (include-lib "clj/include/core.lfe") 197 | ;; loaded-core 198 | ;; 199 | ;; > (get-in data 1 1) 200 | ;; 1 201 | ;; > (get-in data 2 3) 202 | ;; 3 203 | ;; > (get-in data 3 3 3 3 3) 204 | ;; 9 205 | ;; > (get-in data 4) 206 | ;; undefined 207 | ;; > (get-in data 4 3 3 3) 208 | ;; undefined 209 | ;; 210 | ;; Key-value-based usage: 211 | ;; 212 | ;; Given the following data structure assigned to the variable 'data': 213 | ;; 214 | ;; '(#(key-1 val-1) 215 | ;; #(key-2 val-2) 216 | ;; #(key-3 (#(key-4 val-4) 217 | ;; #(key-5 val-5) 218 | ;; #(key-6 (#(key-7 val-7) 219 | ;; #(key-8 val-8)))))) 220 | ;; 221 | ;; > (include-lib "clj/include/core.lfe") 222 | ;; loaded-core 223 | ;; > (get-in data 'key-1) 224 | ;; val-1 225 | ;; > (get-in data 'key-3 'key-5) 226 | ;; val-5 227 | ;; > (get-in data 'key-3 'key-6 'key-8) 228 | ;; val-8 229 | ;; > (get-in data 'key-19) 230 | ;; undefined 231 | ;; > (get-in data 'key-3 'key-6 'key-89) 232 | ;; undefined 233 | ;; > (get-in data 'key-3 'key-6 'key-89 'key-100) 234 | ;; undefined 235 | (defun get-in (data keys) 236 | "This function is not intended to be used directly (though one certainly may) 237 | but rather to be used via the macro defined in include/seq.lfe." 238 | ;; XXX We'll take the cheap way out right now and assume (uh-oh ...) that 239 | ;; any error here will be keys or indices not found, and thus return 240 | ;; undefined. Might be better to only do this for function_clause errors ... 241 | (try 242 | (cond ((clj-p:proplist? data) (get-in-proplist data keys)) 243 | ((clj-p:dict? data) (get-in-dict data keys)) 244 | ((clj-p:list? data) (get-in-list data keys)) 245 | ((clj-p:map? data) (get-in-map data keys))) 246 | (catch (_ 247 | 'undefined)))) 248 | 249 | (defun get-in-list (data indices) 250 | (lists:foldl #'lists:nth/2 data indices)) 251 | 252 | (defun get-in-proplist (data keys) 253 | (lists:foldl #'proplists:get_value/2 data keys)) 254 | 255 | (defun get-in-dict (data keys) 256 | (get-in-kv #'dict:fetch/2 data keys)) 257 | 258 | (defun get-in-map (data keys) 259 | (get-in-kv #'maps:get/2 data keys)) 260 | 261 | (defun get-in-kv 262 | ((func data (cons key keys)) 263 | (let ((value (funcall func key data))) 264 | (if (orelse (clj-p:proplist? value) 265 | (clj-p:dict? value) 266 | (clj-p:map? value)) 267 | (get-in value keys) 268 | value)))) 269 | 270 | ;; Reduce 271 | ;; 272 | ;; This macro simplifies the usage of lists:foldl when using it as a reduce 273 | ;; operation. 274 | ;; 275 | ;; Before: 276 | ;; (lists:foldl (lambda (n acc) (+ n acc)) 0 '(1 2 3)) 277 | ;; 278 | ;; After: 279 | ;; (reduce #'+/2 '(1 2 3)) 280 | ;; or: 281 | ;; (reduce (fun + 2) '(1 2 3)) 282 | (defun reduce 283 | ((func `(,head . ,tail)) 284 | (lists:foldl func head tail))) 285 | 286 | ;; An alias for lists:foldl to allow for use of the same name for reduce/2 and 287 | ;; reduce/3. 288 | (defun reduce (func acc data) 289 | (lists:foldl func acc data)) 290 | 291 | ;; Repeat 292 | ;; 293 | ;; Alias for lists:duplicate/2, but can also take a function as an argument. 294 | ;; In the first form, returns a list of n items, where each item is constructed 295 | ;; by calling f. 296 | ;; In the second form, simply repeats n times the item given as argument x. 297 | ;; 298 | ;; Inspired by Clojure's repeatedly and repeat. 299 | ;; 300 | ;; Another way to write this would be to use list comprehensions: 301 | ;; (lc ((<- _ (seq n))) x)) 302 | ;; 303 | ;; but constructing the seq is more costly than using recursion to 304 | ;; directly construct the list. 305 | (defun repeat 306 | ((n f) (when (is_function f) (is_integer n) (>= n 0)) 307 | (fletrec ((repeat-fun 308 | ((0 acc) 309 | acc) 310 | ((n acc) 311 | (repeat-fun (- n 1) (cons (funcall f) acc))))) 312 | (repeat-fun n '()))) 313 | ((n x) 314 | (lists:duplicate n x))) 315 | -------------------------------------------------------------------------------- /src/clj-util.lfe: -------------------------------------------------------------------------------- 1 | (defmodule clj-util 2 | (export all)) 3 | 4 | (defun get-version () 5 | (lr3-ver-util:get-app-version 'clj)) 6 | 7 | (defun get-versions () 8 | (++ (lr3-ver-util:get-versions) 9 | `(#(kla ,(lr3-ver-util:get-app-version 'kla)) 10 | #(clj ,(get-version))))) 11 | -------------------------------------------------------------------------------- /src/clj.app.src: -------------------------------------------------------------------------------- 1 | %% -*- erlang -*- 2 | {application, clj, 3 | [ 4 | %% A quick description of the application. 5 | {description, "Clojure functions and macros for LFE."}, 6 | 7 | %% The version of the application 8 | {vsn, "0.5.0"}, 9 | 10 | %% All modules used by the application. 11 | {modules, 12 | [ 13 | clj 14 | ]}, 15 | 16 | %% All of the registered names the application uses. This can be ignored. 17 | {registered, []}, 18 | 19 | %% Applications that are to be started prior to this one. This can be ignored 20 | %% leave it alone unless you understand it well and let the .rel files in 21 | %% your release handle this. 22 | {applications, 23 | [ 24 | kernel, 25 | stdlib 26 | ]}, 27 | 28 | %% OTP application loader will load, but not start, included apps. Again 29 | %% this can be ignored as well. To load but not start an application it 30 | %% is easier to include it in the .rel file followed by the atom 'none' 31 | {included_applications, []}, 32 | 33 | %% configuration parameters similar to those in the config file specified 34 | %% on the command line. can be fetched with gas:get_env 35 | {env, []} 36 | ] 37 | }. 38 | -------------------------------------------------------------------------------- /test/clj-comp-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule clj-comp-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | (include-lib "clj/include/seq.lfe") 7 | (include-lib "clj/include/compose.lfe") 8 | 9 | (deftest -> 10 | (is-equal '(#(a 1) #(b 2) #(c 3) #(d 4) #(e 5) #(f 6)) 11 | (-> '(#(a 1) #(b 2) #(c 3)) 12 | (++ '(#(d 4))) 13 | (++ '(#(e 5))) 14 | (++ '(#(f 6))))) 15 | (is-equal '("L" "F" "E") 16 | (-> "a b c d e" 17 | (string:to_upper) 18 | (string:tokens " ") 19 | (lists:merge '("X" "F" "L")) 20 | (lists:sort) 21 | (lists:reverse) 22 | (lists:sublist 2 3)))) 23 | 24 | (deftest ->> 25 | (is-equal '(#(f 6) #(e 5) #(d 4) #(a 1) #(b 2) #(c 3)) 26 | (->> '(#(a 1) #(b 2) #(c 3)) 27 | (++ '(#(d 4))) 28 | (++ '(#(e 5))) 29 | (++ '(#(f 6))))) 30 | (is-equal 1540.0 31 | (->> (clj-seq:seq 42) 32 | (lists:map (lambda (x) (math:pow x 2))) 33 | (lists:filter (clj-comp:compose #'clj-p:even?/1 #'round/1)) 34 | (clj-seq:take 10) 35 | (lists:foldl #'+/2 0)))) 36 | 37 | (deftest compose 38 | (let ((asin-result (funcall (clj-comp:compose #'math:sin/1 #'math:asin/1) 0.5))) 39 | (is-equal "0.5" (car (io_lib:format "~.1f" `(,asin-result))))) 40 | (is-equal 1.5 41 | (funcall (clj-comp:compose `(,#'math:sin/1 42 | ,#'math:asin/1 43 | ,(lambda (x) (+ x 1)))) 0.5)) 44 | (is-equal '(1 2 3 4) 45 | (lists:filter (clj-comp:compose #'not/1 #'clj-p:zero?/1) 46 | '(0 1 0 2 0 3 0 4))) 47 | (let ((asin-result (clj-comp:compose #'math:sin/1 #'math:asin/1 0.5))) 48 | (is-equal "0.5" (car (io_lib:format "~.1f" `(,asin-result)))))) 49 | 50 | (deftest partial 51 | (is-equal 3 (funcall (clj-comp:partial #'+/2 1) 2)) 52 | (is-equal 6 (funcall (clj-comp:partial #'+/3 1) '(2 3)))) 53 | -------------------------------------------------------------------------------- /test/clj-p-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule clj-p-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | (include-lib "clj/include/predicates.lfe") 7 | 8 | (deftest string? 9 | (is (clj-p:string? "string data! yaya!")) 10 | (is-not (clj-p:string? (list "my" "string" "data")))) 11 | 12 | ;; XXX add a unit test for (unicode? ...) 13 | 14 | (deftest list? 15 | (is-not (clj-p:list? "string data! yaya!")) 16 | (is (clj-p:list? (list "my" "string" "data")))) 17 | 18 | (deftest tuple? 19 | (is-not (clj-p:tuple? "string data! yaya!")) 20 | (is (clj-p:tuple? (tuple "my" "string" "data")))) 21 | 22 | (deftest atom? 23 | (is-not (clj-p:atom? "string data! yaya!")) 24 | (is (clj-p:atom? 'my-atom)) 25 | (is (clj-p:atom? '|more atom data|))) 26 | 27 | (deftest dict? 28 | (is-not (clj-p:dict? "a string")) 29 | (is-not (clj-p:dict? '("a" "list"))) 30 | (is-not (clj-p:dict? #b("a binary"))) 31 | (is-not (clj-p:dict? #("a" "tuple"))) 32 | (is-not (clj-p:dict? '(#("a" "tuple")))) 33 | (is (clj-p:dict? (dict:from_list '(#("a" "tuple")))))) 34 | 35 | (deftest set? 36 | (is-not (clj-p:set? '(c a b))) 37 | (is (clj-p:set? '(a b c))) 38 | (is (clj-p:set? '())) 39 | (is (clj-p:set? (sets:new))) 40 | (is (clj-p:set? (ordsets:new)))) 41 | 42 | (deftest proplist? 43 | (is-not (clj-p:proplist? 1)) 44 | (is-not (clj-p:proplist? '(1))) 45 | (is-not (clj-p:proplist? '(1 2))) 46 | (is-not (clj-p:proplist? '((1 2)))) 47 | (is-not (clj-p:proplist? '(#(1 2)))) 48 | (is-not (clj-p:proplist? '(#(a 1) #(2 b) #(c 3)))) 49 | (is (clj-p:proplist? '(a))) 50 | (is (clj-p:proplist? '(a b c))) 51 | (is (clj-p:proplist? '(#(a 1) b c))) 52 | (is (clj-p:proplist? '(#(a 1) #(b 2) c))) 53 | (is (clj-p:proplist? '(#(a 1) #(b 2) #(c 3))))) 54 | 55 | (deftest proplist-kv? 56 | (is (clj-p:proplist-kv? 'a)) 57 | (is-not (clj-p:proplist-kv? "a")) 58 | (is-not (clj-p:proplist-kv? 1)) 59 | (is (clj-p:proplist-kv? '#(a b))) 60 | (is-not (clj-p:proplist-kv? '(a b)))) 61 | 62 | (deftest undef? 63 | (is-not (clj-p:undef? 42)) 64 | (is-not (clj-p:undef? 'undef)) 65 | (is (clj-p:undef? 'undefined))) 66 | 67 | (deftest nil? 68 | (is-not (clj-p:nil? 32)) 69 | (is-not (clj-p:nil? 'undefined)) 70 | (is (clj-p:nil? 'nil)) 71 | (is (clj-p:nil? '()))) 72 | 73 | (deftest true? 74 | (is-not (clj-p:true? 'false)) 75 | (is (clj-p:true? 'true))) 76 | 77 | (deftest false? 78 | (is-not (clj-p:false? 'true)) 79 | (is (clj-p:false? 'false))) 80 | 81 | (deftest in? 82 | (is-not (in? 0 '(1 2 3 4 5 6))) 83 | (is (in? 6 '(1 2 3 4 5 6))) 84 | (is-not (in? "z" '("a" "b" "c" "d" "e"))) 85 | (is (in? "e" '("a" "b" "c" "d" "e"))) 86 | (is-not (in? 'z '(a b c d e))) 87 | (is (in? 'e '(a b c d e)))) 88 | 89 | (deftest not-in? 90 | (is (not-in? 0 '(1 2 3 4 5 6))) 91 | (is-not (not-in? 6 '(1 2 3 4 5 6))) 92 | (is (not-in? "z" '("a" "b" "c" "d" "e"))) 93 | (is-not (not-in? "e" '("a" "b" "c" "d" "e"))) 94 | (is (not-in? 'z '(a b c d e))) 95 | (is-not (not-in? 'e '(a b c d e)))) 96 | 97 | (defun test-in-with-guard 98 | ((arg) (when (in? arg '(a b c))) 99 | 'found) 100 | ((_) 'not-found)) 101 | 102 | (deftest in?-guard 103 | (is-equal (test-in-with-guard 'a) 'found) 104 | (is-equal (test-in-with-guard 'b) 'found) 105 | (is-equal (test-in-with-guard 'c) 'found) 106 | (is-equal (test-in-with-guard 'd) 'not-found)) 107 | 108 | (defun test-not-in-with-guard 109 | ((arg) (when (not-in? arg '(i j k))) 110 | 'not-found) 111 | ((_) 'found)) 112 | 113 | (deftest not-in?-guard 114 | (is-equal (test-not-in-with-guard 'i) 'found) 115 | (is-equal (test-not-in-with-guard 'j) 'found) 116 | (is-equal (test-not-in-with-guard 'k) 'found) 117 | (is-equal (test-not-in-with-guard 'a) 'not-found)) 118 | 119 | (deftest identical? 120 | (is (clj-p:identical? '(a b c) '(a b c))) 121 | (is-not (clj-p:identical? '(a b c) '(a b d)))) 122 | 123 | (deftest empty? 124 | (is (clj-p:empty? '())) 125 | (is-not (clj-p:empty? '(1 2 3)))) 126 | 127 | (deftest every? 128 | (is (clj-p:every? #'clj-p:zero?/1 '(0 0 0 0 0))) 129 | (is-not (clj-p:every? #'clj-p:zero?/1 '(0 0 0 0 1)))) 130 | 131 | (deftest any? 132 | (is (clj-p:any? #'clj-p:zero?/1 '(0 1 1 1 1))) 133 | (is-not (clj-p:any? #'clj-p:zero?/1 '(1 1 1 1 1)))) 134 | 135 | (deftest not-any? 136 | (is-not (clj-p:not-any? #'clj-p:zero?/1 '(0 1 1 1 1))) 137 | (is (clj-p:not-any? #'clj-p:zero?/1 '(1 1 1 1 1)))) 138 | 139 | (deftest element? 140 | (is (clj-p:element? 'a '(a b c))) 141 | (is-not (clj-p:element? 'z '(a b c))) 142 | (is (clj-p:element? 'a (sets:from_list '(a b c)))) 143 | (is-not (clj-p:element? 'z (sets:from_list '(a b c)))) 144 | (is (clj-p:element? 'a (ordsets:from_list '(a b c)))) 145 | (is-not (clj-p:element? 'z (ordsets:from_list '(a b c))))) 146 | 147 | -------------------------------------------------------------------------------- /test/clj-seq-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule clj-seq-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | (include-lib "clj/include/seq.lfe") 7 | 8 | (deftest seq 9 | (is-equal '(1 2 3 4) (clj-seq:seq 4)) 10 | (is-equal '(2 3 4) (clj-seq:seq 2 4)) 11 | (is-equal '(2 4 6 8 10) (clj-seq:seq 2 10 2))) 12 | 13 | (deftest drop 14 | (is-equal '(6 7 8 9 10 11 12) (clj-seq:drop 5 '(1 2 3 4 5 6 7 8 9 10 11 12))) 15 | (is-equal '() (clj-seq:drop 'all '(1 2 3 4 5 6 7 8 9 10 11 12)))) 16 | 17 | (deftest take 18 | (is-equal '(1 2 3 4) (clj-seq:take 4 (clj-seq:range))) 19 | (is-equal '(1 2 3 4 5) (clj-seq:take 5 '(1 2 3 4 5 6 7 8 9 10 11 12))) 20 | (is-error function_clause (clj-seq:take -1 (clj-seq:range))) 21 | (is-equal '(1 2 3 4 5 6 7 8 9 10 11 12) (clj-seq:take 'all '(1 2 3 4 5 6 7 8 9 10 11 12)))) 22 | 23 | (deftest next-and-take 24 | (is-equal 25 | '(1 6 21 66 201 606 1821 5466 16401 49206) 26 | (clj-seq:take 10 (clj-seq:next (lambda (x y) (* 3 (+ x y))) 1 1))) 27 | (is-equal 28 | '(1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536) 29 | (clj-seq:take 17 (clj-seq:next (lambda (x _) (* 2 x)) 1 1))) 30 | (is-equal 31 | '(1 4.0 25.0 676.0 458329.0 210066388900.0 4.4127887745906175e22) 32 | (clj-seq:take 7 (clj-seq:next (lambda (x _) (math:pow (+ x 1) 2)) 1 1)))) 33 | 34 | (deftest range 35 | (is-equal 1 (car (funcall (clj-seq:range)))) 36 | (is-equal 2 (car (funcall (cdr (funcall (clj-seq:range)))))) 37 | (is-equal 3 (car (funcall (cdr (funcall (cdr (funcall (clj-seq:range)))))))) 38 | (is-equal 4 (car (funcall (cdr (funcall (cdr (funcall (cdr (funcall (clj-seq:range))))))))))) 39 | 40 | (deftest split-at 41 | (is-equal 42 | '((1 2 3) (4 5 6 7 8 9 10 11 12)) 43 | (clj-seq:split-at 3 '(1 2 3 4 5 6 7 8 9 10 11 12)))) 44 | 45 | (deftest split-by 46 | (is-equal 47 | '() 48 | (clj-seq:split-by 0 '())) 49 | (is-equal 50 | '() 51 | (clj-seq:split-by 1 '())) 52 | (is-equal 53 | '() 54 | (clj-seq:split-by 100 '())) 55 | (is-equal 56 | '(1 2 3 4 5 6 7 8 9 10 11 12) 57 | (clj-seq:split-by 0 '(1 2 3 4 5 6 7 8 9 10 11 12))) 58 | (is-equal 59 | '((1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12)) 60 | (clj-seq:split-by 1 '(1 2 3 4 5 6 7 8 9 10 11 12))) 61 | (is-equal 62 | '((1 2) (3 4) (5 6) (7 8) (9 10) (11 12)) 63 | (clj-seq:split-by 2 '(1 2 3 4 5 6 7 8 9 10 11 12))) 64 | (is-equal 65 | '((1 2 3 4 5) (6 7 8 9 10) (11 12)) 66 | (clj-seq:split-by 5 '(1 2 3 4 5 6 7 8 9 10 11 12))) 67 | (is-equal 68 | '((1 2 3 4 5 6 7) (8 9 10 11 12)) 69 | (clj-seq:split-by 7 '(1 2 3 4 5 6 7 8 9 10 11 12))) 70 | (is-equal 71 | '((1 2 3 4 5 6 7 8 9 10 11) (12)) 72 | (clj-seq:split-by 11 '(1 2 3 4 5 6 7 8 9 10 11 12))) 73 | (is-equal 74 | '((1 2 3 4 5 6 7 8 9 10 11 12)) 75 | (clj-seq:split-by 12 '(1 2 3 4 5 6 7 8 9 10 11 12)))) 76 | 77 | (deftest interleave 78 | (is-equal '(a 1 b 2 c 3) (clj-seq:interleave '(a b c) '(1 2 3)))) 79 | 80 | (defun get-in-data-1 () 81 | '((1) 82 | (1 2 3) 83 | (1 2 (3 4 (5 6 (7 8 9)))))) 84 | 85 | (deftest get-in-nth 86 | (is-equal 1 (get-in 1 1 (get-in-data-1))) 87 | (is-equal 3 (get-in 2 3 (get-in-data-1))) 88 | (is-equal 9 (get-in 3 3 3 3 3 (get-in-data-1))) 89 | (is-equal 'undefined (get-in 4 (get-in-data-1))) 90 | (is-equal 'undefined (get-in 4 3 3 3 (get-in-data-1)))) 91 | 92 | (defun get-in-data-2 () 93 | '(#(key-1 val-1) 94 | #(key-2 val-2) 95 | #(key-3 (#(key-4 val-4) 96 | #(key-5 val-5) 97 | #(key-6 (#(key-7 val-7) 98 | #(key-8 val-8) 99 | #(key-9 val-9))))))) 100 | 101 | (deftest get-in-keys 102 | (is-equal 'val-1 (get-in 'key-1 (get-in-data-2))) 103 | (is-equal 'val-5 (get-in 'key-3 'key-5 (get-in-data-2))) 104 | (is-equal 'val-9 (get-in 'key-3 'key-6 'key-9 (get-in-data-2))) 105 | (is-equal 'undefined (get-in 'key-18 (get-in-data-2))) 106 | (is-equal 'undefined (get-in 'key-3 'key-6 'key-89 (get-in-data-2))) 107 | (is-equal 'undefined (get-in 'key-3 'key-6 'key-89 'key-100(get-in-data-2)))) 108 | 109 | (deftest reduce 110 | (is-equal 6 (clj-seq:reduce (lambda (x acc) (+ x acc)) '(1 2 3))) 111 | (is-equal 6 (clj-seq:reduce #'+/2 '(1 2 3))) 112 | (is-equal 6 (clj-seq:reduce (fun + 2) '(1 2 3))) 113 | (is-equal 6 (clj-seq:reduce (lambda (x acc) (+ x acc)) 0 '(1 2 3))) 114 | (is-equal 6 (clj-seq:reduce #'+/2 0 '(1 2 3))) 115 | (is-equal 6 (clj-seq:reduce (fun + 2) 0 '(1 2 3)))) 116 | 117 | (deftest repeat 118 | (is-equal '(1 1 1) (clj-seq:repeat 3 1)) 119 | (is-equal '("xo" "xo") (clj-seq:repeat 2 "xo")) 120 | (is-equal '() (clj-seq:repeat 0 "oh noes")) 121 | (is-equal '(ok ok ok ok) (clj-seq:repeat 4 'ok)) 122 | (is-error function_clause (clj-seq:repeat -1 0)) 123 | (is-equal '(1 1 1) (clj-seq:repeat 3 (lambda () 1))) 124 | (is-error function_clause (clj-seq:repeat -1 (lambda () 1))) 125 | (is-equal 2 (length (clj-seq:repeat 2 #'random:uniform/0)))) 126 | -------------------------------------------------------------------------------- /test/include-compose-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule include-compose-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | (include-lib "clj/include/seq.lfe") 7 | (include-lib "clj/include/compose.lfe") 8 | 9 | (deftest -> 10 | (is-equal '(#(a 1) #(b 2) #(c 3) #(d 4) #(e 5) #(f 6)) 11 | (-> '(#(a 1) #(b 2) #(c 3)) 12 | (++ '(#(d 4))) 13 | (++ '(#(e 5))) 14 | (++ '(#(f 6))))) 15 | (is-equal '("L" "F" "E") 16 | (-> "a b c d e" 17 | (string:to_upper) 18 | (string:tokens " ") 19 | (lists:merge '("X" "F" "L")) 20 | (lists:sort) 21 | (lists:reverse) 22 | (lists:sublist 2 3)))) 23 | 24 | (deftest ->> 25 | (is-equal '(#(f 6) #(e 5) #(d 4) #(a 1) #(b 2) #(c 3)) 26 | (->> '(#(a 1) #(b 2) #(c 3)) 27 | (++ '(#(d 4))) 28 | (++ '(#(e 5))) 29 | (++ '(#(f 6))))) 30 | (is-equal 1540.0 31 | (->> (clj-seq:seq 42) 32 | (lists:map (lambda (x) (math:pow x 2))) 33 | (lists:filter (clj-comp:compose #'clj-p:even?/1 #'round/1)) 34 | (clj-seq:take 10) 35 | (lists:foldl #'+/2 0)))) 36 | 37 | (deftest compose 38 | (let ((asin-result (funcall (compose #'math:sin/1 #'math:asin/1) 0.5))) 39 | (is-equal "0.5" (car (io_lib:format "~.1f" `(,asin-result))))) 40 | (is-equal 1.5 41 | (funcall (compose `(,#'math:sin/1 42 | ,#'math:asin/1 43 | ,(lambda (x) (+ x 1)))) 0.5)) 44 | (is-equal '(1 2 3 4) 45 | (lists:filter (compose #'not/1 #'clj-p:zero?/1) 46 | '(0 1 0 2 0 3 0 4))) 47 | (let ((asin-result (compose #'math:sin/1 #'math:asin/1 0.5))) 48 | (is-equal "0.5" (car (io_lib:format "~.1f" `(,asin-result)))))) 49 | 50 | (deftest partial 51 | (is-equal 3 (funcall (partial #'+/2 1) 2)) 52 | (is-equal 6 (funcall (partial #'+/3 1) '(2 3)))) 53 | -------------------------------------------------------------------------------- /test/include-predicates-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule include-predicates-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | (include-lib "clj/include/predicates.lfe") 7 | 8 | (deftest string? 9 | (is (string? "string data! yaya!")) 10 | (is-not (string? (list "my" "string" "data")))) 11 | 12 | ;; XXX add a unit test for (unicode? ...) 13 | 14 | (deftest list? 15 | (is-not (list? "string data! yaya!")) 16 | (is (list? (list "my" "string" "data")))) 17 | 18 | (deftest tuple? 19 | (is-not (tuple? "string data! yaya!")) 20 | (is (tuple? (tuple "my" "string" "data")))) 21 | 22 | (deftest atom? 23 | (is-not (atom? "string data! yaya!")) 24 | (is (atom? 'my-atom)) 25 | (is (atom? '|more atom data|))) 26 | 27 | (deftest dict? 28 | (is-not (dict? "a string")) 29 | (is-not (dict? '("a" "list"))) 30 | (is-not (dict? #b("a binary"))) 31 | (is-not (dict? #("a" "tuple"))) 32 | (is-not (dict? '(#("a" "tuple")))) 33 | (is (dict? (dict:from_list '(#("a" "tuple")))))) 34 | 35 | (deftest set? 36 | (is-not (set? '(c a b))) 37 | (is (set? '(a b c))) 38 | (is (set? '())) 39 | (is (set? (sets:new))) 40 | (is (set? (ordsets:new)))) 41 | 42 | (deftest proplist? 43 | (is-not (proplist? 1)) 44 | (is-not (proplist? '(1))) 45 | (is-not (proplist? '(1 2))) 46 | (is-not (proplist? '((1 2)))) 47 | (is-not (proplist? '(#(1 2)))) 48 | (is-not (proplist? '(#(a 1) #(2 b) #(c 3)))) 49 | (is (proplist? '(a))) 50 | (is (proplist? '(a b c))) 51 | (is (proplist? '(#(a 1) b c))) 52 | (is (proplist? '(#(a 1) #(b 2) c))) 53 | (is (proplist? '(#(a 1) #(b 2) #(c 3))))) 54 | 55 | (deftest proplist-kv? 56 | (is (proplist-kv? 'a)) 57 | (is-not (proplist-kv? "a")) 58 | (is-not (proplist-kv? 1)) 59 | (is (proplist-kv? '#(a b))) 60 | (is-not (proplist-kv? '(a b)))) 61 | 62 | (deftest undef? 63 | (is-not (undef? 42)) 64 | (is-not (undef? 'undef)) 65 | (is (undef? 'undefined))) 66 | 67 | (deftest nil? 68 | (is-not (nil? 32)) 69 | (is-not (nil? 'undefined)) 70 | (is (nil? 'nil)) 71 | (is (nil? '()))) 72 | 73 | (deftest true? 74 | (is-not (true? 'false)) 75 | (is (true? 'true))) 76 | 77 | (deftest false? 78 | (is-not (false? 'true)) 79 | (is (false? 'false))) 80 | 81 | (deftest in? 82 | (is-not (in? 0 '(1 2 3 4 5 6))) 83 | (is (in? 6 '(1 2 3 4 5 6))) 84 | (is-not (in? "z" '("a" "b" "c" "d" "e"))) 85 | (is (in? "e" '("a" "b" "c" "d" "e"))) 86 | (is-not (in? 'z '(a b c d e))) 87 | (is (in? 'e '(a b c d e)))) 88 | 89 | (deftest not-in? 90 | (is (not-in? 0 '(1 2 3 4 5 6))) 91 | (is-not (not-in? 6 '(1 2 3 4 5 6))) 92 | (is (not-in? "z" '("a" "b" "c" "d" "e"))) 93 | (is-not (not-in? "e" '("a" "b" "c" "d" "e"))) 94 | (is (not-in? 'z '(a b c d e))) 95 | (is-not (not-in? 'e '(a b c d e)))) 96 | 97 | (defun test-in-with-guard 98 | ((arg) (when (in? arg '(a b c))) 99 | 'found) 100 | ((_) 'not-found)) 101 | 102 | (deftest in?-guard 103 | (is-equal (test-in-with-guard 'a) 'found) 104 | (is-equal (test-in-with-guard 'b) 'found) 105 | (is-equal (test-in-with-guard 'c) 'found) 106 | (is-equal (test-in-with-guard 'd) 'not-found)) 107 | 108 | (defun test-not-in-with-guard 109 | ((arg) (when (not-in? arg '(i j k))) 110 | 'not-found) 111 | ((_) 'found)) 112 | 113 | (deftest not-in?-guard 114 | (is-equal (test-not-in-with-guard 'i) 'found) 115 | (is-equal (test-not-in-with-guard 'j) 'found) 116 | (is-equal (test-not-in-with-guard 'k) 'found) 117 | (is-equal (test-not-in-with-guard 'a) 'not-found)) 118 | 119 | (deftest identical? 120 | (is (identical? '(a b c) '(a b c))) 121 | (is-not (identical? '(a b c) '(a b d)))) 122 | 123 | (deftest empty? 124 | (is (empty? '())) 125 | (is-not (empty? '(1 2 3)))) 126 | 127 | (deftest every? 128 | (is (every? #'zero?/1 '(0 0 0 0 0))) 129 | (is-not (every? #'zero?/1 '(0 0 0 0 1)))) 130 | 131 | (deftest any? 132 | (is (any? #'zero?/1 '(0 1 1 1 1))) 133 | (is-not (any? #'zero?/1 '(1 1 1 1 1)))) 134 | 135 | (deftest not-any? 136 | (is-not (not-any? #'zero?/1 '(0 1 1 1 1))) 137 | (is (not-any? #'zero?/1 '(1 1 1 1 1)))) 138 | 139 | (deftest element? 140 | (is (element? 'a '(a b c))) 141 | (is-not (element? 'z '(a b c))) 142 | (is (element? 'a (sets:from_list '(a b c)))) 143 | (is-not (element? 'z (sets:from_list '(a b c)))) 144 | (is (element? 'a (ordsets:from_list '(a b c)))) 145 | (is-not (element? 'z (ordsets:from_list '(a b c))))) 146 | 147 | -------------------------------------------------------------------------------- /test/include-seq-tests.lfe: -------------------------------------------------------------------------------- 1 | (defmodule include-seq-tests 2 | (behaviour ltest-unit) 3 | (export all)) 4 | 5 | (include-lib "ltest/include/ltest-macros.lfe") 6 | (include-lib "clj/include/seq.lfe") 7 | 8 | (deftest seq 9 | (is-equal '(1 2 3 4) (seq 4)) 10 | (is-equal '(2 3 4) (seq 2 4)) 11 | (is-equal '(2 4 6 8 10) (seq 2 10 2))) 12 | 13 | (deftest drop 14 | (is-equal '(6 7 8 9 10 11 12) (drop 5 '(1 2 3 4 5 6 7 8 9 10 11 12))) 15 | (is-equal '() (drop 'all '(1 2 3 4 5 6 7 8 9 10 11 12)))) 16 | 17 | (deftest take 18 | (is-equal '(1 2 3 4) (take 4 (range))) 19 | (is-equal '(1 2 3 4 5) (take 5 '(1 2 3 4 5 6 7 8 9 10 11 12))) 20 | (is-error function_clause (take -1 (range))) 21 | (is-equal '(1 2 3 4 5 6 7 8 9 10 11 12) (take 'all '(1 2 3 4 5 6 7 8 9 10 11 12)))) 22 | 23 | (deftest next-and-take 24 | (is-equal 25 | '(1 6 21 66 201 606 1821 5466 16401 49206) 26 | (take 10 (next (lambda (x y) (* 3 (+ x y))) 1 1))) 27 | (is-equal 28 | '(1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536) 29 | (take 17 (next (lambda (x _) (* 2 x)) 1 1))) 30 | (is-equal 31 | '(1 4.0 25.0 676.0 458329.0 210066388900.0 4.4127887745906175e22) 32 | (take 7 (next (lambda (x _) (math:pow (+ x 1) 2)) 1 1)))) 33 | 34 | (deftest range 35 | (is-equal 1 (car (funcall (range)))) 36 | (is-equal 2 (car (funcall (cdr (funcall (range)))))) 37 | (is-equal 3 (car (funcall (cdr (funcall (cdr (funcall (range)))))))) 38 | (is-equal 4 (car (funcall (cdr (funcall (cdr (funcall (cdr (funcall (range))))))))))) 39 | 40 | (deftest split-at 41 | (is-equal 42 | '((1 2 3) (4 5 6 7 8 9 10 11 12)) 43 | (split-at 3 '(1 2 3 4 5 6 7 8 9 10 11 12)))) 44 | 45 | (deftest split-by 46 | (is-equal 47 | '() 48 | (split-by 0 '())) 49 | (is-equal 50 | '() 51 | (split-by 1 '())) 52 | (is-equal 53 | '() 54 | (split-by 100 '())) 55 | (is-equal 56 | '(1 2 3 4 5 6 7 8 9 10 11 12) 57 | (split-by 0 '(1 2 3 4 5 6 7 8 9 10 11 12))) 58 | (is-equal 59 | '((1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12)) 60 | (split-by 1 '(1 2 3 4 5 6 7 8 9 10 11 12))) 61 | (is-equal 62 | '((1 2) (3 4) (5 6) (7 8) (9 10) (11 12)) 63 | (split-by 2 '(1 2 3 4 5 6 7 8 9 10 11 12))) 64 | (is-equal 65 | '((1 2 3 4 5) (6 7 8 9 10) (11 12)) 66 | (split-by 5 '(1 2 3 4 5 6 7 8 9 10 11 12))) 67 | (is-equal 68 | '((1 2 3 4 5 6 7) (8 9 10 11 12)) 69 | (split-by 7 '(1 2 3 4 5 6 7 8 9 10 11 12))) 70 | (is-equal 71 | '((1 2 3 4 5 6 7 8 9 10 11) (12)) 72 | (split-by 11 '(1 2 3 4 5 6 7 8 9 10 11 12))) 73 | (is-equal 74 | '((1 2 3 4 5 6 7 8 9 10 11 12)) 75 | (split-by 12 '(1 2 3 4 5 6 7 8 9 10 11 12)))) 76 | 77 | (deftest interleave 78 | (is-equal '(a 1 b 2 c 3) (interleave '(a b c) '(1 2 3)))) 79 | 80 | (defun get-in-data-1 () 81 | '((1) 82 | (1 2 3) 83 | (1 2 (3 4 (5 6 (7 8 9)))))) 84 | 85 | (deftest get-in-nth 86 | (is-equal 1 (get-in 1 1 (get-in-data-1))) 87 | (is-equal 3 (get-in 2 3 (get-in-data-1))) 88 | (is-equal 9 (get-in 3 3 3 3 3 (get-in-data-1))) 89 | (is-equal 'undefined (get-in 4 (get-in-data-1))) 90 | (is-equal 'undefined (get-in 4 3 3 3 (get-in-data-1)))) 91 | 92 | (defun get-in-data-2 () 93 | '(#(key-1 val-1) 94 | #(key-2 val-2) 95 | #(key-3 (#(key-4 val-4) 96 | #(key-5 val-5) 97 | #(key-6 (#(key-7 val-7) 98 | #(key-8 val-8) 99 | #(key-9 val-9))))))) 100 | 101 | (deftest get-in-keys 102 | (is-equal 'val-1 (get-in 'key-1 (get-in-data-2))) 103 | (is-equal 'val-5 (get-in 'key-3 'key-5 (get-in-data-2))) 104 | (is-equal 'val-9 (get-in 'key-3 'key-6 'key-9 (get-in-data-2))) 105 | (is-equal 'undefined (get-in 'key-18 (get-in-data-2))) 106 | (is-equal 'undefined (get-in 'key-3 'key-6 'key-89 (get-in-data-2))) 107 | (is-equal 'undefined (get-in 'key-3 'key-6 'key-89 'key-100(get-in-data-2)))) 108 | 109 | (deftest reduce 110 | (is-equal 6 (reduce (lambda (x acc) (+ x acc)) '(1 2 3))) 111 | (is-equal 6 (reduce #'+/2 '(1 2 3))) 112 | (is-equal 6 (reduce (fun + 2) '(1 2 3))) 113 | (is-equal 6 (reduce (lambda (x acc) (+ x acc)) 0 '(1 2 3))) 114 | (is-equal 6 (reduce #'+/2 0 '(1 2 3))) 115 | (is-equal 6 (reduce (fun + 2) 0 '(1 2 3)))) 116 | 117 | (deftest repeat 118 | (is-equal '(1 1 1) (repeat 3 1)) 119 | (is-equal '("xo" "xo") (repeat 2 "xo")) 120 | (is-equal '() (repeat 0 "oh noes")) 121 | (is-equal '(ok ok ok ok) (repeat 4 'ok)) 122 | (is-error function_clause (repeat -1 0)) 123 | (is-equal '(1 1 1) (repeat 3 (lambda () 1))) 124 | (is-error function_clause (repeat -1 (lambda () 1))) 125 | (is-equal 2 (length (repeat 2 #'random:uniform/0)))) 126 | --------------------------------------------------------------------------------