articles icon indicating copy to clipboard operation
articles copied to clipboard

loeb moeb swing

Open BlackCapCoder opened this issue 7 years ago • 2 comments

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.

BlackCapCoder avatar Dec 03 '18 09:12 BlackCapCoder

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?

quchen avatar Dec 03 '18 11:12 quchen

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

BlackCapCoder avatar Dec 03 '18 12:12 BlackCapCoder