variadic bind in Haskell
-
10-02-2021 - |
Question
The following code is an attempt to write a variadic function that acts like this:
bind_variadic mx f = mx >>= f
bind_variadic mx my f = do { x <- mx; y <- my; f x y }
I can write it if one expresses the "rest of binding" as a variable k
, but in order to write a typeclass I need to write one function in terms of the other. To be precise, I want to express l1
in terms of l0
, l2
in terms of l1
, etc.
import Prelude hiding ((>>=), (>>), Monad, return)
-- override the default monad so we don't get confusing
-- instances like "Monad (->)".
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
h :: Monad m => m a -> (t -> m b) -> (a -> t) -> m b
h mx k f = mx >>= \x -> k (f x)
l0 = h (return 3) id (\x -> return x)
l1 = h (return 3) (h (return 4) id) (\x y -> return x)
l2 = h (return 3) (h (return 4) (h (return 5) id)) (\x y z -> return x)
Perhaps the solution involves another continuation?
edit
here's an idea that requires an additional join...
-- if not using Control.Monad, use this
join :: Monad 𝔪 => 𝔪 (𝔪 α) -> 𝔪 α
join mx = mx >>= id
-- idea: get side effects of evaluating first arguments first
h' mz k f = k f >>= \f' -> mz >>= (return . f')
l1' = h' (return 3) return
unary = join (l1' (\x -> return x))
l2' = h' (return 4) l1'
binary = join (l2' (\x y -> return x))
l3' = h' (return 5) l2'
ternary = join (l3' (\x y z -> return x))
Solution
If you want to express this:
ap_variadic mx f = mx >>= f
ap_variadic mx my f = do { x <- mx; y <- my; f x y }
I would use Control.Applicative
instead. Then:
join (f <$> mx)
join (f <$> mx <*> my)
join (f <$> mx <*> my <*> mz)
I think this is better (simpler, more maintainable) than any polyvariadic solution would be.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow