1
\$\begingroup\$

I think I'd like to learn Clojure eventually, but at the moment am having fun with Hy, a "dialect of Lisp that's embedded in Python."

(import socket)
(defn echo-upper (sock)
 (.send c (.upper (.recv c 10000)))
 (.close c)
)
(def s socket.socket)
(.bind s (tuple ["" 8000]))
(.listen s 5)
(while True
 (echo-upper (.__getitem__ (s.accept) 0))
)

Python generated from ABS with astor:

import socket
def echo_upper(sock):
 c.send(c.recv(10000).upper())
 return c.close()
s = socket.socket
s.bind(tuple([u'', 8000]))
s.listen(5)
while True:
 echo_upper(s.accept().__getitem__(0))

I'm not worried about not dealing with connections properly etc, I'd just like feedback on using lispy syntax. I'm tempted to do things like ((getattr s "bind") (tuple ["" 8000])) because it looks more like simple Scheme, the only lisp I have a little experience with.

Any thoughts on syntax and style? Any guidelines for dealing with Python APIs in a lispy way, something that apparently happens a lot in Clojure with Java?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jun 8, 2013 at 19:25
\$\endgroup\$

4 Answers 4

1
\$\begingroup\$

I wouldn't use the threading macro here. That's most useful when you want to see the data flow, but you're using c two times in this expression, there's no clear flow that -> could make easier to untangle. It makes it more complicated in this case...

If you'd decouple the receive and the send part, then it'd be different, but then the expression becomes so simple you don't even need the macro:

(let [[received (.recv c 10000)]]
 (.send c (.upper received)))

With the threading macro, the inner part would become (-> received (.upper) (.send c)) - doesn't make it much clearer, either.

What you could do, however, is abstract away the accept -> do something -> close thing into a macro:

(defmacro with-accepted-connection [listening-socket & rest]
 (quasiquote (let [[*sock* (get (.accept (unquote listening-socket)) 0)]]
 (unquote-splice rest)
 (.close *sock*))))
(with-accepted-connection s (.send *sock* (upper (.recv *sock* 10000))))

The above may or may not work out of the box, I just conjured it up. But something similar may make the code lispier and easier to understand the intent later.

answered Jun 13, 2013 at 23:09
\$\endgroup\$
1
\$\begingroup\$

As suggested by the Hy docs, I'm trying the threading macro here:

(.send c (.upper (.recv c 10000)))

becomes

(-> (.recv c 10000) (.upper) (c.send))

I'm not sure I like it.

answered Jun 8, 2013 at 19:55
\$\endgroup\$
1
\$\begingroup\$

algernon in freenode/#hy says:

Looks lispy enough to me, except for the __getitem__ line.

...and the closing braces.

I'm think this is fix for the braces and using get instead of __getitem__:

(import socket)
(defn echo-upper (sock)
 (.send c (.upper (.recv c 10000)))
 (.close c))
(def s socket.socket)
(.bind s (tuple ["" 8000]))
(.listen s 5)
(while True
 (echo-upper (get (s.accept) 0)))
answered Jun 8, 2013 at 19:41
\$\endgroup\$
1
\$\begingroup\$

So, yeah, the threading macro is a great way of writing it - using it is a borrowed bit of syntax from Clojure :)

FYI, using a tupple in Hy is:

(, 1 2 3)
; (1, 2, 3)

If you'd like, I can help you through another version of this in a more "Hythonic" way (like Algernon's!)

answered Jun 14, 2013 at 2:24
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.