haskell中解压函数的实现
我试图实现解压功能,我做了以下代码,但我得到了错误haskell中解压函数的实现,haskell,Haskell,我试图实现解压功能,我做了以下代码,但我得到了错误 myUnzip [] =() myUnzip ((a,b):xs) = a:fst (myUnzip xs) b:snd (myUnzip xs) 我知道问题在第二行的右边,但我知道如何改进它。 请给我任何提示 我得到的错误是 ex1.hs:190:22: Couldn't match expected type `()' with actual type `[a0]' In the expression: a : fst (myUnzip
myUnzip [] =()
myUnzip ((a,b):xs) = a:fst (myUnzip xs) b:snd (myUnzip xs)
我知道问题在第二行的右边,但我知道如何改进它。
请给我任何提示
我得到的错误是
ex1.hs:190:22:
Couldn't match expected type `()' with actual type `[a0]'
In the expression: a : fst (myUnzip xs) b : snd (myUnzip xs)
In an equation for `myUnzip':
myUnzip ((a, b) : xs) = a : fst (myUnzip xs) b : snd (myUnzip xs)
ex1.hs:190:29:
Couldn't match expected type `(t0 -> a0, b0)' with actual type `()'
In the return type of a call of `myUnzip'
In the first argument of `fst', namely `(myUnzip xs)'
In the first argument of `(:)', namely `fst (myUnzip xs) b'
ex1.hs:190:49:
Couldn't match expected type `(a1, [a0])' with actual type `()'
In the return type of a call of `myUnzip'
In the first argument of `snd', namely `(myUnzip xs)'
In the second argument of `(:)', namely `snd (myUnzip xs)'
通过遍历列表两次,可以降低效率
myUnzip [] = ([], []) -- Defaults to a pair of empty lists, not null
myUnzip xs = (map fst xs, map snd xs)
但这并不是很理想,因为与只循环一次相比,它肯定会非常慢。为了避免这种情况,我们必须递归地进行
myUnzip [] = ([], [])
myUnzip ((a, b):xs) = (a : ???, b : ???)
where ??? = myUnzip xs
我将让您填写这些空白,但从这里开始应该很简单,只需查看
myUnzip
的类型签名,并找出您可以在where???处放置什么来代替问号即可myUnzip xs
以下是我在完成上述指导后得到的结果
myUnzip' [] = ([],[])
myUnzip' ((a,b):xs) = (a:(fst rest), b:(snd rest))
where rest = myUnzip' xs
我认为展示两种备选解决方案可能会很有趣。实际上,您不会使用这些,但它们可能会让您了解Haskell的一些可能性 首先,有一个直接的解决方案,使用折叠-
unzip' xs = foldr f x xs
where
f (a,b) (as,bs) = (a:as, b:bs)
x = ([], [])
这使用一个名为foldr
的组合器来迭代列表。相反,您只需定义组合函数f
,它告诉您如何将一对(a,b)
与一对列表(as,bs)
组合,并定义初始值x
第二,记住有一个好看的解决方案
unzip'' xs = (map fst xs, map snd xs)
它看起来很整洁,但执行输入列表的两次迭代。能够编写像这样简单的东西会很好,但是它只在输入列表中迭代一次
使用Foldl
库几乎可以实现这一点。对于为什么它不太有效的解释,请参阅结尾的注释-也许有更多知识/时间的人可以解释修复方法
首先,导入库并定义标识折叠。您可能必须先运行cabal install foldl
才能安装库
import Control.Applicative
import Control.Foldl
ident = Fold (\as a -> a:as) [] reverse
然后,您可以定义提取成对列表的第一个和第二个组件的折叠
fsts = map fst <$> ident
snds = map snd <$> ident
模式匹配要求我们在第二个参数中打开元组,这需要评估折叠的一个步骤,这需要打开另一个元组,这需要评估折叠的一个步骤,等等。但是,如果我们使用无可辩驳的模式匹配(总是成功,不必检查模式)我们的懒惰程度恰到好处-
unzip'' xs = foldr f x xs
where
f (a,b) ~(as,bs) = (a:as, b:bs)
x = ([], [])
所以我们现在可以做了
>> let xs = repeat (1,2)
>> take 10 . fst . unzip' $ xs
^CInterrupted
<< take 10 . fst . unzip'' $ xs
[1,1,1,1,1,1,1,1,1,1]
>让xs=重复(1,2)
>>拿10块。fst。解压“$xs”
^干扰
下面是使用(有些新的)“折叠”包编写的:
导入数据。折叠(R(R),运行)
导入控件。应用程序((),())
识别码::RA[a]
ident=R id(:)[]
fsts::R(a,b)[a]
fsts=映射fst标识
snds::R(a,b)[b]
snds=地图snd标识
解压“::R(a,b)([a],[b])
解压'=(,)fsts SND
测试::([Int],[Int])
测试=运行[(1,2)、(3,4)、(5,6)]解压'
*主>测试
([1,3,5],[2,4,6])
myunzip::[(a,b)]->([a],[b])
myunzip xs=(第一个值xs,第二个值xs)
哪里
第一个值::[(a,b)]->[a]
第一个值[]=[]
firstValues(x:xs)=fst x:firstValues xs
第二个值::[(a,b)]->[b]
第二个值[]=[]
secondValues(x:xs)=snd x:secondValues xs
你能告诉我们你得到了什么错误吗?嗨,皮平,我刚刚意识到我错误地使用了第一个而不是fst,第二个而不是snd,所以我修正了我的错误并把错误放在上面。事实上,你的第一行也有一个错误:()
没有类型([a],[b])
,但是([],[])
是的。想想如何a:fst(myUnzip-xs)
和b:snd(myUnzip-xs)
。现在,您只是将它们并置,在Haskell中,这意味着函数应用程序。你需要创建一对。我知道了,所以我只想在下面列出正确的答案。在阅读了你的指南后,我做了什么,但它仍然在抱怨。你能帮我吗?myUnzip'[]=([],[])myUnzip'((a,b):xs)=(a:(fst rest),b:(snd rest))其中rest=myUnzip'xsI得到了,所以我将在下面给出正确的答案,谢谢兄弟你确定第二个版本比第一个版本快吗?@augustss Nope,但它是在一个循环中完成的。@bheklillr是一个循环,在每次迭代中分配两个cons单元格和一对cons单元格。而不是在每次迭代中分配cons单元的两个循环。我也不知道,但并不总是环接是最贵的。很好。您甚至可以执行(a:as,b:bs)其中(as,bs)=myUnzip'xs
“折叠”包似乎包括左折叠、右折叠以及更多其他功能@托梅利斯:我可能应该指出,我的解决方案和你的解决方案都不适用于无限列表。我想知道是否有可能定义可以处理无限列表的合成折叠。这是可以做到的,因为管道(部分)就是这样做的:)左折叠不起作用,因为它依赖于反向折叠。正确的折叠应该可以工作,但是()
的实现不够懒惰。是的,你是对的-你可以通过使用无可辩驳的模式匹配来修复我的答案中的foldr
示例。我并不完全清楚folds库一般来说这样做是否明智,因此我在某种程度上避免了对bug报告的猜测。我想edwardk会知道惰性模式匹配在一般情况下是否合理。这将起作用并且易于理解
unzip'' xs = foldr f x xs
where
f (a,b) ~(as,bs) = (a:as, b:bs)
x = ([], [])
>> let xs = repeat (1,2)
>> take 10 . fst . unzip' $ xs
^CInterrupted
<< take 10 . fst . unzip'' $ xs
[1,1,1,1,1,1,1,1,1,1]
import Data.Fold (R(R), run)
import Control.Applicative ((<$>), (<*>))
ident :: R a [a]
ident = R id (:) []
fsts :: R (a, b) [a]
fsts = map fst <$> ident
snds :: R (a, b) [b]
snds = map snd <$> ident
unzip' :: R (a, b) ([a], [b])
unzip' = (,) <$> fsts <*> snds
test :: ([Int], [Int])
test = run [(1,2), (3,4), (5,6)] unzip'
*Main> test
([1,3,5],[2,4,6])