虽然可以绑定IO [[Char]]
和IO ()
,但不允许将Maybe
绑定到IO
。有人可以举例说明这种放松会导致糟糕的设计吗?为什么允许Monad的多态类型中的自由而不是Monad本身呢?
答案 0 :(得分:7)
有许多好的理论原因,包括“那不是Monad
。”但是,让我们暂时离开它,看看实现细节。
首先关闭 - Monad
不是魔法。它只是一个标准的类型。 Monad
的实例只有在有人写一个实例时才会创建。
编写该实例是定义(>>)
如何工作的原因。通常它是通过(>>=)
方面的默认定义隐式完成的,但这只是(>>=)
是更一般的运算符的证据,编写它需要做出写(>>)
的所有相同决策需要。
如果你有一个不同的运算符可以处理更常见的类型,你必须回答两个问题。首先,这些类型是什么?其次,您将如何提供实施?从你的问题来看,真正不清楚所需的类型是什么。我猜是以下之一:
class Poly1 m n where
(>>) :: m a -> n b -> m b
class Poly2 m n where
(>>) :: m a -> n b -> n b
class Poly3 m n o | m n -> o where
(>>) :: m a -> n b -> o b
所有这些都可以实施。但是你实际上失去了两个非常重要的因素。
n
与n^2
的对比。Monad
背后的理论对操作施加了很多限制。这些限制被称为“单一法律”。它们超出了在Haskell中验证的能力,但任何不遵守它们的Monad
实例都被认为是错误的。最终结果是,您可以快速建立对Monad
操作执行和不执行操作的直觉。您可以在不查看所涉及的每种类型的详细信息的情况下使用它们,因为您知道它们遵守的属性。我建议的那些可能的课程都没有给你任何类似的保证。你根本不知道他们做了什么。答案 1 :(得分:0)
我不确定我是否正确理解了您的问题,但绝对有可能将Maybe
与IO
或[]
组合起来,就像您可以撰写{{1}一样与IO
。
例如,如果使用[]
检查GHCI中的类型,
:t
为您提供getContents >>= return . lines
。如果你添加
IO [String]
您获得的 >>= return . map Text.Read.readMaybe
类型由IO [Maybe a]
,IO
和[]
组成。然后你可以把它传递给
Maybe
将其展平为 >>= return . Data.Maybe.catMaybes
。然后,您可以将已解析的有效输入行列表传递给再次展平它的函数,并计算输出。
把这个放在一起,程序
IO [a]
输入:
import Text.Read (readMaybe)
import Data.Maybe (catMaybes)
main :: IO ()
main = getContents >>= -- IO String
return . lines >>= -- IO [String]
return . map readMaybe >>= -- IO [Maybe Int]
return . catMaybes >>= -- IO [Int]
return . (sum :: [Int] -> Int) >>= -- IO Int
print -- IO ()
打印1
2
Ignore this!
3
。
也可以使用6
,IO (Maybe [String])
等。
您也可以使用Maybe [IO String]
执行此操作。受控示例:>>
读取输入,忽略它,并返回getContents >> (return . Just) False
。