What's a nice way to generate pairs of strings that differ by n characters? All my efforts so far have led to me baking in a ton of logic into fmaps. Does anyone have any suggestions about how I can do this by putting non-custom generators together?
it seems unlikely, but I think you should be able to get by with a single fmap
Equal length strings?
generate a string of more than n characters, generate a vector of n characters and indices, then fmap over both of those producing a pair of the string, and the string with characters swapped at the indices
(the indices will require some fiddling to work out right, but doable)
You could also generate edit operations
yeah, characters + indices are an edit operation
What I've done so far is generate a string, and then edit out parts of it at random start and end positions using subs, joins and replace
no, I don't think you can do it without an fmap
Random meaning calling rand-int or similar?
in order for the generator to work at all, you need to at the base to be able to turn 1 string in to a pair of strings
that is gonna be an fmap
choose
with a range based on the count of characters in the string
Tied together with bind and fmap?
Yup. I've thrown the code away and it's no longer in my undo tree unfortunately.
Ha
let instead of bind.
Sure
I think generating edits is pretty easy, though it might be harder to aim for exactly N differences if you need that
Generating edits would shrink nicely I think
If you want to shrink toward fewer differences
I'll give it a shot in the AM and report
;; written but not run
;; assuming strings of length 5 and differences of 3 characters
(gen/fmap
(fn [string edits]
(loop [[[shift index] & es] edits
s (vec string)
editted #{}]
(if e
(let [i (mod index (count s))]
(if (contains? editted i)
(recur (cons [shift (inc index)] es) s editted)
(recur es
(update-in s [i] (fn [c]
(char (+ 32 (mod (+ offset (- (int c) 32)) 126)))))
(conj editted i))))
(apply str s))))
(gen/tuple (gen/resize 5 gen/string-ascii)
(gen/tuple
(gen/tuple s-pos-int s-pos-int)
(gen/tuple s-pos-int s-pos-int)
(gen/tuple s-pos-int s-pos-int))))
(that mod 126 should maybe be mod 126 - 32)
and the fn has to destructure the vector, etc
Can you recur
from there?
inside a loop? of course
I meant from non-tail position
I am pretty sure those are all tails
I thought I had run into not being able to recur from the first branch of if but I may well be getting mixed up with recur within try
yes, you can't recur across a try, logically a try pushes an exception handler on to a stack, so recuring across a try grows the exception handling stack
Thanks, that makes sense