Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the branching arrows -<, -<<, --<, and -as-<. (resubmitted) #280

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 85 additions & 1 deletion README.md
Expand Up @@ -147,6 +147,7 @@ Functions reducing lists into single value.
* [-inits](#-inits-list) `(list)`
* [-tails](#-tails-list) `(list)`
* [-common-prefix](#-common-prefix-rest-lists) `(&rest lists)`
* [-common-suffix](#-common-suffix-rest-lists) `(&rest lists)`
* [-min](#-min-list) `(list)`
* [-min-by](#-min-by-comparator-list) `(comparator list)`
* [-max](#-max-list) `(list)`
Expand Down Expand Up @@ -275,6 +276,10 @@ Functions pretending lists are trees.
* [-some->](#-some--x-optional-form-rest-more) `(x &optional form &rest more)`
* [-some->>](#-some--x-optional-form-rest-more) `(x &optional form &rest more)`
* [-some-->](#-some---x-optional-form-rest-more) `(x &optional form &rest more)`
* [-<](#--x-collector-rest-forms) `(x collector &rest forms)`
* [-<<](#--x-collector-rest-forms) `(x collector &rest forms)`
* [--<](#---x-collector-rest-forms) `(x collector &rest forms)`
* [-as-<](#-as--x-collector-variable-rest-forms) `(x collector variable &rest forms)`

### Binding

Expand Down Expand Up @@ -1052,10 +1057,20 @@ Return the longest common prefix of `lists`.

```el
(-common-prefix '(1)) ;; => '(1)
(-common-prefix '(1 2) nil '(1 2)) ;; => nil
(-common-prefix '(1 2) '(3 4) '(1 2)) ;; => nil
(-common-prefix '(1 2) '(1 2 3) '(1 2 3 4)) ;; => '(1 2)
```

#### -common-suffix `(&rest lists)`

Return the longest common suffix of `lists`.

```el
(-common-suffix '(1)) ;; => '(1)
(-common-suffix '(1 2) '(3 4) '(1 2)) ;; => nil
(-common-suffix '(1 2 3 4) '(2 3 4) '(3 4)) ;; => '(3 4)
```

#### -min `(list)`

Return the smallest value from `list` of numbers or markers.
Expand Down Expand Up @@ -2188,6 +2203,75 @@ and when that result is non-nil, through the next form, etc.
(-some--> '(1 3 5) (-filter 'even? it) (append it it) (-map 'square it)) ;; => nil
```

#### -< `(x collector &rest forms)`

Thread the expr through each form in parallel. Insert `x` as the
second item in each form, then call `collector` on the result.
`collector` must be able to take as many arguments as the length of
`forms`. `x` will be evaluated only once.

`collector` may have short-circuiting behavior like the `and`
special form.


```el
(-< '(2 3 5) list) ;; => '((2 3 5))
(-< '(2 3 5) list (append '(8 13))) ;; => '((2 3 5 8 13))
(-< '(2 3 5) list (append '(8 13)) (-slice 1 -1)) ;; => '((2 3 5 8 13) (3))
```

#### -<< `(x collector &rest forms)`

Thread the expr through each form in parallel. Insert `x` as the
last item in each form, then call `collector` on the result.
`collector` must be able to take as many arguments as the length of
`forms`. `x` will be evaluated only once.

`collector` may have short-circuiting behavior like the `and`
special form.


```el
(-<< '(1 2 3) list (-map 'square)) ;; => '((1 4 9))
(-<< '(1 2 3) list (-map 'square) (-remove 'even?)) ;; => '((1 4 9) (1 3))
(-<< '(1 2 3) list (-map 'square) (-reduce '+)) ;; => '((1 4 9) 6)
```

#### --< `(x collector &rest forms)`

Thread the expr through each form in parallel.

Insert `x` at the position signified by the symbol `it` in the each
form, then call `collector` on the result. `collector` must be able
to take as many arguments as the length of `forms`. `x` will be
evaluated only once.

`collector` may have short-circuiting behavior like the `and`
special form.

```el
(--< "def" list (concat "abc" it "ghi")) ;; => '("abcdefghi")
(--< "def" list (concat "abc" it "ghi") (upcase it)) ;; => '("abcdefghi" "DEF")
(--< "def" list (concat "abc" it "ghi") upcase) ;; => '("abcdefghi" "DEF")
```

#### -as-< `(x collector variable &rest forms)`

Thread the expr through each form in parallel. Bind `variable`
to `x` in each form, then call `collector` on the result. `collector`
must be able to take as many arguments as the length of `forms`. `x`
will be evaluated only once.

`collector` may have short-circuiting behavior like the `and`
special form.


```el
(-as-< 3 list my-var (1+ my-var) (list my-var) (mapcar (lambda (ele) (* 2 ele)) (list my-var))) ;; => '(4 (3) (6))
(-as-< 3 list my-var 1+) ;; => '(4)
(-as-< 3 list my-var) ;; => '(3)
```


## Binding

Expand Down
63 changes: 63 additions & 0 deletions dash.el
Expand Up @@ -1554,6 +1554,69 @@ and when that result is non-nil, through the next form, etc."
(--> ,result ,form))
,@more))))

(defmacro dash--thread-each-and-collect (op x collector &optional forms)
"Private: Used by -< and -<<.

Returned expr: (COLLECTOR (OP X form1) (OP X form2) ...).
If no forms were passed then returned expr would be: (COLLECTOR (OP X nil)).
X will be evaluated only once.
"
(let ((value (make-symbol "value")))
`(let ((,value ,x))
(,collector ,@(--map (list op value it)
(or forms '(nil)))))))

(defmacro -< (x collector &rest forms)
"Thread the expr through each form in parallel. Insert X as the
second item in each form, then call COLLECTOR on the result.
COLLECTOR must be able to take as many arguments as the length of
FORMS. X will be evaluated only once.

COLLECTOR may have short-circuiting behavior like the `and'
special form.
"
`(dash--thread-each-and-collect -> ,x ,collector ,forms))

(defmacro -<< (x collector &rest forms)
"Thread the expr through each form in parallel. Insert X as the
last item in each form, then call COLLECTOR on the result.
COLLECTOR must be able to take as many arguments as the length of
FORMS. X will be evaluated only once.

COLLECTOR may have short-circuiting behavior like the `and'
special form.
"
`(dash--thread-each-and-collect ->> ,x ,collector ,forms))

(defmacro -as-< (x collector variable &rest forms)
"Thread the expr through each form in parallel. Bind VARIABLE
to X in each form, then call COLLECTOR on the result. COLLECTOR
must be able to take as many arguments as the length of FORMS. X
will be evaluated only once.

COLLECTOR may have short-circuiting behavior like the `and'
special form.
"
(cond
((null forms)
`(,collector (-as-> ,x ,variable)))
(:else (let ((value (make-symbol "value")))
`(let ((,value ,x))
(,collector ,@(--map (list '-as-> value variable it)
(or forms '(nil)))))))))

(defmacro --< (x collector &rest forms)
"Thread the expr through each form in parallel.

Insert X at the position signified by the symbol `it' in the each
form, then call COLLECTOR on the result. COLLECTOR must be able
to take as many arguments as the length of FORMS. X will be
evaluated only once.

COLLECTOR may have short-circuiting behavior like the `and'
special form. "
`(-as-< ,x ,collector it ,@forms))

(defun -grade-up (comparator list)
"Grade elements of LIST using COMPARATOR relation, yielding a
permutation vector such that applying this permutation to LIST
Expand Down