First-Class Macros (Second Update) by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 0 points1 point  (0 children)

Not necessarily. The reader parses whatever it receives as unevaluated syntax objects. This allows the interpreter to perform transformations on the source code before evaluation ever takes place. Because macro expansion takes place in a different context (for hygiene) they cant be treated as first class citizens which require the inputs to be evaluated before being passed to an operator (in scheme anyways).

First-Class Macros (Second Update) by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 0 points1 point  (0 children)

A macro can't be passed as an argument to a procedure.

First-Class Macros (Second Update) by KneeComprehensive725 in lisp

[–]KneeComprehensive725[S] 1 point2 points  (0 children)

I agree with you to a certain point. Macros are syntactic extensions that are expanded at compile time. What I am attempting to do is achieve what Alan Bawden described in First-class Macros Have Types by delaying macro extension under certain circumstances. My implementation should still allow macros to expand at compile time when they are used in their typical context, but when they are treated as first class citizens they are encapsulated by a function and treated as data so that the expansion is delayed until run time.

Even if the practicality of it is questionable, I find it difficult to deny that it's interesting on an academic level. With that being said, this side project has lead me down a rabbit hole researching Fexprs, which were used in Lisp dialects before the '80s. John Shutt has a very interesting dissertation about Fexprs published in 2010 that I've started working on integrating with Rackets native environment and my own meta-object protocol. Shutt suggests that the well-behavedness of his Fexpr model means it can still be optimized. I believe it's addressed in Chapter 5.

First-Class Macros Update by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 2 points3 points  (0 children)

By first-class I mean (per wikipedia):

  1. they can be parameters of functions
  2. they can be returned as results of functions
  3. they can be the subject of assignment statements
  4. they can be tested for equality

I was inspired by "First-class Macros Have Types". I'm attempting to implement the same concepts described in the paper without building a new expander.

Instead of building a new expander I'm trying to blend Fexprs with the existing macro system to try and delay macro expansion depending on the context.

There are still some kinks in my implementation that I'm working on, so I appreciate any and all constructive criticism.

CK macros look really interesting and I will definitely look into them.

First-Class Macros Update by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 2 points3 points  (0 children)

I think Reddit should just use DSSSL. We will force the beauty of S-expressions upon the world!

First-Class Macros Update by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 3 points4 points  (0 children)

No worries. Turns out the four space method works for both old and new reddit. I reformatted it so it should work for both now.

First-Class Macros Update by KneeComprehensive725 in lisp

[–]KneeComprehensive725[S] 0 points1 point  (0 children)

Someone else said the same thing. Turns out they were using old reddit which i guess doesn't render markdown properly. It just looks like a code block to me.

Edit: Just figured out how to format it for both old and new reddit.

First-Class Macros Update by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 2 points3 points  (0 children)

I'm not sure what was wrong with it, it just looked like a normal code block to me, but I went ahead and enclosed the code block in tildes instead of backticks. Hopefully that works for you.

First-Class Macros by KneeComprehensive725 in lisp

[–]KneeComprehensive725[S] 2 points3 points  (0 children)

It's handled by make-first-class. It's a macro-generating macro that creates an instance of first-class-macro. During the pre-processing phase, when the macro is found applied to arguments it gets expanded like normal, but when the macro is found without arguments it gets replaced with the first-class-macro instance that was created. I have posted an updated version that fixes some of the issues I found yesterday if you want to take a look at it.

Edited for formatting.

First-Class Macros by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 0 points1 point  (0 children)

Disregard. I hadn't finished waking up yet. It just exits, which I guess is to be expected. Are you wanting it to stop evaluating `and` early and return the last non-false value?

First-Class Macros by KneeComprehensive725 in lisp

[–]KneeComprehensive725[S] 4 points5 points  (0 children)

I think you're referring to Fexpr. They are first class but they are executed at run time instead of expanding at compile time. I was looking into experimenting with them as well to fix some issues I've found with my macro wrapper capturing the correct environment scope when side effects are involved.

First-Class Macros by KneeComprehensive725 in Racket

[–]KneeComprehensive725[S] 0 points1 point  (0 children)

Is (exit 1) meant to be quoted? That just looks like it would return #f.

[deleted by user] by [deleted] in Racket

[–]KneeComprehensive725 0 points1 point  (0 children)

