Monad中的变量函数

时间:2017-09-26 11:48:16

标签: haskell type-families

我有一个可变函数类型系列:

type family (~~>) (argTypes :: [Type]) (result :: Type) :: Type where
'[]       ~~> r = r
(t ': ts) ~~> r = t -> (ts ~~> r)

infixr 0 ~~>

我想要一个可变参数函数,它将一些monadic动作(比如print)应用于它的所有参数:

class Foo (ts :: [Type]) where
foo :: ts ~~> IO ()

instance Foo '[] where
    foo = pure ()

instance (Show t, Foo ts) => Foo (t ': ts) where
    foo t = print t >> foo @ts

通常的monadic组合在这里不起作用。 (>>)的类型为IO () -> IO () -> IO ()。我需要使用IO () -> (ts ~~> IO ()) -> ts ~~> IO ()类型的内容来组合print tfoo @ts

是否可以编写这样的功能?

2 个答案:

答案 0 :(得分:3)

延续传递风格可直接访问计算结果。

另一种方法是构建一个类型类来迭代合成,但它很麻烦。

 {-# LANGUAGE FlexibleInstances #-}

class Foo t where
  foo_ :: (IO () -> IO ()) -> t

instance (Show a, Foo t) => Foo (a -> t) where
  foo_ k a = foo_ (\continue -> k (print a >> continue))

instance Foo (IO ()) where
  foo_ k = k (return ())

foo :: Foo t => t
foo = foo_ id

main :: IO ()
main = foo () (Just "bar") [()]

答案 1 :(得分:0)

我找到了编写函数Sub EventRequests() Dim ns As Outlook.NameSpace Dim moveToFolder As Outlook.MAPIFolder Dim objItem As Outlook.MailItem Set ns = Application.GetNamespace("MAPI") On Error GoTo 0 Set moveToFolder = ns.GetDefaultFolder(olFolderInbox).Parent.Folders("Events").Folders("Event Requests") If Application.ActiveExplorer.Selection.Count = 0 Then MsgBox ("Select an E-mail first") Exit Sub End If If moveToFolder Is Nothing Then MsgBox "Target folder not found!", vbOKOnly + vbExclamation, "Move Macro Error" End If For Each objItem In Application.ActiveExplorer.Selection If moveToFolder.DefaultItemType = olMailItem Then If objItem.Class = olMail Then objItem.Move moveToFolder End If End If Next Set objItem = Nothing Set moveToFolder = Nothing Set ns = Nothing End Sub

的方法
IO () -> (ts ~~> IO ()) -> ts ~~> IO ()

因此,有问题的实例成为:

-- | Perform first action `m a` then pass its result to a function `(a -> ts ~~> mb)`
--   which returns variadic function and return that function.
class BindV (m :: Type -> Type) a b (ts :: [Type]) where
    bindV :: m a -> (a -> ts ~~> m b) -> ts ~~> m b

instance (Monad m) => BindV m a b '[] where
    bindV ma f = ma >>= f

instance (BindV m a b ts) => BindV m a b (t ': ts) where
    bindV ma f x = bindV @m @a @b @ts ma ((flip f) x)

-- | Monadic composition that discards result of the first action.
thenV :: forall (m :: Type -> Type) a b (ts :: [Type]).
    (BindV m a b ts) => 
    m a -> (ts ~~> m b) -> ts ~~> m b
thenV ma f = bindV @m @a @b @ts ma (\_ -> f)

我希望我可以将instance (Show t, Foo ts, BindV IO () () ts) => Foo (t ': ts) where foo t = thenV @IO @() @() @ts (print t) (foo @ts) thenV写为运算符,但bindV不能与运算符一起使用。