刚性类型变量如何在Monads的上下文中起作用?

时间:2015-12-18 09:27:23

标签: haskell casting monads higher-order-functions algebraic-data-types

假设我有一个Monad data Concurrent a = Concurrent ((a -> Action) -> Action)和一个类型Action,它允许各种可能的IO Actions

说我想写一个函数action :: Concurrent a -> Action,有效地编写自定义解包。第一步可能是编写函数action2 :: ((a -> Action) -> Action) -> Action

我有几个问题: 我的理解是a是一个严格的变量,例如一个类型变量,由编译器强制转换为某种类型。

这使得((a -> Action) -> Action)成为一个函数(让我们称之为f1),它接受类型(a -> Action)的函数,并返回一个Action,对于某种任意类型,和((a -> Action) -> Action) -> Action,一个接受上述函数f1的函数,运行它,并返回结果。

假设以上是正确的,我的问题确实是:

在Monad的背景下,这有什么意义?说我有一个功能:

stringToAction :: (String -> Action)
stringToAction [] = Stop
stringToAction x = Atom $ putStr x

所以:t stringToAction履行了(a - > Action)的合同 但是:t stringToAction" 7"类型(String -> Action) -> String -> Action

我是否必须编写(a -> Action) -> a -> Action类型的辅助函数(例如)

higherOrderStringToAction :: (String -> Action) -> String -> Action
higherOrderStringToAction f x = f x

然后在传递的函数上调用它(a - > Action)?

stringToActionHelper = higherOrderStringToAction stringToAction

我是否必须为我希望处理的每种可能类型的a编写一组不同的辅助函数?

然后,更令人担忧的是,我是否必须处理Monad Instance定义中的所有内容? e.g

Concurrent 7如何知道如何将7转换为动作?我是否必须在a定义和分支中询问>>=的类型?我怎么会这样做?

或者我(这显然可能)完全忽略了这一点和/或直接想到这个错误?

1 个答案:

答案 0 :(得分:1)

  

假设我有一个Monad data Concurrent a = Concurrent ((a -> Action) -> Action)和一个类型Action,它允许各种可能的IO Actions

我将假设您无缘无故地将“IO动作”放入反引号中。我不知道你是否对你头脑中发生的事情有一个可靠的模型,但由于Haskell是一种纯语言,IO x的含义是“一个程序,在运行时产生x” (换句话说,Haskell对功能I / O的解决方案是参与元编程而不是其他编程。)因此,在实践中Action听起来像是IO ()的类型同义词或东西。

Hoogle对(a -> IO x) -> IO x的搜索显示,这是withMVar m的输出类型,也与fixIO类型相关。换句话说:您的Concurrent就是要包含a类型的某些值并保留以供日后使用。

如果我们定义data C b a = C ((a -> b) -> b),我们可以最明确地看到这一点,以便您的Concurrent实际上只是特殊情况C Action。这里的技巧是这个函数类型forall b. (a -> b) -> b实际上是Identity monad newtype Identity a = Identity {runIdentity :: a}的Church编码。反过来我们可以说更普遍的monad是:

instance Monad (C b) where
    return x = C ($ x)
    (C w_wx) >>= my_x = my_x (w_wx id)

所以你为Concurrent所写的内容实际上是身份monad的一个特例。

  

所以:t stringToAction履行了(a - > Action)的合同但是:t stringToAction“7”的类型为(String -> Action) -> String -> Action

假。 stringToAction "7"的类型为Action,因为它类型String -> Action的函数应用于String类型的值。

  

我是否必须编写(a -> Action) -> a -> Action

类型的辅助函数

您所写的内容有一个名称,它是名为id的函数,或者更具体地说是其类型特化($)。此外,上面的这种类型没有您想要推送到data Concurrent a = Concurrent ((a -> Action) -> Action)构造函数的类型。相反,你想要($ "myString") :: (String -> Action) -> Action之类的东西将该字符串嵌入你的身份monad。

  

Concurrent 7如何知道如何将7转换为Action?我是否必须在a定义和分支中询问>>=的类型?我怎么会这样做?

没有。您的Concurrent monad实际上只是Identity monad,将7转换为Action的过程由您传递的Int -> Action函数完成参与辩论。 (就此而言,如果你写Concurrent 7,你会从GHC那里得到一个令人讨厌的错误,说“我不知道类型(a -> Action) -> ActionNum类型类的元素,是什么到底是怎么回事?!“