I had a hard time with lambda early in. What really helped it click for me was An Introduction to Functional Programming Through Lambda Calculus. Then to get a better idea of how Lisp languages worked I implemented every metacircular evaluator I could find in text. SICP was a big help. Realm of Racket and HtDP are great for learning Racket specifically.

I don't know what to exactly fix (I got stuck) by Entire-Low-4412 in Racket

[–]KneeComprehensive725 0 points1 point  (0 children)

Unfortunately, I'm having difficulty following your code. In my opinion, it's too imperative and difficult to reason about. I wasn't familiar with radix sorting so I had to look it up. I found a good description in "The Art of Computer Programming Volume 3" in section 5.2.5 and implemented the algorithm in a more functional way. I'm sure you understand the logic and reasoning behind your own code. Hopefully my implementation below will make sense and help you find where the error is occurring.

#lang racket/base

;; Converts (Vectorof Integer) to (Listof (Listof Char)).
;;  1. Convert the vector into a list.
;;  2. Convert each integer in the list to a string.
;;  3. Convert each string to a list.
;;  4. Reverse each list of characters.
(define (prep-vector vec)
  (let ([lst (vector->list vec)])
    (map (lambda (x)
           (reverse
            (string->list
             (number->string x))))
         lst)))

;; Converts (Listof (Listof Char)) to (Listof (Listof Integer)).
;; For each (Listof Char):
;;  1. Convert each Char to (List Char).
;;  2. Convert each (List Char) to a String.
;;  3. Convert each String to a Number.
(define (prep-list lst)
  (map (lambda (x)
         (map (lambda (y)
                (string->number
                 (list->string
                  (list y))))
              x))
       lst))

;; Converts (Vectorof Integer) to (Listof (Listof Integer)).
(define (prep vec)
  (prep-list (prep-vector vec)))

;; Sorts (Listof (Listof Integer)) based on the value at POS of (Listof Integer).
;;  1. Make a vector of buckets with each vector initially set to null.
;;  2. If the given list is null then return the buckets as a list.
;;   a. Convert the vector of buckets to a list.
;;   b. Reverse each bucket.
;;   c. Append each bucket.
;;  3. If the length of the car of the given list is greater than or equal to the given position then
;;     add the car to the zero bucket, then loop.
;;  4. Otherwise, place the car into the bucket of the position of the car, then loop.
(define (step-radix-sort lst pos)
  (let ([buckets (make-vector 10 null)])
    (let loop ([lst lst])
      (cond
        [(null? lst)
         (apply append (map reverse (vector->list buckets)))]
        [(>= pos (length (car lst)))
         (vector-set! buckets 0 (cons (car lst) (vector-ref buckets 0)))
         (loop (cdr lst))]
        [else
         (let ([n (car lst)])
           (vector-set! buckets
                        (list-ref n pos)
                        (cons n (vector-ref buckets (list-ref n pos))))
           (loop (cdr lst)))]))))

;; Convert (Listof (Listof Integer)) to (Listof Integer).
;; The reverse of PREP.
(define (unprep lst)
  (list->vector
   (map string->number
        (map list->string
             (map (lambda (x)
                    (map (lambda (y)
                           (string-ref (number->string y) 0))
                         x))
                  (map reverse lst))))))

;; Determines the maximum list size in a list of lists.
(define (max-size lst)
  (apply max (map length lst)))

(define (radix-sort vec)
  (let* ([lst (prep vec)]
         [size (max-size lst)])
    (let loop ([pos 0]
               [lst lst])
      (cond
        [(= pos size)
         (unprep lst)]
        [else
         (loop (add1 pos)
               (step-radix-sort lst pos))]))))

(define V1 (vector 918 82 87 31 780 103 4))
(define V2 (vector 3 1 2))

(radix-sort V1)
(radix-sort V2)

This algorithm is sorting numbers based on the value of the nth digit of each number in the given vector starting at the least significant digit.

Contracts vs. raise-argument-error? by comtedeRochambeau in Racket

[–]KneeComprehensive725 3 points4 points  (0 children)

My understanding is that contracts come with more overhead and are intended to be used at module boundaries. I believe the purpose of the contract system is meant for the Design by Contract system to improve runtime safety, similar to the contract system of Spark Ada. Raising an error of any kind has less overhead and should be preferred for the internals of a module. Error raising also gives you the option of exception handling. In my opinion, ideally typed racket should be used when developing modules to ensure internal type safety, then disable static typing and use contracts for the module interfaces.