#lang scheme/base
(require
scheme/match
"base.ss"
(for-syntax
scheme/base))
(provide
(all-defined-out))
(define first car)
(define second cadr)
(define third caddr)
(define (uncons x) (values (car x) (cdr x)))
(define (take n lst)
(if (or (zero? n)
(null? lst))
'()
(cons (car lst)
(take (sub1 n) (cdr lst)))))
(define (diff-lists l1 l2)
(if (and (not (null? l1))
(not (null? l2))
(eq? (car l1) (car l2)))
(diff-lists (cdr l1) (cdr l2))
(values l1 l2)))
(define (port->list port [read read])
(let next ((lst '()))
(let ((atom (read port)))
(if (eof-object? atom)
(reverse lst)
(next (cons atom lst))))))
(define (hash-add-alist! hash alist)
(for-each
(lambda (x)
(hash-set! hash (car x) (cdr x)))
alist)
hash)
(define (alist->hash alist)
(hash-add-alist! (make-hash) alist))
(define (hash->alist hash)
(hash-map hash cons))
(define-syntax-rule (values->list . body)
(call-with-values
(lambda () . body)
list))
(define (dip fn)
(lambda (lst)
(cons (car lst)
(fn (cdr lst)))))
(define (splash fn)
(lambda (args)
(apply fn args)))
(define (for-each* fn . lsts)
(apply for-each
(lambda (args)
(apply fn args))
lsts))
(define (map* fn . lsts)
(apply map
(lambda (x)
(apply fn x))
lsts))
(define (collect eq? lst)
(let ((tags (list->lset eq? (map car lst))))
(map
(lambda (current-tag)
(cons current-tag
(foldr
(match-lambda* ((list (list-rest tag data) collection)
(if (eq? tag current-tag)
(cons data collection)
collection)))
'() lst)))
tags)))
(define (list->lset same? lst)
(foldr
(lambda (head rest)
(if (contains same? head rest)
rest
(cons head rest)))
'() lst))
(define (contains same? el lst)
(memf (lambda (e) (same? el e)) lst))
(define-syntax-rule (with-stack push! . expr)
(let* ((stack '())
(push! (lambda (x)
(set! stack (cons x stack)))))
(begin . expr)
stack))
(define-syntax-rule (push! stack value)
(let ((rest stack))
(set! stack (cons value rest))))
(define-syntax-rule (pop! stack)
(if (null? stack)
(error 'stack-underflow
"pop!: no elements on: ~a" 'stack)
(let ((top (car stack)))
(set! stack (cdr stack))
top)))
(define-syntax (struct-match stx)
(define (type stx)
(syntax-case stx ()
((tag . fields)
#`(struct tag #,(map type (syntax->list #'fields))))
(name
(identifier? #'name)
#`name)))
(syntax-case stx ()
((_ in (pattern template) ...)
#`(match in
#,(map (lambda (p t)
#`(#,(type p) #,t))
(syntax->list #'(pattern ...))
(syntax->list #'(template ...)))))))
(define-syntax struct-match-lambda
(syntax-rules ()
((_ . body)
(lambda (x) (struct-match x . body)))))
(define (make-sos n)
(for/list ((i (in-range n))) '()))
(define (sos->list sos)
(reverse
(list-ref
(sos-collapse sos)
(- (length sos) 1))))
(define (sos-push sos x)
(cons (cons x (car sos))
(cdr sos)))
(define (sos-collapse sos [n (- (length sos) 1)])
(if (zero? n)
sos
(cons '()
(sos-collapse
(sos-push (cdr sos)
(reverse (car sos)))
(- n 1)))))
(define (sos-stash d entry)
(match d ((list-rest 1st 2nd more)
(list* 1st (cons entry 2nd) more))))
(define-syntax-rule (sos-push! sos x)
(begin
(set! sos (sos-push sos x))
sos))
(define-syntax-rule (sos-collapse! sos n)
(begin
(set! sos (sos-collapse sos n))
sos))
(define (split-list head? combine . ls)
(define sos (make-sos 2))
(let next ((ls ls))
(if (null? (car ls))
(sos->list sos)
(let ((els (map car ls)))
(when (apply head? els)
(sos-collapse! sos 1))
(sos-push! sos (apply combine els))
(next (map cdr ls))))))