I would like to randomly shuffle a list in agda.
I thought about taking random n elements from the beginning and adding them to the end, but I couldn't get the random part to work from this approach.
Is this possible with pattern matching or do I really have to figure out random number generation?
Current state:
shuffle : {A : Set} -> List A -> List A
shuffle [] = []
shuffle (x ∷ []) = x ∷ []
shuffle (x ∷ x₁ ∷ xs) = ?
I think the straightforward way to implement Fisher-Yates shuffle is to use a monadic effect for generating random numbers:
So how do we produce random
Fin ns? @mudri's comment points us toData.Nat.PseudoRandom.LCGwhich suggests usingstepwith a state of typeℕ, and using simple remainder bynto produce aFin n:Example usage:
Note that this doesn't prove that the output is indeed a permutation of the input. If you need that, I think it's easier to change
shuffleandswapto produce a permutation witness (e.g. like this) instead of operating on the input vector directly and proving it externally.Edited to add: In Idris 2 at least, we can prove that
shuffleis linear in the shuffled vector by just using linear types where they matter:Note the type of
xsin the signature ofshuffle. I think parametricity + linearity together here should be sufficiently convincing thatshuffleindeed shuffles its input.