提问人:Sophie 提问时间:4/19/2023 最后编辑:Sophie 更新时间:4/19/2023 访问量:67
在 Haskell 中将任何类型的列表作为函数参数(使用 Replit)
Take list of any type as a function parameter in Haskell (using Replit)
问:
我正在尝试在 Haskell 中编写一个函数,该函数将列表作为参数并返回并删除最后一个元素 这是我拥有的代码:
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement (hd:rest) =
if null rest
then return []
else hd:remLastElement rest
我已经使用它作为参数对其进行了测试,因此我知道它按预期工作,但是我想知道如何允许它获取不同类型的列表,例如我有一个列表或列表[Int]
['apples','oranges','pears']
[2.4,7.32,1.46,4.5]
我做了一些搜索,在我找到的许多示例和文档中,[a] 被用来表示任何类型的列表,但 Replit 不接受它作为有效的语法。我不确定它是否真的不是有效的语法,或者 Replit 是否出于某种原因很愚蠢。 我也偶然发现了所有的东西,但据我所知,这不是 Haskell 内置的东西,我需要一个扩展才能使用它。
答:
但我想知道我如何允许它获取不同类型的列表,例如我有一个列表或列表。
['apples','oranges','pears']
[2.4,7.32,1.46,4.5]
它已经做到了,只要列表中的所有元素都具有相同的类型,那么 s、s 等列表就可以了。Int
String
你只是犯了一个错误,你应该放弃.事实上,虽然列表是一个单子,但你在这里返回一个简单的列表,所以:return
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement (hd:rest) =
if null rest
then []
else hd:remLastElement rest
该功能还可以通过模式匹配轻松简化,甚至可以通过以下方式提高效率:
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement (x:xs) = go x xs
where go _ [] = []
go z (y:ys) = z : go y ys
这将防止两次拆包相同的缺点。
我们可以用浮点数和字符串来测试这一点:
ghci> remLastElement ["apples","oranges","pears"]
["apples","oranges"]
ghci> remLastElement [2.4,7.32,1.46,4.5]
[2.4,7.32,1.46]
让我们检查一下你的代码:
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement (hd:rest) =
if null rest
then return []
else hd:remLastElement rest
在此上下文中,表示 ,仅包含作为其唯一元素的列表。因此,表示 ,包含空列表作为其唯一元素的列表列表。但是,这与类型签名所承诺的类型相符。return x
[x]
x
return []
[[]]
[a]
一般来说,除非您知道自己正在使用 monads,否则请避免使用。return
因此,固定代码是
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement (hd:rest) =
if null rest
then []
else hd : remLastElement rest
不过,我们仍然可以改进这一点。通常,您不必使用 ,它是一个次要的反模式。您已经使用模式匹配来检查输入列表是否为空,这不需要 .真棒!null
null
我们可以使用相同的技术(模式)匹配来检查尾部(上面称为)是否为空。rest
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement (hd:[]) = []
remLastElement (hd:(hd2:rest2)) = hd : remLastElement (hd2:rest2)
请注意,我们如何用两个新情况替换原始情况,并且将第二个方程拆分为两个新方程。现在不需要了。rest
[]
hd2:rest2
if null
我们仍然可以改进。该模式可以写成 。此外,我们可以用原始变量替换整个模式——这是因为方程是按顺序尝试的,所以如果 和 大小写不匹配,我们知道它一定是非空的。hd:[]
[hd]
hd2:rest2
rest
[]
[hd]
rest
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement [hd] = []
remLastElement (hd:rest) = hd : remLastElement rest
最后的润色:如果您打开警告(我强烈建议),GHC 会抱怨第二个等式中没有使用。为了使警告静音,我们可以将该变量替换为通配符。-Wall
hd
_
remLastElement :: [a] -> [a]
remLastElement [] = []
remLastElement [_] = []
remLastElement (hd:rest) = hd : remLastElement rest
评论
pure
,它适用于更多类型,并且误导性要小得多。但在此示例中,您也不需要。return
return
return