hey i have a math problem i was hoping somebody could solve
okay so as you may already know i wrote some haskell code for enumerating through values, and that was real neat and useful and generally speaking i accomplished a lot with it.
now i'm trying to expand it. specifically: the code as written lets you enumerate through values, but in constructing the values any sense of relative position is lost. you can do something like
SO i had the idea to track mergings of decks. change the data type to
and make the applicative instance
so that
and so then you can decompose indices into movements along those axes, like so:
and it will say: okay index 62 there decomposes to
to have it spit out all decomposed values that are one unit distant. so then:
and now you can navigate around within a enumerable deck. very neat. i'm currently using this to put together some really basic plant mutation/crossbreeding code (since you can also crossbreed two indices by decomposing them, and then picking values randomly from the two sets) and it's generally working pretty well.
the PROBLEM is:
the original formulation of
BUT: this new formulation would require some additional segment tracking. Applicative is really easy to store because it just creates n-dimensional prisms with totally regular axes. Alternative is a lot trickier, because it would involve... adding offsets? something? the actual lookup math above is really simple, but if i wanted to store that as a segment i'm pretty sure i would need to stop using just lists of integers.
i've looked at a lot of math and i've tried to mark out the patterns it would make in indexing and i have yet to really figure out what i should do with it. i think the GOAL is to have it treat all choices as adjacent? so like
it's just uhhhh i am totally failing to see whatever structure i need to see to codify that up, so, if anybody has any thoughts i would like to hear them.
(spoilers this two-week project is gonna be trying to make something like this.)
okay so as you may already know i wrote some haskell code for enumerating through values, and that was real neat and useful and generally speaking i accomplished a lot with it.
now i'm trying to expand it. specifically: the code as written lets you enumerate through values, but in constructing the values any sense of relative position is lost. you can do something like
V2 <$> from [1..10] <*> from [1..20]
and that will let you enumerate through all 200 values, but if you have an index representing, say, V2 3 7
(index 62 btw) you can't say "i want to see the indices of all values that are one unit adjacent". basically there's no way to inspect a deck.SO i had the idea to track mergings of decks. change the data type to
data Enumerable a = Enumerable
{ count :: Integer
, segments :: [Integer]
, selector :: Integer -> a
}
and make the applicative instance
instance Applicative Enumerable where
pure v = Enumerable 1 [1] $ const v
(Enumerable c s f) <*> (Enumerable c' s' g) =
Enumerable (c * c') (s <> ((c *) <$> s')) $ \i -> let
j = i `mod` c
k = i `div` c
in f j $ g k
so that
V2 <$> from [1..10] <*> from [1..20]
value would have 'segments' of [1,10]
, meaning that there are two axes: one that increases/decreases in steps of 1 and one that increases/decreases in steps of 10.and so then you can decompose indices into movements along those axes, like so:
decompose :: Enumerable a -> Integer -> [Integer]
decompose (Enumerable _ s _) i' = snd $ mapAccumR split i' s
where
split :: Integer -> Integer -> (Integer, Integer)
split i c = (i `mod` c, i `div` c)
and it will say: okay index 62 there decomposes to
[2,6]
. and then you can do something like...mutate :: Enumerable a -> [Integer] -> [[Integer]]
mutate e i = tail $ recombine $ zip i mutvals
where
mutvals = uncurry spread <$> zip (maxAxes e) i
spread m c = snd <$> filter fst
[ (c > 0, c - 1)
, (c < m, c + 1)
]
recombine [] = [[]]
recombine ((base,vars):rs) = ((:) <$> pure base <*> recombine rs)
<> ((:) <$> vars <*> pure (fst <$> rs))
maxAxes :: Enumerable a -> [Integer]
maxAxes e = decompose e $ count e - 1
mutateI :: Enumerable a -> Integer -> [Integer]
mutateI e i = construct e <$> mutate e (decompose e i)
to have it spit out all decomposed values that are one unit distant. so then:
λ> let foo = ((,) <$> from [1..10] <*> from [1..20])
λ> select foo 62
Just (3,7)
λ> mutateI foo 62
[52,72,61,63]
λ> select foo <$> mutateI foo 62
[Just (3,6),Just (3,8),Just (2,7),Just (4,7)]
and now you can navigate around within a enumerable deck. very neat. i'm currently using this to put together some really basic plant mutation/crossbreeding code (since you can also crossbreed two indices by decomposing them, and then picking values randomly from the two sets) and it's generally working pretty well.
the PROBLEM is:
the original formulation of
Enumerable
is also an Alternative
and a Monoid
:instance Alternative Enumerable where
empty = Enumerable 0 $ const (error "no value")
(Enumerable c v) <|> (Enumerable c' v') =
Enumerable (c + c') $ \i -> case i - c of
x | x >= 0 -> v' x
| otherwise -> v i
instance Monoid (Enumerable a) where
mempty = empty
mappend = (<|>)
BUT: this new formulation would require some additional segment tracking. Applicative is really easy to store because it just creates n-dimensional prisms with totally regular axes. Alternative is a lot trickier, because it would involve... adding offsets? something? the actual lookup math above is really simple, but if i wanted to store that as a segment i'm pretty sure i would need to stop using just lists of integers.
i've looked at a lot of math and i've tried to mark out the patterns it would make in indexing and i have yet to really figure out what i should do with it. i think the GOAL is to have it treat all choices as adjacent? so like
pure 1 <|> pure 2 <|> pure 3 <|> pure 4
would be different from from [1,2,3,4]
because the alternative would consider 1 adjacent to all of 2, 3, and 4, whereas the basic enumeration would only consider 1 adjacent to 2. (and then from [1,2] <|> from [3,4] <|> from [5,6] <|> from [7,8]
would consider 1 and 2 to be adjacent to each other and to all of 3 5 and 7. ditto 3 & 4 with 1, 5, and 7.)it's just uhhhh i am totally failing to see whatever structure i need to see to codify that up, so, if anybody has any thoughts i would like to hear them.
(spoilers this two-week project is gonna be trying to make something like this.)