Hi,

I just wanted to point out that the docs (http://clojure.org/
special_forms#let ) say that destructuring uses nthrest, when it uses
nthnext in the sources; probably leftover from before the lazier
sequences changes.


Out of curiosity, does it make sense to have fully lazy
destructuring?  It doesn't seem like it would be easy to reason about
or even very useful, but I ran into it when translating the Haskell
example below (Haskell seems like a nice way to learn general lazy and
pure concepts useful in Clojure programming!).

As expressed (a direct translation of the Haskell example), the code
needs to be fully lazy so I don't see how destructuring could be used
as it stands -- but I would love to know if I'm overlooking something.

The motivating Haskell example follows the Clojure code.

Thanks for the excellent language!
-Sudish

PS: http://thread.gmane.org/gmane.comp.lang.haskell.cafe/59054 has a
discussion of the Haskell's lazy pattern matching and is where I
encountered the example.

;;; Clojure implementation of lazily recursive client/server from
;;; Haskell extract quoted below.

(def *debug* false)

;; Client request and server response handlers
(def first-req 0)
(defn next-req [n]
  (when *debug* (println (format "(next-req %d)" n)))
  (dec n))

(defn process [n]
  (when *debug* (println (format "(process %d)" n)))
  (+ n 3))

;; Client and server
(defn client [init resps]
  (cons init
        (lazy-seq (client (next-req (first resps)) (rest resps)))))

(defn server [reqs]
  (cons (process (first reqs))
        (lazy-seq (server (rest reqs)))))

;; Requests and responses as (lazy) lists
(declare responses)

(def requests  (lazy-seq (client first-req responses)))
(def responses (lazy-seq (server requests)))

;; The original Haskell code

;; 4.4  Lazy Patterns

;; There is one other kind of pattern allowed in Haskell. It is called
;; a lazy pattern, and has the form ~pat. Lazy patterns are
;; irrefutable: matching a value v against ~pat always succeeds
;; regardless of pat. Operationally speaking, if an identifier in pat
;; is later "used" on the right-hand-side, it will be bound to that
;; portion of the value that would result if v were to successfully
;; match pat, and _|_ otherwise.

;; Lazy patterns are useful in contexts where infinite data structures
;; are being defined recursively. For example, infinite lists are an
;; excellent vehicle for writing simulation programs, and in this
;; context the infinite lists are often called streams. Consider the
;; simple case of simulating the interactions between a server process
;; server and a client process client, where client sends a sequence
;; of requests to server, and server replies to each request with some
;; kind of response. This situation is shown pictorially in Figure
;; 2. (Note that client also takes an initial message as argument.)

;; Figure 2

;; Using streams to simulate the message sequences, the Haskell code
;; corresponding to this diagram is:

;;   reqs                     = client init resps
;;   resps                    = server reqs

;; These recursive equations are a direct lexical transliteration of
;; the diagram.

;; Let us further assume that the structure of the server and client
;; look something like this:

;;   client init (resp:resps) = init : client (next resp) resps
;;   server      (req:reqs)   = process req : server reqs

;; where we assume that next is a function that, given a response from
;; the server, determines the next request, and process is a function
;; that processes a request from the client, returning an appropriate
;; response.

;; Unfortunately, this program has a serious problem: it will not
;; produce any output! The problem is that client, as used in the
;; recursive setting of reqs and resps, attempts a match on the
;; response list before it has submitted its first request! In other
;; words, the pattern matching is being done "too early." One way to
;; fix this is to redefine client as follows:

;;   client init resps         = init : client (next (head resps))
(tail resps)

;; Although workable, this solution does not read as well as that
;; given earlier. A better solution is to use a lazy pattern:

;;   client init ~(resp:resps) = init : client (next resp) resps

;; Because lazy patterns are irrefutable, the match will immediately
;; succeed, allowing the initial request to be "submitted", in turn
;; allowing the first response to be generated; the engine is now
;; "primed", and the recursion takes care of the rest.


--~--~---------~--~----~------------~-------~--~----~
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