# I documented this just for you, /prog/. What now, >>1?
class Cycle
def cycle(*args) # All args are passed as an array object
# Assign a new hashtable to the @cycles instance variable if it
# doesn't already exist. If you try to access @cycles[x] for any
# key x that is not already in @cycles, a default value of -1 will
# automatically be inserted. By the way, there's absolutely no
# reason to use an underscore at the beginning of an ivar name.
# The @ already marks it as an ivar.
@cycles ||= Hash.new(-1)
h = args.hash # Hashcode, not array-as-hashtable
@cycles[h] += 1 # Tragically, there's no ++ in ruby
# Have you studied your modular arithmetic today? By the way,
# this is an implicit return statement
args[@cycles[h] % args.size]
end
end
# Now to demonstrate what it actually does
foo = Cycle.new
foo.cycle :hax, :my, :anus # => :hax
foo.cycle :hax, :my, :anus # => :my
foo.cycle :achieve, :satori # => :achieve
foo.cycle :hax, :my, :anus # => :anus
foo.cycle :hax, :my, :anus # => :hax
>>1
If what >>12 said was right, here's how to do it in CL:
(let ((ht (make-hash-table :test #'equal)))
(defun cycle (&rest args)
(unless (gethash args ht)
(setf (gethash args ht) args))
(pop (gethash args ht))))
And a version with less repetition:
(let ((ht (make-hash-table :test #'equal)))
(defun cycle (&rest args)
(symbol-macrolet ((h (gethash args ht)))
(unless h (setf h args))
(pop h))))
Name:
Anonymous2009-08-27 1:23
>>15
Still longer than >>1-chan's Ruby version. I'm masturbating to it as we speak!
Name:
David Caruso2009-08-27 1:24
>>14 If what >>12 said was right
UMH memesmith....
>>16
It does take slightly longer to digest for someone not familiar with Ruby, but the same is probably true for my CL version if people don't know CL.
I'm curious how would the Haskell version be written, especially since OP's problem requires having state implicitly (no passing around a state object).
What >>22 is trying to say is that this is pointless to even try in Haskell. The type system forces you to either write a special monad specifically for the purpose of calling cycle[/cycle], or fuck around with the IO monad so at least you can intersperse it with IO calls.
Oh, and all the arguments have to be of the same type....Actually, it's even worse than that. Since you need a way to compare argument lists to each other, the type signature should say [code](Eq a) => stuff or (Ord a) => stuff, which means that a can't be a function type, which means you can't even use a list like [print 4, print 2]. So basically this (toy) function is more useless than ever in Haskell.
There is a way around this, but it means using separate functions for setting and getting the argument list (and still using a special monad). If you have setArgs :: [a] -> State [a] () and getArg :: State [a] a, the implementation is trivial. The catch is that you can only access the last arglist you set with setArgs, and if you've got different types of arglists you want to use, you have to actually thread them through different instances of State [a].
>>27
As a matter of principle I never use a language that doesn't properly support &optional, &key, and &rest.
Name:
Anonymous2009-08-27 16:13
>>28
I haven't seen a language other than CL with proper support of lambda-list-like features. I've seen some scripting languages try and hack around support for them, but not as good, and I'm not even saying anything about defmacro's arguments being passed as if by destructuring-bind. Yes, there are some insignificant (these days) performance costs to using complex key args, but it makes functions/code much more manageable/generic.
>>25
Yet it would take a lot more code than >>1's or >>14-15's to write the equivalent functionality, and passing variable length args would be awkward unless you passed argument count or just used a list or null-terminated array to represent them. You will have to write a fairly generic hash table implementation(or use one already available), and write a bunch of other boiler-plate code, unless you already have some architecture behind you on which you can lean.
Name:
Anonymous2009-08-27 16:25
from collections import defaultdict
class Cycle(object):
def __init__(self):
self.cycles = defaultdict(int)
c = Cycle()
for i in xrange(6):
print c.cycle("this","is","shit")
Name:
Anonymous2009-08-27 16:53
import Data.Map
import Data.IORef
newCycle =
do state <- newIORef empty
let memoCycle args =
do modifyIORef state $ alter (Just . maybe (cycle args) tail) args
fmap (head . (!args)) $ readIORef state
return memoCycle
>>31
I just thought about writing something using IORefs just to show >>24-26 that it's possible. Good thing you were faster though, as I've never used IORefs before.