
Folks, I'm curious about how the following bit of Lisp code would translate to Haskell. This is my implementation of Lisp RPC and it basically sends strings around, printed "readably" and read on the other end by the Lisp reader. If I have a list '(1 2) it prints as "(1 2)" and becomes '(1 2) again when read on the other end. I'm wrote a couple of macros to make the job of defining the RPC easier. def-remote-class defines the main (server) class as well as the client (proxy) class. def-remote-method creates the server method as well as a proxy method that sends data over and possibly waits for results and returns them (depending on the :async or :sync qualifier). My Lisp RPC code runs on top of UDP, looks good and works well. I have a soft spot for Haskell in my heart, though, so I wonder how I would go about implementing the same architecture in Haskell. This is an example from my test harness: (define-test remote-basic (def-remote-class remote (server) ()) (def-remote-method sum :sync ((self remote) (a fixnum) (b integer)) (declare (ignorable ip port)) (+ a b seqnum)) (let* ((port (+ 1000 (random 50000))) (server (make-instance 'remote :port port)) (client (make-instance 'remote-proxy :host (host-address) :port port))) (assert-equal '(6) (sum client 1 2 :seqnum 3)) (stop server) (stop client) )) I think I can send Haskell code over the wire to be read on the other side just like I do with Lisp. The part that baffles me is being able to provide an interface that lets one easily define remote classes and methods. I totally hate Template Haskell because I find it incomprehensible and I'm not going to compare it to Lisp macros. Is there a way to do it without TH? Also, it seems to me that the only way to deal with variable numbers of differently typed arguments is to use the HList approach which is quite heavy machinery, IMO. Any suggestions? Thanks, Joel P.S. The Haskell Cafe has been a bit quiet lately so I do mean to stir it up some. I think this example shows the advantage of dynamically-typed languages. I'm also genuinely interested in possible Haskell solutions. -- http://wagerlabs.com/

On 5/25/06, Joel Reymont
This is an example from my test harness:
(define-test remote-basic (def-remote-class remote (server) ()) (def-remote-method sum :sync ((self remote) (a fixnum) (b integer)) (declare (ignorable ip port)) (+ a b seqnum)) (let* ((port (+ 1000 (random 50000))) (server (make-instance 'remote :port port)) (client (make-instance 'remote-proxy :host (host-address) :port port))) (assert-equal '(6) (sum client 1 2 :seqnum 3)) (stop server) (stop client) ))
I won't comment on the difference between haskell and lisp (both languages I respect), but I will say that you should add a macro or high order function (depneding on lisp vs. haskell) that is something like "(with-client (c args-list) body)", that way you can simplify the creation/cleanup of clients. Same idea as with-open-file. You can do the same with server. As for your actual question, there is a deriving(Read), but I don't remember what extensions are needed. Jason

On May 25, 2006, at 2:25 PM, Jason Dagit wrote:
On 5/25/06, Joel Reymont
wrote: This is an example from my test harness:
(define-test remote-basic (def-remote-class remote (server) ()) (def-remote-method sum :sync ((self remote) (a fixnum) (b integer)) (declare (ignorable ip port)) (+ a b seqnum)) (let* ((port (+ 1000 (random 50000))) (server (make-instance 'remote :port port)) (client (make-instance 'remote-proxy :host (host-address) :port port))) (assert-equal '(6) (sum client 1 2 :seqnum 3)) (stop server) (stop client) ))
I won't comment on the difference between haskell and lisp (both languages I respect), but I will say that you should add a macro or high order function (depneding on lisp vs. haskell) that is something like "(with-client (c args-list) body)", that way you can simplify the creation/cleanup of clients. Same idea as with-open-file. You can do the same with server.
As for your actual question, there is a deriving(Read), but I don't remember what extensions are needed.
None. 'deriving' for Read and Show are both Haskell 98. It won't work for functions though. Haskell functions, unlike in lisp/scheme, are "opaque". If all you want to do is send data around, then you can surely use Read/Show, or some of the more efficient workalikes from DrIFT (http://repetae.net/~john/computer/haskell/DrIFT/). Joel Raymont:
I think I can send Haskell code over the wire to be read on the other side just like I do with Lisp. The part that baffles me is being able to provide an interface that lets one easily define remote classes and methods.
I totally hate Template Haskell because I find it incomprehensible and I'm not going to compare it to Lisp macros. Is there a way to do it without TH?
If you want to deliver source code to be executed elsewhere, you can use hs-plugins or the GHC API (in GHC HEAD branch). Check out the lambdabot for inspiration (http://haskell.org/haskellwiki/ Lambdabot). Or you could maybe do something interesting here with YHC bytecode. If you instead want to go the XML-RPC route there's HaXR (http://www.haskell.org/haxr/). I can understand the sentiment about TH, but it's probably the only way to get a similar interface to the lisp one, short of preprocessing/code generation. Beyond that, I'd say there are a few too many free variables in the problem description. What would be the design goals and non-goals for such an RPC mechanism? What problems prompted the original lisp implementation? What about fault tolerance, reliability, security? etc. Rob Dockins Speak softly and drive a Sherman tank. Laugh hard; it's a long way to the bank. -- TMBG

On May 25, 2006, at 8:34 PM, Robert Dockins wrote:
If you want to deliver source code to be executed elsewhere, you can use hs-plugins or the GHC API (in GHC HEAD branch).
hs-plugins is too heavy since it runs ghc. I don't need to deliver any type of source code, just a function call and its arguments.
Beyond that, I'd say there are a few too many free variables in the problem description. What would be the design goals and non-goals for such an RPC mechanism? What problems prompted the original lisp implementation? What about fault tolerance, reliability, security? etc.
The design goals is just to have a simple RPC mechanism with synchronous (request/reply) and asynchronous (send a message) facilities. The problem I'm trying to address is running a whole bunch of software servers for scalability. Reliability and fault tolerance are taken care of by having redundant servers and security is not addressed at all. It seems that I can do something similar in Haskell by having heterogenous lists of arguments and making each RPC call into a type class but then I would have to implement the functions myself. I wish Glasgow Distributed Haskell (GdH) was more active and visible! Does anybody know its current state? Shouldn't it be an extension to GHC just like Concurrent Haskell is? Joel -- http://wagerlabs.com/

On Fri, May 26, 2006 at 09:20:25AM +0100, Joel Reymont wrote:
On May 25, 2006, at 8:34 PM, Robert Dockins wrote:
If you want to deliver source code to be executed elsewhere, you can use hs-plugins or the GHC API (in GHC HEAD branch).
hs-plugins is too heavy since it runs ghc. I don't need to deliver any type of source code, just a function call and its arguments.
Is there a discrete set of functions you want to be able to call, then? If so, why not just define a data type: data MyRPC = LengthIntList [Int] | HeadList [Int] | ... deriving ( Show, Read ) Then you just implement a runfunction (LengthIntList xs) = length xs runfunction (HeadList (x:_) = x ... No trickiness required, all you need is one datatype enumerating the functions you want to be able to call, and a dispatch function. At the cost (over lisp) of having to write these enumerations, you gain the safety of knowing that only that list of functions can be called, and that they all have the appropriate return type (or maybe they'll all return IO (), I don't know). -- David Roundy http://www.darcs.net

Hello Joel,
I wish Glasgow Distributed Haskell (GdH) was more active and visible!
are you've seen http://www.informatik.uni-kiel.de/~fhu/PUBLICATIONS/1999/ifl.ps.gz ? afair, source code was also available -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On May 25, 2006, at 7:25 PM, Jason Dagit wrote:
I will say that you should add a macro or high order function (depneding on lisp vs. haskell) that is something like "(with-client (c args-list) body)", that way you can simplify the creation/cleanup of clients. Same idea as with-open-file. You can do the same with server.
Yes, thanks for the suggestion. This would indeed be useful. -- http://wagerlabs.com/

Given that we have no easy way to serialize thunks, the whole RPC approach just seems wrong for Haskell. RPC in general is pretty old school. REST seems to have worked better in practice (e.g. HTTP GET/POST!). For a general description of REST see http://webservices.xml.com/pub/a/ws/2002/02/06/rest.html For a summary of the REST vs RPC issue see e.g. http://www.tbray.org/ongoing/When/200x/2003/05/12/SoapAgain Note that Amazon exposed both sorts of interfaces and found the REST style interface much more popular! That being said, I am actually looking or a good Haskell SOAP client lib to talk to paypal so YMMV. -Alex- ______________________________________________________________ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com On Thu, 25 May 2006, Joel Reymont wrote:
Folks,
I'm curious about how the following bit of Lisp code would translate to Haskell. This is my implementation of Lisp RPC and it basically sends strings around, printed "readably" and read on the other end by the Lisp reader. If I have a list '(1 2) it prints as "(1 2)" and becomes '(1 2) again when read on the other end.
I'm wrote a couple of macros to make the job of defining the RPC easier. def-remote-class defines the main (server) class as well as the client (proxy) class.
def-remote-method creates the server method as well as a proxy method that sends data over and possibly waits for results and returns them (depending on the :async or :sync qualifier). My Lisp RPC code runs on top of UDP, looks good and works well. I have a soft spot for Haskell in my heart, though, so I wonder how I would go about implementing the same architecture in Haskell.
This is an example from my test harness:
(define-test remote-basic (def-remote-class remote (server) ()) (def-remote-method sum :sync ((self remote) (a fixnum) (b integer)) (declare (ignorable ip port)) (+ a b seqnum)) (let* ((port (+ 1000 (random 50000))) (server (make-instance 'remote :port port)) (client (make-instance 'remote-proxy :host (host-address) :port port))) (assert-equal '(6) (sum client 1 2 :seqnum 3)) (stop server) (stop client) ))
I think I can send Haskell code over the wire to be read on the other side just like I do with Lisp. The part that baffles me is being able to provide an interface that lets one easily define remote classes and methods.
I totally hate Template Haskell because I find it incomprehensible and I'm not going to compare it to Lisp macros. Is there a way to do it without TH?
Also, it seems to me that the only way to deal with variable numbers of differently typed arguments is to use the HList approach which is quite heavy machinery, IMO.
Any suggestions?
Thanks, Joel
P.S. The Haskell Cafe has been a bit quiet lately so I do mean to stir it up some. I think this example shows the advantage of dynamically-typed languages. I'm also genuinely interested in possible Haskell solutions.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

"S. Alexander Jacobson"
Given that we have no easy way to serialize thunks, the whole RPC approach just seems wrong for Haskell.
Tom Shackell is developing a simple bytecode reflection API to be implemented in the yhc compiler. This will allow the transmission of arbitrary function code across the network for execution on a remote machine, with the results fed back to the calling machine. e.g. encodeF :: (a->b) -> Bytecode (a->b) dynload :: Bytecode (a->b) -> (a->b) Work in progress... There are doubtless lots of security issues here, not least type safety.... Regards, Malcolm

hi
2006/5/25, Joel Reymont
[snip] Also, it seems to me that the only way to deal with variable numbers of differently typed arguments is to use the HList approach which is quite heavy machinery, IMO.
(i ve made a quick read of previous reply .. think there is not my answer :) the usual way to deal with that is just http://www.haskell.org/hawiki/ExistentialTypes. To put it simply : u encapsulate each different data type in one "unifying" wrapping type. It works as long as each wrapped type belongs to the same (haskell) class. I think that if you add a String or something to identify the wrapped data, you can manage the data part of you problem (but i dont know for moving functions). Cheers, mt

On May 25, 2006, at 11:00 AM, Joel Reymont wrote:
Folks,
I'm curious about how the following bit of Lisp code would translate to Haskell. This is my implementation of Lisp RPC and it basically sends strings around, printed "readably" and read on the other end by the Lisp reader. If I have a list '(1 2) it prints as "(1 2)" and becomes '(1 2) again when read on the other end.
I'm wrote a couple of macros to make the job of defining the RPC easier. def-remote-class defines the main (server) class as well as the client (proxy) class.
def-remote-method creates the server method as well as a proxy method that sends data over and possibly waits for results and returns them (depending on the :async or :sync qualifier). My Lisp RPC code runs on top of UDP, looks good and works well. I have a soft spot for Haskell in my heart, though, so I wonder how I would go about implementing the same architecture in Haskell.
This is an example from my test harness:
(define-test remote-basic (def-remote-class remote (server) ()) (def-remote-method sum :sync ((self remote) (a fixnum) (b integer)) (declare (ignorable ip port)) (+ a b seqnum)) (let* ((port (+ 1000 (random 50000))) (server (make-instance 'remote :port port)) (client (make-instance 'remote-proxy :host (host-address) :port port))) (assert-equal '(6) (sum client 1 2 :seqnum 3)) (stop server) (stop client) ))
I think I can send Haskell code over the wire to be read on the other side just like I do with Lisp. The part that baffles me is being able to provide an interface that lets one easily define remote classes and methods.
I totally hate Template Haskell because I find it incomprehensible and I'm not going to compare it to Lisp macros. Is there a way to do it without TH?
Also, it seems to me that the only way to deal with variable numbers of differently typed arguments is to use the HList approach which is quite heavy machinery, IMO.
Any suggestions?
Thanks, Joel
P.S. The Haskell Cafe has been a bit quiet lately so I do mean to stir it up some. I think this example shows the advantage of dynamically-typed languages. I'm also genuinely interested in possible Haskell solutions.
Hi Joel, the attached example is a simple RPC library. It uses show and read for serialization, and some type class tricks to allow functions with different arities. This is essentially the HaXR (http:// www.haskell.org/haxr/) API, but without the XML, HTTP and error reporting stuff. /Björn

Thank you Bjorn! I'll take a look but it sounds like exactly what I'm looking for! On May 30, 2006, at 2:35 AM, Bjorn Bringert wrote:
Hi Joel,
the attached example is a simple RPC library. It uses show and read for serialization, and some type class tricks to allow functions with different arities. This is essentially the HaXR (http:// www.haskell.org/haxr/) API, but without the XML, HTTP and error reporting stuff.
participants (9)
-
Bjorn Bringert
-
Bulat Ziganshin
-
David Roundy
-
Jason Dagit
-
Joel Reymont
-
Malcolm Wallace
-
minh thu
-
Robert Dockins
-
S. Alexander Jacobson