main.scm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. ;; (define flat?
  2. ;; (λ (lst)
  3. ;; (cond
  4. ;; [(null? lst) #t]
  5. ;; [(pair? (car lst)) #f]
  6. ;; [(null? (car lst)) #f] ; needed because (pair? '()) is #f
  7. ;; [else (flat? (cdr lst))])))
  8. (library (prefix-to-postfix)
  9. (export arity-lookup-table
  10. known-operation?
  11. look-for-next-list
  12. adapt-arity
  13. prefix->postfix)
  14. (import
  15. (except (rnrs base) let-values map)
  16. (only (guile)
  17. lambda* λ
  18. simple-format
  19. current-output-port)
  20. (srfi srfi-69) ; hash-table
  21. (srfi srfi-1) ; lists
  22. )
  23. (define arity-lookup-table
  24. (alist->hash-table
  25. '((+ . 3)
  26. (- . 2)
  27. (* . 2)
  28. (/ . 2))))
  29. (define known-operation?
  30. (λ (op)
  31. (hash-table-exists? arity-lookup-table op)))
  32. (define look-for-next-list
  33. (λ (lst callback)
  34. "LST is the list which is looked at element by element, to find the
  35. next sublist. CALLBACK is the function called for the next found
  36. sublist."
  37. (cond
  38. [(null? lst) '()]
  39. [(null? (car lst))
  40. (cons '() (look-for-next-list (cdr lst) callback))]
  41. [(pair? (car lst))
  42. (cons (callback (car lst))
  43. (look-for-next-list (cdr lst) callback))]
  44. [else
  45. (cons (car lst)
  46. (look-for-next-list (cdr lst) callback))])))
  47. (define adapt-arity
  48. (λ (lst)
  49. ;; (+ 1 2 3 4) --> (+ 1 (+ 2 3 4)) --> (+ 1 (+ 2 (+ 3 4)))
  50. (let ([operation (car lst)])
  51. (cond
  52. ;; base case empty list
  53. [(null? lst) '()]
  54. [(known-operation? operation)
  55. (let ([wanted-arity (hash-table-ref arity-lookup-table (car lst))])
  56. ;; check, if we have sufficient arguments for another "split"
  57. (cond
  58. [(<= (length lst) wanted-arity)
  59. (cons (car lst)
  60. ;; But there could still be other operations in the
  61. ;; remaining too few arguments, so we need to check,
  62. ;; whether they are operations and then adapt their
  63. ;; arity as well.
  64. (look-for-next-list (cdr lst) adapt-arity))]
  65. [else
  66. ;; make a proper list - append takes 2 proper lists as input
  67. (append
  68. ;; The list still contains the operation. Take 1 less
  69. ;; argument than operation arity to keep 1 argument for the
  70. ;; new call to the operation.
  71. (take lst wanted-arity)
  72. ;; Build the last argument, which is a new call to the
  73. ;; operation with the remaining arguments. However, those
  74. ;; could be too many, so do a recursive call.
  75. (list
  76. (adapt-arity
  77. (cons operation
  78. (drop lst wanted-arity)))))]))]
  79. ;; Ignore unrecognized operations. We do not have arity
  80. ;; information for them, so just leave them as they are.
  81. [else lst]))))
  82. (define prefix->postfix
  83. (λ (lst)
  84. (cond
  85. [(null? lst) '()]
  86. [else
  87. (append
  88. ;; "Look for the next sublist and call me back, when you find
  89. ;; it!"
  90. (look-for-next-list (cdr lst)
  91. prefix->postfix)
  92. (list (car lst)))])))
  93. (define (flatten lst)
  94. (let loop ([remaining-lst lst]
  95. [acc '()])
  96. (cond
  97. [(null? remaining-lst) acc]
  98. [(pair? remaining-lst)
  99. (loop (car remaining-lst)
  100. (loop (cdr remaining-lst)
  101. acc))]
  102. [else
  103. (cons remaining-lst acc)])))
  104. (simple-format (current-output-port)
  105. "adapted arity: ~a\n"
  106. (adapt-arity '(+ 1 2 (- 3 4) 5)))
  107. (simple-format (current-output-port)
  108. "postfix: ~a\n"
  109. (prefix->postfix (adapt-arity '(+ 1 2 (- 3 4) 5))))
  110. (simple-format (current-output-port)
  111. "flattened: ~a\n"
  112. (flatten (prefix->postfix (adapt-arity '(+ 1 2 (- 3 4) 5))))))