Exercism: clean and format a phone number in Clojure

Problem statement

Phone Number

Write a program that cleans up user-entered phone numbers so that they can be sent SMS messages.

The rules are as follows:

1. If the phone number is less than 10 digits assume that it is bad number
2. If the phone number is 10 digits assume that it is good
3. If the phone number is 11 digits and the first number is 1, trim the 1 and use the last 10 digits
4. If the phone number is 11 digits and the first number is not 1, then it is a bad number
5. If the phone number is more than 11 digits assume that it is a bad number

Proposed Solution

(ns phone-number
(:require [clojure.string :as str]))

(def non-digits #"\D")
(def parts #"^1?(...)(...)(....)$") (def error-val ["000" "000" "0000"]) (defn- digits [n] (str/replace n non-digits "")) (defn- trio-h [n] (if-let [ps (re-find parts n)] (rest ps) error-val)) (defn- trio [n] (-> n digits trio-h)) (defn number [n] (-> n trio str/join)) (defn area-code [n] (-> n trio first)) (defn pretty-print [n] (let [[area exch line] (trio n)] (format "(%s) %s-%s" area exch line)))  Questions 1. In pretty-print is the use of let necessary? Or is there a way in Clojure to splice in the result of (trio n) in-place for the call to format? The result of (trio n) is a vector containing three strings and the format call is expecting three %s strings to stick into the format string. If there is an alternative to my use of let, which is preferred? 2. Are the names ok? Do they read like Clojure names? Is there a convention for naming a one-off helper function? 3. Is it better to keep trio-h a separate helper function, or let it inside the using function, or would you just use the code in-place instead? 4. :refering clojure.string/replace triggers a warning (since it collides with clojure.core/replace) so I :refered all of clojure.string. Is there a way to :refer as to avoid the collision? 5. Do you have other improvements you could suggest? Tests 1 Answer I'm still learning clojure, but I'll contribute what I can. 1. I don't know if it is prefered or not, but if you wanted to get rid of the let, you could do something like (apply (partial format "(%s) %s-%s") trio) or (apply format (concat '["(%s) %s-%s"] trio)) instead. 2. Naming seems ok. 3. No comment. 4. I don't know. 5. Your regex for parts is suboptimal. '.' will pick up any character, but you really only want digits. Something like "^1?(\d{3})(\d{3})(\d{4})$" would be more accurate.
• For 1, even simpler would be (apply format "(%s) %s-%s" (trio n)), but it might be better to just use a let for clarity's sake. – Sam Estep Jun 5 '16 at 14:37