#lang typed/scheme #:optimize
(provide clist empty? head tail
CatenableList append empty filter remove
(rename-out [clist->list ->list]
[clist list] [kons cons]
[head first] [tail rest]
[kons-rear cons-to-end] [cmap map]
[cfoldl foldl] [cfoldr foldr]))
(require scheme/promise)
(require (prefix-in rtq: "bootstrapedqueue.ss"))
(define-struct: EmptyList ())
(define-struct: (A) List ([elem : A]
[ques : (rtq:Queue (Promise (List A)))]))
(define-type-alias CatenableList (All (A) (U (List A) EmptyList)))
(define empty (make-EmptyList))
(: empty? : (All (A) ((CatenableList A) -> Boolean)))
(define (empty? cat)
(EmptyList? cat))
(: link : (All (A) ((List A) (Promise (List A)) -> (List A))))
(define (link lst cat)
(make-List (List-elem lst) (rtq:enqueue cat (List-ques lst))))
(: link-all : (All (A) ((rtq:Queue (Promise (List A))) -> (List A))))
(define (link-all rtq)
(let ([hd (force (rtq:head rtq))]
[tl (rtq:tail rtq)])
(if (rtq:empty? tl)
hd
(link hd (delay (link-all tl))))))
(: append-inner : (All (A) ((CatenableList A) (CatenableList A) -> (CatenableList A))))
(define (append-inner cat1 cat2)
(cond
[(EmptyList? cat1) cat2]
[(EmptyList? cat2) cat1]
[else (link cat1 (delay cat2))]))
(: append : (All (A) ((CatenableList A) * -> (CatenableList A))))
(define (append . cats)
(if (null? cats)
empty
(append-inner (car cats) (apply append (cdr cats)))))
(: kons : (All (A) (A (CatenableList A) -> (CatenableList A))))
(define (kons elem cat)
(append (make-List elem rtq:empty) cat))
(: kons-rear : (All (A) (A (CatenableList A) -> (CatenableList A))))
(define (kons-rear elem cat)
(append cat (make-List elem rtq:empty)))
(: head : (All (A) ((CatenableList A) -> A)))
(define (head cat)
(if (EmptyList? cat)
(error 'first "given list is empty")
(List-elem cat)))
(: tail : (All (A) ((CatenableList A) -> (CatenableList A))))
(define (tail cat)
(if (EmptyList? cat)
(error 'rest "given list is empty")
(tail-helper cat)))
(: tail-helper : (All (A) ((List A) -> (CatenableList A))))
(define (tail-helper cat)
(let ([ques (List-ques cat)])
(if (rtq:empty? ques)
empty
(link-all ques))))
(: cmap : (All (A C B ...) ((A B ... B -> C) (CatenableList A)
(CatenableList B) ... B ->
(CatenableList C))))
(define (cmap func lst . lsts)
(if (or (empty? lst) (ormap empty? lsts))
empty
(kons (apply func (head lst) (map head lsts))
(apply cmap func (tail lst) (map tail lsts)))))
(: cfoldl :
(All (C A B ...) ((C A B ... B -> C) C (CatenableList A)
(CatenableList B) ... B -> C)))
(define (cfoldl func base fst . rst)
(if (or (empty? fst) (ormap empty? rst))
base
(apply cfoldl
func
(apply func base (head fst) (map head rst))
(tail fst)
(map tail rst))))
(: cfoldr :
(All (C A B ...) ((C A B ... B -> C) C (CatenableList A)
(CatenableList B) ... B -> C)))
(define (cfoldr func base fst . rst)
(if (or (empty? fst) (ormap empty? rst))
base
(apply func (apply cfoldr
func
base
(tail fst)
(map tail rst)) (head fst) (map head rst))))
(: filter : (All (A) ((A -> Boolean) (CatenableList A) -> (CatenableList A))))
(define (filter func que)
(: inner : (All (A) ((A -> Boolean) (CatenableList A) (CatenableList A) -> (CatenableList A))))
(define (inner func que accum)
(if (empty? que)
accum
(let ([head (head que)]
[tail (tail que)])
(if (func head)
(inner func tail (kons head accum))
(inner func tail accum)))))
(inner func que empty))
(: remove : (All (A) ((A -> Boolean) (CatenableList A) -> (CatenableList A))))
(define (remove func que)
(: inner : (All (A) ((A -> Boolean) (CatenableList A) (CatenableList A) -> (CatenableList A))))
(define (inner func que accum)
(if (empty? que)
accum
(let ([head (head que)]
[tail (tail que)])
(if (func head)
(inner func tail accum)
(inner func tail (kons head accum))))))
(inner func que empty))
(: clist : (All (A) (A * -> (CatenableList A))))
(define (clist . lst)
(foldr (inst kons A) empty lst))
(: clist->list : (All (A) ((CatenableList A) -> (Listof A))))
(define (clist->list cat)
(if (EmptyList? cat)
null
(cons (head cat) (clist->list (tail cat)))))