articles
articles copied to clipboard
loeb moeb swing
The pointfree article on haskell.org mentions a strange function named swing:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing f c a = f ($ a) c
swing map :: forall a b. [a -> b] -> a -> [b]
swing any :: forall a. [a -> Bool] -> a -> Bool
swing foldr :: forall a b. b -> a -> [a -> b -> b] -> b
swing zipWith :: forall a b c. [a -> b -> c] -> a -> [b] -> [c]
swing find :: forall a. [a -> Bool] -> a -> Maybe (a -> Bool)
...
The type is very close to your moeb function, but it is a bit more general. Indeed, it turns out that moeb can be defined in terms of swing and fix:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing f c a = f ($ a) c
moeb :: (((a -> b) -> b) -> c -> a) -> c -> a
moeb f x = fix (\go -> f ($ go) x)
moeb f = fix . swing f
loeb = moeb fmap = fix . swing fmap
This realization really brought things together for me:
any :: Foldable t => (a -> Bool) -> t a -> Bool
-- `any` takes a predicate and a collection of things,
-- and returns whether the predicate succeeds for
-- some value in the collection
swing any :: Foldable t => t (a -> Bool) -> a -> Bool
-- `swing any` instead takes a collection of predicates,
-- and returns whether any of them succeeded.
-- Informally it moves the `t` from the `a` to the `(a -> Bool)`.
fix . swing any :: Foldable t => t (Bool -> Bool) -> Bool
-- `moeb any` removes the `a` entirely, instead the collection
-- is defined in terms of itself and moeb finds a fixed point.
I don’t understand what swing does though – I can read the type and implementation, but I wouldn’t know a practical example of what it would be useful for. Löb has spreadsheets, what does swing have?
I don't have a canonical example (yet). My intuition is that given some function (a -> b) -> f a -> _ swing will produce f (a -> b) -> a -> _ - that is, it somehow moves the f.
Something I found really cool is what it does for fmap:
fmap :: Functor f => (a -> b) -> f a -> f b
swing fmap :: Functor f => f (a -> b) -> a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
swing fmap = \fs a -> fs <*> pure a
So swing fmap almost gives you a free Applicative!
instance Applicative [] where
pure = swing fmap [id]
fs <*> [a] = swing fmap fs a
fs <*> as = undefined
-- Valid implementation of `ap` given Monoid:
instance Applicative [] where
fs <*> as = mconcat $ swing fmap fs <$> as