Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 使用do语法创建列表?_Haskell_Monads - Fatal编程技术网

Haskell 使用do语法创建列表?

Haskell 使用do语法创建列表?,haskell,monads,Haskell,Monads,我对哈斯克尔比较陌生。我在上面创建了一个小的api/dsl,它将有一个更类似于Sinatra的界面,主要是为了学习。作为其中的一部分,我想使用do语法构造一个数组(基本上是因为它比msum[route,route,route]东西更漂亮 someFunctionThatMakesStrings :: String unwrapMyMonadAndGiveMeAList :: MyMonad _ -> [String] makeAList :: [String] makeAList =

我对哈斯克尔比较陌生。我在上面创建了一个小的api/dsl,它将有一个更类似于Sinatra的界面,主要是为了学习。作为其中的一部分,我想使用do语法构造一个数组(基本上是因为它比
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
(>>=)
,但这将是一个可怕的黑客行为,不会保存任何键入内容。