I wrote some fairly simple code to demonstrate use of StructMaps and
Refs. It's 80 lines including comments. I'd appreciate it if someone
could look it over and let me know if I've done anything that isn't
very idiomatic.

The program models sports teams and players. The main functionality is
the ability to trade sets of players between teams. Both teams and
players are held by Refs. Players have a reference to their team.
Teams have references to their players.

The output from the code follows:

Before trade:
Oilers roster:
  Wayne Gretzky
  Mike Krushelnyski
  Marty McSorley
Kings roster:
  Jimmy Carson
  Martin Gelinas

After trade:
Oilers roster:
  Martin Gelinas
  Jimmy Carson
Kings roster:
  Wayne Gretzky
  Mike Krushelnyski
  Marty McSorley

Here's the code:

; A player knows his team, if any.
(defstruct player-struct :name :team-ref)

; A team knows its players.
(defstruct team-struct :name :player-refs)

; Makes a new Ref to a player-struct that isn't on any team.
(defn make-player [name]
  (ref (struct player-struct name)))

; Makes a new Ref to a team-struct that contains no players.
(defn make-team [name]
  (ref (struct team-struct name [])))

(defn assign-player-to-team [player-ref new-team-ref]
  (dosync
    ; If the player has a former team, remove them from it.
    (if-let [old-team-ref (@player-ref :team-ref)]
      (let [old-player-refs (@old-team-ref :player-refs)
            new-player-refs (remove #(= % player-ref) old-player-refs)]
        (alter old-team-ref assoc :player-refs new-player-refs)))

    ; Add the player to their new team.
    (let [old-player-refs (@new-team-ref :player-refs)
          new-player-refs (conj old-player-refs player-ref)]
      (alter player-ref assoc :team-ref new-team-ref)
      (alter new-team-ref assoc :player-refs new-player-refs))))

; Returns a string describing a given player.
(defn player-to-string [player-ref]
  (dosync
    (str (@player-ref :name) " plays for "
      (if-let [team-ref (@player-ref :team-ref)]
        (str "the " (@team-ref :name))
        "nobody")
      ".")))

; Returns a string describing a given team.
(defn team-to-string [team-ref]
  (dosync
    (apply str
      (@team-ref :name) " roster:"
      (map
        (fn [player-ref] (str "\n  " (@player-ref :name)))
        (@team-ref :player-refs)))))

; players1 and players2 are collections of Refs to player StructMaps.
; Neither can be empty.
; All players in a collection must be on the same team.
(defn trade [players1 players2]
  (dosync
    (let [team1 ((first players1) :team-ref)
          team2 ((first players2) :team-ref)]
      (doseq [p players1]
        (assign-player-to-team p team2))
      (doseq [p players2]
        (assign-player-to-team p team1)))))

(let [oilers (make-team "Oilers")
      kings (make-team "Kings")
      p1 (make-player "Wayne Gretzky")
      p2 (make-player "Mike Krushelnyski")
      p3 (make-player "Marty McSorley")
      p4 (make-player "Jimmy Carson")
      p5 (make-player "Martin Gelinas")]

  (doseq [p [p1 p2 p3]]
    (assign-player-to-team p oilers))
  (doseq [p [p4 p5]]
    (assign-player-to-team p kings))

  (println "Before trade:")
  (println (team-to-string oilers))
  (println (team-to-string kings))

  (trade [p1 p2 p3] [p4 p5])

  (println "\nAfter trade:")
  (println (team-to-string oilers))
  (println (team-to-string kings)))

-- 
R. Mark Volkmann
Object Computing, Inc.

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to