如何在Haskell中将元组返回的值转换为“位置”参数?

时间:2019-01-21 03:03:42

标签: haskell

我理解没有“位置”参数的意思是,所有函数仅取一个变量并返回一个函数以对其余参数进行运算,但这就是我想做的:

从一些我用来格式化带有前置项,分隔符和结束项的列表的功能开始。

Prelude> formatList start end sep xs = start ++ (intercalate . separator ( map show xs )) ++ end

像这样工作:

Prelude Data.List> formatList "(" ")" "," [1..10]
"(1,2,3,4,5,6,7,8,9,10)"

很酷,相同的想法可以用于xml标签:

Prelude Data.List> formatList "<meow>" "</meow>" "" [1..10]
"<meow>12345678910</meow>"

本着重用功能和简洁性的精神,让我们做到这一点,这样我们就不必通过使函数仅从单词“ tag”产生打开和关闭来键入喵喵标签的冗余部分。 / p>

Prelude Data.List> tagger tag item = "<" ++ tag ++ ">" ++ item ++ "</" ++ tag ++ ">"
Prelude Data.List> tagger "div" "contents"
"<div>contents</div>"

因此,现在让一些标记制作器返回开始和结束,我可以为formatList函数添加第二个参数:

Prelude Data.List> tagMaker tag = ("<" ++ tag ++ ">", "</" ++ tag ++ ">")

看起来不错:

Prelude Data.List> tagMaker "div"
("<div>","</div>")

现在尝试一下。实际行为:

Prelude Data.List> formatList (tagMaker "div") "" [1..10]

<interactive>:49:13: error:
    • Couldn't match expected type ‘[Char]’
                  with actual type ‘([Char], [Char])’
    • In the first argument of ‘formatList’, namely ‘(tagMaker "div")’
      In the expression: formatList (tagMaker "div") "" [1 .. 10]
      In an equation for ‘it’:
          it = formatList (tagMaker "div") "" [1 .. 10]

所需行为:

formatList (tagMaker "div") "" [1..10]
"<div>12345678910</div>

使tagMaker函数能够为希望采用第一个值,然后是第二个值的函数所用的正确方法是什么?如果这完全不是习惯用法,那么正确的成语是什么?

2 个答案:

答案 0 :(得分:9)

命名参数的usual trick似乎很有趣。

data Formatter = Formatter { start, end, sep :: String }

formatList :: Show a => [a] -> Formatter -> String
formatList xs fmt = start fmt ++ intercalate (sep fmt) (map show xs) ++ end fmt

with :: Formatter
with = Formatter "" "" ""

现在您的原始通话如下:

formatList [1..10] with { start = "(", end = ")", sep = "," }
formatList [1..10] with { start = "<meow>", end = "</meow>" }

您可以通过以下方式创建格式化工厂:

xmlTag :: String -> Formatter
xmlTag t = with { start = "<" ++ t ++ ">", end = "</" ++ t ++ ">" }

用法如下:

formatList [1..10] (xmlTag "div")               -- use the default separator
formatList [1..10] (xmlTag "div") { sep = "," } -- specify a separator

答案 1 :(得分:1)

只是简单易用的formatList,因此它以2元组作为第一个参数,而不是两个单独的参数。

> :t formatList
formatList :: Show a => String -> String -> String -> [a] -> String
> :t uncurry formatList
uncurry formatList :: Show a => (String, String) -> String -> [a] -> String
> (uncurry formatList) (tagMaker "div") "" [1..10]
"<div>12345678910</div>

但是,我只是更加明确地使用了tagMaker的返回值。上面的方法仅适用于tagMaker准确地向formatList提供前两个参数。

> let (b,e) = tagMaker "div" in formatList b e "" [1..10]
"<div>12345678910</div>"