schemedoc / cookbook Goto Github PK
View Code? Open in Web Editor NEWNew Scheme Cookbook
Home Page: https://cookbook.scheme.org
New Scheme Cookbook
Home Page: https://cookbook.scheme.org
Sorry, I didn't follow the process. I accidentally pushed my index-list contribution directly to the repo. Please let me know if there are any fixes I should make.
You have a list and you need to find the element with duplicates and find the most frequent element. If the list has no duplicates is should return #f
.
(define (most-frequent xs)
(let count-all-elements ((xs xs) (counters '()))
(if (null? xs)
(let find-max-count ((counters counters) (best #f))
(if (null? counters)
(and best (car best))
(find-max-count
(cdr counters)
(let* ((counter (car counters))
(count (cdr counter)))
(if (and (> count 1) (or (not best) (> count (cdr best))))
counter
best)))))
(count-all-elements
(cdr xs)
(let* ((x (car xs))
(counter (assoc x counters)))
(if (not counter)
(cons (cons x 1) counters)
(begin (set-cdr! counter (+ (cdr counter) 1))
counters)))))))
using hash tables (SRFI 125)
(define (most-frequent xs)
(define (inc n) (+ n 1))
(let ((counts (make-hash-table equal?)))
(let loop ((xs xs) (best-x #f))
(if (null? xs)
best-x
(loop (cdr xs)
(let ((x (car xs)))
(hash-table-update!/default counts x inc 0)
(let ((count (hash-table-ref counts x)))
(if (and (> count 1)
(or (not best-x)
(> count (hash-table-ref counts best-x))))
x
best-x))))))))
Credit @lassik
(most-frequest '(1 2 3 4 2 3 4 2 2 2))
;; ==> 2
(most-frequest '(1 2 3 4 5 6 7))
;; ==> #f
This is the code Arthur Emacs symbol mapping
(defvar pretty-scheme-keywords
(mapcar (lambda (pair)
(cons (concat "\\(" (regexp-quote (car pair)) "\\)")
(cdr pair)))
'(("->" . #x2192)
("<=" . #x2264)
("<==" . #x21D0)
(">=" . #x2265)
("==>" . #x21D2)))
"Alist from regexps to Unicode code points.")
(defun prettify-scheme ()
(add-to-list 'prettify-symbols-alist '("lambda" . #x3BB))
(font-lock-add-keywords
nil
(mapcar (lambda (keyword)
`(,(car keyword)
(0 (progn (compose-region (match-beginning 1) (match-end 1)
,(cdr keyword)
'decompose-region)
nil))))
pretty-scheme-keywords))
(turn-on-font-lock))
(add-hook 'scheme-mode-hook 'prettify-scheme)
It seems that on each opening of Scheme file new lambda will be added to the list which makes the list grow and grow on each open file.
I think that this line:
(add-to-list 'prettify-symbols-alist '("lambda" . #x3BB))
Should be outside of the function is it's called only once.
Implement optional positional arguments in portable code (RnRS and syntax-rules).
https://github.com/ashinn/chibi-scheme/blob/master/lib/chibi/optional.scm
@lassik What do you think about this macro syntax-symbol? it's based on Oleg Kiselyov. I've found it while searching for missing macros from SRFI-46.
I think that if multiple people contributed to the final form of this macro, we can consider it Public Domain. We can credit Oleg. What you think?
Is there anyway for us to look up symbols in REPL in one module(,m r5rs
) ,and like Python dir(object) to look up the attributes (methods and attributes)? Seem like there is an egg apropos
to help out. But as I installed it. It is more like emacs-symbolist to look up symbols present in the currently running REPL session. For instance, call-with-port
is in the module r7rs
in chicken implementation, But after import r7rs
, whichever module (,m r5rs
or ,m r7rs
)are you in, they always check with symbols by ,a call-with-port
in the module r7rs
.
The Cookbook should (as it says) emphasize modern solutions. I wouldn't call the solution
cookbook/recipes/get-type-of-object.md
Line 30 in 76456bc
modern because it loops through a list effectively built at runtime, preventing compiler optimizations. A "modern" solution would use modern macros. :) Or a hardcoded cond
expression where the compiler can inline the primitives.
An independent question: What is a compelling use case for the procedure?
You need a function that will convert any value to a string
(define-values (displayed written)
(let ((repr (lambda (fn)
(lambda (object)
(call-with-port (open-output-string)
(lambda (port)
(fn object port)
(get-output-string port)))))))
(values (repr display) (repr write))))
Credit @jcubic
The functions displayed
and written
are also defined by SRFI 166.
(define (print x)
(display x)
(newline))
(print (written #\x))
;; ==> #\x
(print (written "foo"))
;; ==> "foo"
(print (written '(1 2 3)))
;; ==> (1 2 3)
There are few scheme scripts in repo, but it's not clear which function run and in which order.
We can use make
(create Makefile) and put all stuff that needs to be run to build all the HTML files.
You have Alist and you need to return the new Alist only with specified keys.
(define (match value)
(lambda (x)
(equal? x value)))
(define (alist->subset keys alist)
(let iter ((alist alist) (keys keys) (result '()))
(if (or (null? alist) (null? keys))
(reverse result)
(let* ((pair (car alist)) (key (car pair)))
(if (member key keys)
(let ((keys (remove (match keys) keys)))
(iter (cdr alist) keys (cons pair result)))
(iter (cdr alist) keys result))))))
Credit @jcubic
It uses the remove
function from Recipe #6
The code assumes that Alist has all unique keys.
(define alist '((foo . 10) (bar . 20) (baz . 30) (quux . 40)))
(alist->subset '(quux foo) alist)
;; => '((foo . 10) (quux . 40))
The proposed solution for string-split
uses string-ref
and substring
. Both are allowed to be O(n) where n is the length of the string. Thus the solution can be accidentally quadratic on some Schemes. It should not be promoted but rewritten.
cookbook/recipes/split-string.md
Line 16 in 76456bc
As in my site, it is needed a proxy to access the host schemecookbook.org
. That means I can not see this cookbook at all. But the cookbook look likes so amazing to have.
So I downloaded the file schemecookbook.org.tgz from in you site. Upzip to it the files in my laptop. Then go the folder ..\schemecookbook.org\Cookbook
, edit the fileindex.html
in Emacs.
<div contentbox>
, and put corsal position there.set-mark_command
, Forward Tag
in html-mode.browse-url-of-buffer
And I got the item list of the cookbook in the webpage. Then by the item name in this page I can find which one is what I am interesting, then come to the corresponding folder in the unzipped folder schemecookbook.org
for the webpage(index.html
) of each item. Of course edit index.html
in Emacs as the same way I did in the above.
For the search ability, like grep
the title or code in the target folder schemecookbook.org
.
The question is that by the above way to reference the cookbook we have out there. Is it missing a lots?
You have a directory containing an unknown set of subdirectories and files. For example:
a/a.png
a/a.html
b/b.html
b/c/c.html
c/d.png
d/
Return a list with the relative pathname (e.g. "b/c/c.html"
) of each .html
file in this tree.
No portable solution exists at the moment. SRFI 170 or implementation-specific libraries can be used.
Using SRFI 170 (and string-suffix-ci? comes from SRFI 13)
(define (directory-tree-fold merge state root)
(define (path-append a b)
(if (and a b) (string-append a "/" b) (or a b)))
(let recurse ((state state) (relative #f))
(let* ((path (path-append root relative))
(state (merge path state))
(directory? (file-info-directory? (file-info path #t))))
(if (not directory?) state
(let loop ((state state) (names (directory-files path)))
(if (null? names) state
(loop (recurse state (path-append relative (car names)))
(cdr names))))))))
(directory-tree-fold
(lambda (name names)
(if (string-suffix-ci? ".html" name) (cons name names) names))
'() ".")
Credit @lassik
As learning to run the top level script in the different implementation of Scheme, sound like there are different options available for me. But it takes a while for me to figure out what they are, how can it be used when running the script. Sound like there is a need to standardize the options or part of them for the top level script to run. But is it possible for the implementors point view to do that? Or we already did it before?
Just got a message from Nils M Holm. He did few books about Scheme and pointed to:
http://t3x.org/s9fes/lib.html and http://t3x.org/s9fes/contrib.html
the code is from the book "Scheme 9 from Empty Space" all examples are in the public domain.
Write a procedure (group n lst)
that splits a list into groups of n
consecutive elements.
If the list length is not divisible by n
, the last group will have fewer than n
elements.
The procedure should return a list of the groups in order, such that each group is a sublist of the main list.
(define (group n lst)
(if (< n 1)
(error "group: n must be positive" n)
(let loop ((lst lst) (m n) (g '()) (gs '()))
(cond ((and (null? lst) (null? g))
(reverse gs))
((or (null? lst) (zero? m))
(loop lst n '() (cons (reverse g) gs)))
(else
(loop (cdr lst) (- m 1) (cons (car lst) g) gs))))))
Credit: @lassik
;;; Normal examples:
(group 1 (iota 10))
;; ==> ((0) (1) (2) (3) (4) (5) (6) (7) (8) (9))
(group 2 (iota 10))
;; ==> ((0 1) (2 3) (4 5) (6 7) (8 9))
(group 3 (iota 10))
;; ==> ((0 1 2) (3 4 5) (6 7 8) (9))
(group 4 (iota 10))
;; ==> ((0 1 2 3) (4 5 6 7) (8 9))
(group 5 (iota 10))
;; ==> ((0 1 2 3 4) (5 6 7 8 9))
(group 6 (iota 10))
;; ==> ((0 1 2 3 4 5) (6 7 8 9))
;;; Special cases:
(group 20 (iota 10))
;; ==> ((0 1 2 3 4 5 6 7 8 9))
(group 1 '())
;; ==> ()
(group 2 '())
;; ==> ()
Because the old cookbook has an LGPL license we can't use it for a new cookbook and force people to include a license.
Solution: create a completely new cookbook.
I propose license CC-BY-SA same as StackOverflow from where we can grab some solutions to common problems.
If you want to share the recipe please create an issue.
You have a list and you want to remove any duplicated elements from the list and the order should not change.
The solution can use the equal?
function or use the comparison function as an argument.
Using hash tables (SRFI 125)
(define (remove-duplicates xs)
(let ((seen (make-hash-table equal?)))
(let loop ((xs xs) (new-list '()))
(if (null? xs)
(reverse new-list)
(loop (cdr xs)
(let ((x (car xs)))
(if (hash-table-contains? seen x)
new-list
(begin (hash-table-set! seen x #t)
(cons x new-list)))))))))
Credit @lassik
(remove-duplicates '(1 2 3 1 2 4 4 5 6 7 5))
;; ==> '(1 2 3 4 5 6 7)
There is SRFI-200 (Draft) for pattern matching but I have my own implementation, that I've created as an example for my Scheme implementation:
Here is the whole code, we can use this in cookbook, the code is not that long, but unfortunately, it uses lisp-macros I'm not sure if you can rewrite it with syntax-rules
(or syntax-case)
;; Example pattern matching macro
;;
;; This file is part of the LIPS - Scheme implementation in JavaScript
;; Copyriht (C) 2019-2021 Jakub T. Jankiewicz <https://jcubic.pl/me>
;; Released under MIT license
(cond-expand
(lips)
(guile
(define (object? x) #f)
(define (type x)
(cond ((string? x) "string")
((pair? x) "pair")
((null? x) "nil")
((number? x) "number")
((vector? x) "array")
((procedure? x) "function")
((char? x) "character")))))
;; ---------------------------------------------------------------------------------------
(define (compare a b)
"(compare a b)
Function that compare two values. it compare lists and any element of the list
can be a function that will be called with other value. e.g.:
(compare (list (list 'a) 'b) (list pair? 'b))"
(cond ((and (pair? a) (pair? b))
(and (compare (car a) (car b))
(compare (cdr a) (cdr b))))
((and (vector? a) (vector? b))
(compare (vector->list a) (vector->list b)))
((and (object? a) (object? b))
(compare (vector->list (--> Object (keys a)))
(vector->list (--> Object (keys b)))))
((string=? (type a) (type b)) (eq? a b))
((and (procedure? a) (not (procedure? b)))
(a b))
((and (not (procedure? a)) (procedure? b))
(b a))
(else #f)))
;; ---------------------------------------------------------------------------------------
(define-macro (auto-quote arg)
"(auto-quote list)
Macro that create list recursively but take symbols from scope"
(if (pair? arg)
`(list ,@(map (lambda (item)
(if (symbol? item)
item
(if (pair? item)
`(auto-quote ,item)
`,item)))
arg))
arg))
;; ---------------------------------------------------------------------------------------
(define-macro (match-pattern expr . list)
"(match-pattern ((pattern . body) ...))
Pattern matching macro. examples:
(match-pattern (1 (pair? pair?) 2) ((1 ((1) (1)) 2) (display \"match\")))
;; match
(match-pattern (1 (pair? pair?) 2) ((1 ((1)) 2) (display \"match\")))
(match-pattern (1 (pair? pair?) 2) ((1 ((1)) 2) (display \"match\")) (true \"rest\"))
;; rest"
(if (pair? list)
(let ((ex-name (gensym)))
`(let ((,ex-name (auto-quote ,expr)))
(cond ,@(map (lambda (item)
(if (eq? (car item) #t)
`(else ,(cadr item))
`((compare ,ex-name (auto-quote ,(car item))) ,@(cdr item))))
list))))))
;; ---------------------------------------------------------------------------------------
(match-pattern (1 (pair? pair?) 2) ((1 ((1) (1)) 2)
(display "match")
(newline)))
The license is MIT but I'm fine in releasing it for scheme cookbook in multiple licenses.
@lassik what do you think? Can we put lisp macros into cookbook or should we do only pure R7RS compatible code?
You have a list and want to remove items that return true for a given predicate function
(define (remove fn list)
(let iter ((list list) (result '()))
(if (null? list)
(reverse result)
(let ((item (car list)))
(if (fn item)
(iter (cdr list) result)
(iter (cdr list) (cons item result)))))))
Credit @jcubic
This function is part of SRFI-1, which also has filter
that is reverse of remove
, where if the function returns true
the item will be kept in the output list.
(define >10 (lambda (x) (> x 10)))
(remove >10 '(1 2 3 4 10 11 12 13 14))
;; ==> (1 2 3 4 10)
This is the first recipe that I've created using lisp macro.
The problem is that we want syntax similar to letrec but for macros (not that the same can be rewritten as a hygienic macro):
(define-macro (let-macro macros . body)
`(let ()
,@(map (lambda (macro)
(if (and (symbol? (car macro))
(symbol=? (caadr macro) 'lambda))
(let ((name (car macro))
(args (cadadr macro))
(body (cddadr macro)))
`(define-macro (,name ,@args)
,@body))
(error "let-macro: invalid syntax")))
macros)
(begin
,@body)))
(define (print . args)
(for-each (lambda (arg)
(display arg)
(newline))
args)
(let-macro ((foo (lambda (x) `'(,x ,x)))
(bar (lambda (x y . rest) `(list ,x ,y ,@rest))))
(print (list (foo a) (foo b) (bar 1 2 3 4))))
You want to search and find the index of a string inside a bigger string.
(define (string-find haystack needle . rest)
(let ((start (if (null? rest) 0 (car rest))))
(let* ((haystack-len (string-length haystack))
(needle-len (string-length needle))
(start 0))
(let loop ((h-index start)
(n-index 0))
(let ((h-char (string-ref haystack h-index))
(n-char (string-ref needle n-index)))
(if (char=? h-char n-char)
(if (= (+ n-index 1) needle-len)
(+ (- h-index needle-len) 1)
(loop (+ h-index 1) (+ n-index 1)))
(if (= (+ h-index 1) haystack-len)
#f
(loop (+ h-index 1) 0))))))))
The same functionality is provided by SRFI-13 function string-contains
and string-contains-ci
Credit: @jcubic
(let* ((input "This is hello world")
(search "hello")
(found (string-find input search)))
(if found
(begin
(display (substring input found))
(newline))))
;; ==> "helo world"
We need to decide what license the cookbook will have. Then we will need to add to the website footer (best on each recipe page) and into README and add a file with a license.
You have a list and a function and you want to find the first index for an item for which the function returns true.
(define (list-index fn list)
(let iter ((list list) (index 0))
(if (null? list)
-1
(let ((item (car list)))
(if (fn item)
index
(iter (cdr list) (+ index 1)))))))
Credit @jcubic
This function is defined in SRFI-1
(define >10 (lambda (x) (> x 10)))
(index >10 '(1 2 3 4 10 11 12 13 14))
;; ==> 5
This is file is a standard file used on GitHub when creating a PR and we can link it in README.
The file should say how to create recipes. We will need to decide how to go about it. If we migrate to PR, then we will need to remove or improve the recipe issue template and create a template for PR linked in CONTRIBUTING file. It actually can be the same file since it's already in markdown.
Also, it would be nice to automate publishing the cookbook using CI/CD, we can use free Travis service or GitHub actions.
Split a string into substrings at known delimiters.
(define (string-split char-delimiter? string)
(define (maybe-add a b parts)
(if (= a b) parts (cons (substring string a b) parts)))
(let ((n (string-length string)))
(let loop ((a 0) (b 0) (parts '()))
(if (< b n)
(if (not (char-delimiter? (string-ref string b)))
(loop a (+ b 1) parts)
(loop (+ b 1) (+ b 1) (maybe-add a b parts)))
(reverse (maybe-add a b parts))))))
Credit @lassik
(string-split char-whitespace? "")
;; ==> ()
(string-split char-whitespace? " \t ")
;; ==> ()
(string-split char-whitespace? "ab")
;; ==> ("ab")
(string-split char-whitespace? "ab c d \t efg ")
;; ==> ("ab" "c" "d" "efg")
I want to be able to take random elements from a list without getting unwanted duplicates (so if I ask for 4 random elements from the list '(a b c d)
I don't want to get to '(d a ba )
, for example).
(define (pick elements how-many)
(if (< how-many 0)
(error "Cannot create a list of negative length."
how-many)
(letrec* ((list-length (length elements))
(new-index (lambda (iteration-list-length)
(random-integer (if (zero? iteration-list-length)
list-length
iteration-list-length))))
(do-pick
(lambda (pick-from unchosen result index how-many)
(cond ((zero? how-many)
result)
((null? pick-from)
(do-pick (if (null? unchosen)
elements
unchosen)
'()
result
index
how-many))
((zero? index)
(do-pick (cdr pick-from)
unchosen
(cons (car pick-from)
result)
(new-index (+ (length (cdr pick-from))
(length unchosen)))
(- how-many 1)))
(else
(do-pick (cdr pick-from)
(cons (car pick-from)
unchosen)
result
(- index 1)
how-many))))))
(do-pick elements '() '() (random-integer list-length) how-many))))
Credit @tmtvl
(pick (iota 100)
100)
;; (79 28 18 40 90 29 30 66 80 36 23 34 42 84 25 35 88 54 15 92 69 8 2 16 95 27 19
;; 74 91 77 68 3 83 57 26 86 89 60 53 47 21 85 72 0 73 96 93 58 32 10 ....)
(pick '(A C G T)
5)
;; (T G A T C)
(+ (car (pick (iota 6)
1))
1)
;; 1
Given a directed acyclic graph (DAG) describing how nodes depend on other nodes, visit the nodes in an order where all dependencies of each node are visited before that node. This algorithm is known as topological sort.
For example, the Unix make
program does a topological sort to figure out the build order for the files.
Public domain, from Shiro Kawai: https://github.com/shirok/Gauche/blob/master/lib/util/toposort.scm
You have a number with more than one digits, and you want a list with all its digits as numbers.
(define (number->list number)
(let ((chars (string->list (number->string number))))
(map (lambda (char)
(string->number (string char)))
chars)))
Credit @jcubic
(number->list 10001)
;; ==> '(1 0 0 0 1)
I've seen this pattern in a book by Nils M Hom Sketchy Scheme. it can be written as a variable or as a macro:
(define void (if #f #f))
(define-syntax void
(syntax-rules ()
((_) (if #f #f))))
This is a way to get undefined (or to be precise unspecified by R7RS spec) value in Scheme.
But I'm not sure how much it's compatible with different scheme systems.
we can also add predicate:
(define (void? x)
(equal? (if #f #f) x))
(define (void? x)
(equal? x void))
Tested in Chicken, Guile, and Kawa (that gives warning warning - missing else where value is required
).
It seems that different Scheme implementation works differently in terms of loading R7RS. If we have R7RS code that doesn't work the same out of the box we should list all major implementations and show how to use the code.
An example is bytevector?
in Chicken Scheme discussed in #46 also guile use some other code to use R7RS otherwise some of the code may don't work.
I would add a table (markdown support tables, at least on GitHub) with a matrix:
Scheme | file | REPL |
---|---|---|
Chiken | ... | ... |
Guile | ... | ... |
Kawa | ... | ... |
Given an integer saying the number of seconds since the Unix epoch (1970-01-01 00:00:00) format it as a human-readable date and time string.
Using SRFI-19
(define (time-unix->time-utc seconds)
(add-duration (date->time-utc (make-date 0 0 0 0 1 1 1970 0))
(make-time time-duration 0 seconds)))
(define (time-unix->string seconds . maybe-format)
(apply date->string (time-utc->date (time-unix->time-utc seconds))
maybe-format))
Credit @weinholt
; Loko
> (time-unix->string 946684800)
"Sat Jan 01 00:00:00Z 2000"
; Chez
> (time-unix->string 946684800)
"Sat Jan 01 02:00:00+0200 2000"
; Guile
> (time-unix->string 946684800)
$1 = "Sat Jan 01 01:00:00+0100 2000"
I have this function in my interpreter, but it does a lot more since it also returns types for JavaScript objects and also internal implementation objects.
Here is something for R7RS scheme:
(define (type obj)
(cond ((number? obj) "number")
((string? obj) "string")
((symbol? obj) "symbol")
((vector? obj) "vector")
((pair? obj) "pair")
((null? obj) "nil")
((procedure? x) "procedure")
((char? x) "character")
((boolean? obj) "boolean")))
Unfortunately, there is no way to test if an object is a record type.
@lassik Should we include functions like this or is it too simple? I think it would be nice to have this function so you don't need to write it yourself and can just copy/paste.
@jcubic Should we store the recipes as Markdown files in Git, and write some Scheme code to turn them into HTML and upload them on the server?
We should also decide on the URL - cookbook.scheme.org
or doc.scheme.org/cookbook
?
It would be nice to have GitHub workflow that will build and upload the file to the server. It will make it easier to manage. When this is done for this repo it could be replicated for different repositories.
This is continuation of discussion in #43
We should probably decide on common names to use for variables in similar situations. For example:
list
argument to procedure (or lis
or lst
) by default?(let ((elem (car list)) (rest (cdr list))) ...)
(let loop ...)
?inner
and outer
with nested loops.loop
and recurse
are good ways to differentiate proper tail recursion (needs O(1) stack space) from general recursion (O(n) stack space).Haskell has a convention of using x
for a list element, and xs
for the list. xs
is meant as the plural of x
: "multiple x's". They also use y
and ys
.
You have a list of strings and string delimiter and you want to create a single string from the list with a delimiter in between
(define (string-join list delimiter)
(let iter ((list list) (result '()))
(if (null? list)
(apply string-append (reverse result))
(let ((item (car list))
(rest (cdr list)))
(if (null? result)
(iter rest (cons item result))
(iter rest (cons item (cons delimiter result))))))))
Credit @jcubic
Alternative using string ports
(define (string-join list delimiter)
(if (null? list) ""
(call-with-port (open-output-string)
(lambda (out)
(write-string (car list) out)
(for-each (lambda (item)
(write-string delimiter out)
(write-string item out))
(cdr list))
(get-output-string out)))))
Credit @lassik
you can use SRFI-13 that provides string-join
function.
(string-join '("foo" "bar" "baz") ":")
;; ==> "foo:bar:baz"
I have a task queue and I want to split the work among multiple threads. There can be many more tasks than threads.
The mailbox
library is Chicken only, but any other thread-safe queue could be used instead.
(import (srfi 18))
(cond-expand (chicken (import (mailbox))))
(define (map-iota proc n)
(let loop ((new-list '()) (i 0))
(if (= i n) (reverse new-list)
(loop (cons (proc i) new-list) (+ i 1)))))
(define thread-pool-size (make-parameter 2))
(define (run-thread-pool thunks)
(let ((mailbox (make-mailbox)))
(define (worker)
(let loop ()
(let ((thunk (mailbox-receive! mailbox 0 (eof-object))))
(unless (eof-object? thunk)
(thunk)
(loop)))))
(define (index->thread-name i)
(string (integer->char (+ i (char->integer #\A)))))
(for-each (lambda (thunk) (mailbox-send! mailbox thunk))
thunks)
(let ((threads (map-iota (lambda (i)
(make-thread worker (index->thread-name i)))
(thread-pool-size))))
(for-each thread-start! threads)
(let loop ()
(unless (mailbox-empty? mailbox)
(thread-sleep! 0.1)
(loop)))
(for-each thread-join! threads))))
Credit: @lassik
Someone askes on /r/lisp Sub Reddit: Python's approach is much better {{{ x= ( 10 * [a] ) }}} because i don't have to remember the (ad-hoc) name of the function.
I think it would be fun to create code that will make Scheme work like Python. examples of python code:
[1] * 2 * 4 * 5
2 * [2] * 3 * 3
"x" * 2 * 3
10 * "x" * 10 * 2
you can put sequence (here list or string) and use multiplication to make the sequence larger. And +
works by concatenation of the sequences.
Here is my quick code for two arguments:
(define * (let ((mul *))
(lambda args
(if (= (length args) 2)
(let ((first (car args))
(second (cadr args)))
(cond ((and (list? first) (integer? second))
(apply append (make-list second first)))
((and (list? second) (integer? first))
(apply append (make-list first second)))
(else
(apply mul args))))
(apply mul args)))))
scheme> (* '(1 2) 10)
;; ==> (1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2)
scheme> (* 1 2)
;; ==> 2
I think it would be a nice exercise to make *
work exactly like in Python with lists, vectors, and strings. and It would be a good example that will show that Scheme is more powerful than python because you can do exactly the same what python have in Scheme but not other way around.
What do you think about including a recipe something like "Python * and + in Scheme" or something similar?
NOTE: if you don't like overwriting builtins it was used by Gerrald Sussman in his talk We Really Don't Know How to Compute! from 2011 Strange Loop.
Write a procedure (group-by f lst)
that splits the list lst
into sublists. The sublist boundaries are determined by the value of (f x)
for each element x
in lst
. When the value changes, a new sublist is started from that element. Values of (f x)
are compared by equal?
.
Return a list of the groups, i.e. each group is a sublist in the main list.
(define (group-by f lst)
(if (null? lst) '()
(let ((first (car lst)))
(let loop ((lst (cdr lst)) (key (f first)) (g (list first)) (gs '()))
(if (null? lst)
(reverse (cons (reverse g) gs))
(let ((newkey (f (car lst))))
(if (equal? key newkey)
(loop (cdr lst) key
(cons (car lst) g)
gs)
(loop (cdr lst) newkey
(list (car lst))
(cons (reverse g) gs)))))))))
Credit: @lassik
(group-by even? (iota 10))
;; ==> ((0) (1) (2) (3) (4) (5) (6) (7) (8) (9))
(group-by odd? '(1 3 5 2 1 6 4 1 7))
;; ==> ((1 3 5) (2) (1) (6 4) (1 7))
(group-by string-length '("aa" "bb" "ccc" "dddd" "eeee" "ffff" "g" "h"))
;; ==> (("aa" "bb") ("ccc") ("dddd" "eeee" "ffff") ("g" "h"))
(group-by (lambda (i) (truncate-quotient i 3)) (iota 20))
;; ==> ((0 1 2) (3 4 5) (6 7 8) (9 10 11) (12 13 14) (15 16 17) (18 19))
It would be nice to have the scheme.org menu on the individual cookbook pages. I'm afraid I cannot test this, but would something like the following hand-written changes to www.scm work?
First, define the header:
(define header '(header
(ul (@ (class "menu"))
(li (a (@ (href "https://www.scheme.org")) "Home"))
(li (@ (class "active")) "Docs")
(li (a (@ (href "https://community.scheme.org")) "Community"))
(li (a (@ (href "https://standards.scheme.org")) "Standards"))
(li (a (@ (href "https://implementations.scheme.org")) "Implementations")))))
Add to main page by changing line 127 to splice in the header:
`(,header (h1 (@ (id "logo")) "Scheme Cookbook")
And add to each recipe by changing line 163 to splice in the header:
`(,header ,@(recipe-sxml recipe)
Check if all elements are the same using a predicate.
I'm not sure if there is already a utility like this in some of SRFI. But there are few solutions on StackOverflow, but they use equal?
instead of predicate: Scheme: How to check if all elements of a list are identical.
I came up with a solution using fold:
(define (ordered? fn . args)
(let ((first (car args)))
(fold (lambda (arg result)
(and result (equal? arg first)))
#t
(cdr args))))
Credit: @jcubic
It can be used to check if strings are sorted (for R5RS implementation where string comparators accept 2 arguments) or check if all elements are equal. You can also check if any sequence is monotonous.
(ordered? eq? 1 1 1 1 1 1)
(define (identical? . args)
(apply ordered? eq? args))
(identical? 1 1 1 1 1 1 1)
;; ==> #t
(identical? 1 1 1 1 1 1 0)
;; ==> #f
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.