Haskell 使用do语法创建列表?
我对哈斯克尔比较陌生。我在上面创建了一个小的api/dsl,它将有一个更类似于Sinatra的界面,主要是为了学习。作为其中的一部分,我想使用do语法构造一个数组(基本上是因为它比Haskell 使用do语法创建列表?,haskell,monads,Haskell,Monads,我对哈斯克尔比较陌生。我在上面创建了一个小的api/dsl,它将有一个更类似于Sinatra的界面,主要是为了学习。作为其中的一部分,我想使用do语法构造一个数组(基本上是因为它比msum[route,route,route]东西更漂亮 someFunctionThatMakesStrings :: String unwrapMyMonadAndGiveMeAList :: MyMonad _ -> [String] makeAList :: [String] makeAList =
msum[route,route,route]
东西更漂亮
someFunctionThatMakesStrings :: String
unwrapMyMonadAndGiveMeAList :: MyMonad _ -> [String]
makeAList :: [String]
makeAList = unwrapMyMonadAndGiveMeAList do
someFunctionThatMakesStrings
someFunctionThatMakesStrings
someFunctionThatMakesStrings
...
所以makeAList将返回一个包含3个字符串的列表。注意,我希望在其中使用不知道monad的函数(它们只返回一个字符串)
我可以用Writer实现这一点,但是调用的每个函数都必须知道Writer的monad,而且这似乎有些过分(我不需要返回类型的元组,而我使用它的方式需要大量的包装/展开)
我尝试使用列表monad本身,但它显然是用于不同于此的用途
那么,我的哪些假设需要更改,然后我将如何从头开始创建一个新的列表构造monad?我可以做到多近?Writer肯定是您在这里想要的;您可以避免将
Writer
暴露在外,而代价是在定义本身上增加一点开销:
foo :: [String]
foo = execWriter $ do
tell otherList1
tell otherList2
tell otherList3
otherList1 :: [String]
otherList1 = execWriter $ do
...
i、 例如,您可以将Writer的使用保持在每个定义的本地,但是您必须在tell
中包装每个要用作“源”的列表。这里的关键是使用execWriter
,这将丢弃元组的result元素(它与snd.runWriter
相同)
但是,如果您有很多这样的定义,我建议您直接使用Writer,并且只在需要组合结果的地方应用execWriter
;您可以通过定义同义词type Foo=Writer[String]
使类型更干净
我不确定构建自己的列表创建monad有什么好处;它最终将与Writer[String]
相同
单子列表确实与您在这里想做的事情无关
就定义自己的列表编写monad而言,非常简单:
data ListWriter a = ListWriter a [String]
runListWriter :: ListWriter a -> (a, [String])
runListWriter (ListWriter a xs) = (a, xs)
execListWriter :: ListWriter a -> [String]
execListWriter = snd . runListWriter
instance Monad ListWriter where
return a = ListWriter a []
ListWriter a xs >>= f = ListWriter b (xs ++ ys)
where ListWriter b ys = f a
唯一棘手的部分是
(>>=)
,我们只需要取左参数的值部分,将其输入到右参数中,将其拆分,然后将两个列表合并在一起,用右参数的结果将其包装起来。这太棒了!我想,构造自己的参数没有好处,但因为我根本无法生成一个,我希望至少能够这样做来学习。当我试图从头开始制作一个时,我不断地得到错误,当我试图将>>=的定义从第一部分的列表写到第二部分的列表时,a不等于b。所以我真的很想看看它会如何look@SeanClarkHess:我添加了一个示例implem列表编写器的entation。是否可以从ListWriter中删除“a”(fst)呢?似乎我不需要它,因为函数实际上不需要相互传递值——它们只需要为列表创建独立的项。换句话说,我永远不会使用,但ListWriter“有种类
”“@SeanClarkHess:monad必须有一个类型参数;这几乎就是全部要点:)去掉它会给你一个;当然,这对您没有帮助,因为您基本上希望获得幺半群的do
-表示法的好处。事实上,Writer所做的是将幺半群转换为单子。您可以保留类型参数,但不在ListWriter
中包含实际的a
值,将未定义的传递给中的f
(>>=)
,但这将是一个可怕的黑客行为,不会保存任何键入内容。