Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
haskell中解压函数的实现_Haskell - Fatal编程技术网

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])