Skip to content

Instantly share code, notes, and snippets.

@lispm
Last active March 5, 2017 18:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lispm/63a50e07de78a59bdf3e053ebe7abb67 to your computer and use it in GitHub Desktop.
Save lispm/63a50e07de78a59bdf3e053ebe7abb67 to your computer and use it in GitHub Desktop.
; https://z0ltan.wordpress.com/2017/02/24/a-piglatin-translator-in-common-lisp-and-contrasting-it-with-the-racket-version/
#|
(defpackage #:piglatin
(:use :cl :cl-user))
; using CL-USER makes no sense, it usually does not export anything.
(in-package #:piglatin)
(defun translate (sentence)
(let ((*readtable* (copy-readtable nil)))
(setf (readtable-case *readtable*) :preserve)
(mapcar #'make-symbol
(mapcar #'english-to-piglatin
(mapcar #'string-to-list
(mapcar #'symbol-name sentence))))))
; Why use a readtable, when you don't read? The readtable has no effect at all.
; The function is called with a list of symbols. Thus they are already read.
; Nested mapcars? Not really.
; ---
; In plain Lisp, instead of:
(mapcar #'make-symbol
(mapcar #'english-to-piglatin
(mapcar #'string-to-list
(mapcar #'symbol-name sentence))))
; use:
(mapcar (lambda (symbol)
(make-symbol
(english-to-piglatin
(string-to-list
(symbol-name symbol)))))
sentence)
; or:
(loop for symbol in sentence
collect (make-symbol (english-to-piglatin (string-to-list (symbol-name symbol)))))
; ---
(defun english-to-piglatin (word)
(if (starts-vowel-p word)
(word-to-vowel-rule word)
(word-to-consonant-rule word)))
(defun starts-vowel-p (word)
(member (char-downcase (car word)) '(#\a #\e #\i #\o #\u #\y)))
; A word as a list? Use strings.
(defun word-to-vowel-rule (word)
(coerce (append word '(#\w #\a #\y)) 'string))
; A word as a list? Use strings.
(defun word-to-consonant-rule (word)
(let ((was-capital-p (upper-case-p (car word))))
(labels ((f (word)
(if (starts-vowel-p word)
(cond (was-capital-p (string-capitalize
(coerce (append word '(#\a #\y)) 'string)))
(t (coerce (append word '(#\a #\y)) 'string)))
(f (append (cdr word) (list (char-downcase (car word))))))))
(f word))))
; A word as a list? Use strings.
; Get rid of the recursion, too.
(defun string-to-list (word)
(coerce word 'list))
; A word as a list? Use strings.
|#
; basic rules
; * don't convert strings to lists
; * readtables have no effect on already read symbols
; * create more useful basic functions
; * don't use nested mapcars
; * basic functions should not take one data structure and return another, until necessary
; if it gets a string, return a string.
; if it gets a list, it should return a list
; if it gets a symbol, it should return a symbol
;
; optional
; * replace symbols with strings
; basic meta rule
; * if the Common Lisp code looks quirky, then it is possibly non-idiomatic
; a more idiomatic version
(defun vowel-p (char)
(find char "aeiouy" :test #'char-equal))
(defun starts-with-vowel-p (word)
(vowel-p (aref word 0)))
(defun capital-p (word)
(upper-case-p (aref word 0)))
(defun word-vowel-rule (word)
(concatenate 'string word "way"))
(defun word-consonant-rule (word)
(let* ((pos (or (position-if #'vowel-p word) (length word)))
(new-word (concatenate 'string (subseq word pos) (subseq word 0 pos) "ay")))
(if (capital-p word)
(string-capitalize new-word)
new-word)))
(defun english-to-piglatin (word)
(if (starts-with-vowel-p word)
(word-vowel-rule word)
(word-consonant-rule word)))
(defun translate (sentence)
(loop for word in sentence
collect (intern (english-to-piglatin (string word)))))
; (translate '(|Hello| |world| |we| |meet| "again"))
; -> (|Ellohay| |orldway| |eway| |eetmay| |againway|)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment