我必须将列表分成两半,导致列表的前半部分和列表的后半部分(half1,half2)的元组。当这个列表的长度是奇数时,我想让half1包含比half2更多的元素。如果给出一个空列表,我想要一个([],[])元组。但是,以下代码给出了一个错误。
halve :: [a] -> ([a],[a])
halve [] = ([],[])
halve xs =
if (((length(xs) `mod` 2)==1))
then(take (ceiling(toRational(length(xs) `div` 2))) xs, drop(ceiling(toRational(length(xs) `div` 2))) xs)
else ((take (floor(toRational(length(xs) `div` 2))) xs, drop (floor(toRational(length(xs) `div` 2))) xs))
main = do
putStrLn(show (halve [1,2,3]))
putStrLn(show (halve [])) gives me an error
我认为对于putStrLn(show(halve []))的错误,解释器不知道数组是由什么构成的,但我怎么能这样做以便类型无关紧要以便该行给出我([],[])。
答案 0 :(得分:2)
问题是[]
是多态的吗?它的类型是[] :: [a]
。这与我们使用Show
的事实相结合意味着我们的类型为Show a => [a]
。
现在Haskell不知道我们想要哪个a
,而且选择很重要!如果a
是Char
,则打印("", "")
,如果a
不是,则可能会打印([], [])
。所以我们必须决定我们想要使用什么类型。
一个简单的诀窍是[] :: String
只是""
。所以
putStrLn (show (halve ""))
由于print
是相同的行为
print (halve "")
如果我们不想使用Char
,那么我们就可以写
print (halve ([] :: [SomeType]))
答案 1 :(得分:2)
你不能这样做。您必须指定列表的内容。这是静态类型的工作方式,ghc必须在编译时知道。所以你必须有这样的东西。
main = do
print (halve [1,2,3])
print (halve ([] :: [Int]))
另外,我清理了你的减半功能。
halve :: [a] -> ([a],[a])
halve [] = ([],[])
halve xs
| odd l = splitAt ((l `div` 2) + 1) xs
| otherwise = splitAt (l `div` 2) xs
where l = length xs
答案 2 :(得分:0)
顺便说一句,你的halve
函数编写得有些糟糕。你可以使这个功能更短,如下:
halve :: [a] -> ([a], [a])
halve xs = (take n xs, drop n xs)
where n = ceiling . (/2) . toRational . length $ xs
这取决于take n []
== drop n []
== []
。
此外,在Haskell中,函数调用f(a,b) == f a b
不需要括号,而g(f(x))
可以写成g . f $ x
。
最后,正如其他人所提到的,你需要指定[]
的类型,编译器可以找到相应的show实例。
(一个巧妙的技巧是print = putStrLn . show
)
main = do
print $ halve [1,2,3]
print $ halve ([] :: [Integer])