使用 do 语法创建列表?
我对 Haskell 比较陌生。我正在 happstack-lite 之上创建一个小型 api/dsl ,它将有一个更类似于 Sinatra 的界面,主要是为了学习。作为其中的一部分,我想使用 do 语法构造一个数组(基本上是因为它比 msum [route,route,route] 更漂亮。monad 的用法看起来像this:
someFunctionThatMakesStrings :: String
unwrapMyMonadAndGiveMeAList :: MyMonad _ -> [String]
makeAList :: [String]
makeAList = unwrapMyMonadAndGiveMeAList do
someFunctionThatMakesStrings
someFunctionThatMakesStrings
someFunctionThatMakesStrings
...
所以 makeAList 将返回一个包含 3 个字符串的列表。请注意,我想使用其中不知道 monad 的函数(它们只返回一个字符串)
,但每个调用的函数都有。要意识到Writer monad,而且它看起来也有点矫枉过正(我不需要返回类型元组,而且我让它工作的方式涉及大量包装/展开)
我尝试使用列表 monad 本身,但它显然是为了某些东西 那么我的哪些假设
需要改变,然后我如何从头开始创建一个新的列表构造单子呢?
I'm relatively new to Haskell. I'm creating a small api/dsl on top of happstack-lite, which will have an interface more similar to Sinatra, mostly to learn. As a part of this, I want to construct an array using do syntax (basically because it would be prettier than the msum [route, route, route]
thing. The usage of the monad would look something like this:
someFunctionThatMakesStrings :: String
unwrapMyMonadAndGiveMeAList :: MyMonad _ -> [String]
makeAList :: [String]
makeAList = unwrapMyMonadAndGiveMeAList do
someFunctionThatMakesStrings
someFunctionThatMakesStrings
someFunctionThatMakesStrings
...
So makeAList would return a list with 3 strings. Notice that I would like to use functions inside it that aren't aware of the monad (they just return a string).
I can do this with Writer, but each function called has to be aware of the Writer monad, and it also seems like overkill (I don't need the return type tuple, and the way I got it to work involved lots of wrapping/unwrapping)
I tried using the list monad itself, but it clearly is intended for something different than this.
So which of my assumptions need to change, and then how would I make a new list-construction monad from scratch? How close can I get?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Writer 绝对是您想要的;您可以避免将 Writer 暴露给外部,但代价是定义本身会增加一点开销:
即,您可以将 Writer 的使用保留在每个定义本地,但必须包装每个定义您想要在
tell
中用作“源”的列表。这里的关键是使用execWriter
,它会丢弃元组的结果元素(它与snd . runWriter
相同)。然而,如果你有很多这样的定义,我建议直接使用 Writer,并且只在你想要组合结果的地方应用 execWriter;您可以通过定义类似
type Foo = Writer [String]
的同义词来使类型更加简洁。我不确定构建自己的列表创建 monad 会有什么优势;它最终将与 Writer [String] 相同。
列表单子确实与您想要在这里执行的操作无关。
就定义您自己的列表写入 monad 而言,它非常简单:
唯一棘手的部分是
(>>=)
,我们必须只获取左侧参数的值部分,将其输入到右侧参数中,将其拆开,然后将两个列表组合在里面,并用右侧的结果将其包装起来。Writer is definitely what you want here; you can avoid "exposing"
Writer
to the outside at the cost of a little more overhead in the definitions themselves:i.e., you can keep the use of Writer local to each definition, but you have to wrap each list you want to use as a "source" in
tell
. The key thing here is to useexecWriter
, which discards the result element of the tuple (it's identical tosnd . runWriter
).However, if you have a lot of definitions like this, I would recommend simply using Writer directly, and only applying
execWriter
in the place where you want the combined result; you can make the types a bit cleaner by defining a synonym liketype Foo = Writer [String]
.I'm not sure what advantage constructing your own list-creation monad would be; it would end up being identical to
Writer [String]
.The list monad is indeed irrelevant to what you want to do here.
As far as defining your own list-writing monad goes, it's pretty simple:
The only tricky part is
(>>=)
, where we have to take only the value part of the left argument, feed it into the right hand argument, take it apart, and then combine the two lists inside, wrapping it back up with the result of the right hand side.