Sorting 评论这深夜,noob Haskell代码
我正在做第三章末尾的练习 我采取了一种不寻常的方法:尽管我知道他们还没有涵盖一些对我有帮助的语言功能,但我尝试只使用他们明确涵盖的内容来做这些练习。为什么?只是为了好玩而已。这感觉就像是强迫我给我的大脑一些额外的递归练习 因此,我刚刚完成了如下练习:“创建一个函数,根据每个子列表的长度对列表列表进行排序。(您可能希望从Data.list模块查看sortBy函数)。” 现在,他们加入了关于Data.List模块的提示。但是他们没有说一句话关于参考文档可以在哪里找到,关于如何导入东西等等。所以我决定自己做一个分类,看看我是否能做到。我使用冒泡排序,因为它是最简单的算法 结果如下。我想请你哈斯克尔大师来评论一下。。。但是请记住以下警告:如果您提出改进建议,请基于真实世界Haskell第3章中介绍的语言功能(或者您猜这些功能可能是什么,而无需费心查找)。我知道有很多很棒的语言特性在等着我,这些特性将使我的代码变得更好,但目前的具体挑战是如何使用到目前为止介绍的“原始”特性Sorting 评论这深夜,noob Haskell代码,sorting,functional-programming,haskell,Sorting,Functional Programming,Haskell,我正在做第三章末尾的练习 我采取了一种不寻常的方法:尽管我知道他们还没有涵盖一些对我有帮助的语言功能,但我尝试只使用他们明确涵盖的内容来做这些练习。为什么?只是为了好玩而已。这感觉就像是强迫我给我的大脑一些额外的递归练习 因此,我刚刚完成了如下练习:“创建一个函数,根据每个子列表的长度对列表列表进行排序。(您可能希望从Data.list模块查看sortBy函数)。” 现在,他们加入了关于Data.List模块的提示。但是他们没有说一句话关于参考文档可以在哪里找到,关于如何导入东西等等。所以我决定
charlieSort :: (Eq a) => [[a]] -> [[a]]
charlieSort [] = []
charlieSort (x:xs) = charlieSort (filter (cmpLen (>) x) xs) ++ [x] ++
charlieSort (filter (cmpLen (<=) x) xs)
where filter _ [] = []
filter p (x:xs) = (if (p x) then (x:) else id) (filter p xs)
cmpLen f x y = f (length x) (length y)
我确信有些情况下,我会绕着我的肩膀去抓我的胳膊肘,有些情况下,当递归和模式匹配可以为我做更多的时候,我会使用显式控制流,等等。我确信代码也会变得更短,更具可读性。我打赌有一些我不知道的好习惯用法可以和我限制自己使用的原始语言功能一起使用。这些就是我想要得到的提示
这可能是任何语言中我引以为傲的最丑陋的代码(至少我记得)。我的第一次尝试,在函数式语言中,在“Hello,world”类型的东西之外。现在你要把它打得屁滚尿流:)。请温柔一点,但我期待着一些具体的见解。谢谢
areListsEqual :: (Eq a) => [a] -> [a] -> Bool
areListsEqual [] [] = True
areListsEqual [] _ = False
areListsEqual _ [] = False
areListsEqual xs ys = (head xs == head ys) && (areListsEqual (tail xs) (tail ys))
charlieSort :: (Eq a) => [[a]] -> [[a]]
charlieSort [] = []
charlieSort (x:xs) | null xs = [x]
charlieSort xs | (length xs) >= 2 = if(not (areListsEqual xs wip))
then charlieSort wip
else wip
where
first = head xs
second = head (tail xs)
theRest = drop 2 xs
swapPairIfNeeded a b = if(length a >= length b)
then [second, first]
else [first, second]
modifiedPair = swapPairIfNeeded first second
wip = (take 1 modifiedPair) ++ charlieSort ( (drop 1 modifiedPair) ++ theRest)
您不需要
areListsEqual
函数。您可以使用(==)
函数比较列表。我会使用快速排序而不是气泡排序。这里有一个解决方案,我认为它只使用了你到目前为止应该学到的东西
charlieSort :: (Eq a) => [[a]] -> [[a]]
charlieSort [] = []
charlieSort (x:xs) = charlieSort (filter (cmpLen (>) x) xs) ++ [x] ++
charlieSort (filter (cmpLen (<=) x) xs)
where filter _ [] = []
filter p (x:xs) = (if (p x) then (x:) else id) (filter p xs)
cmpLen f x y = f (length x) (length y)
charlieSort::(等式a)=>[[a]]->[[a]]
charlieSort[]=[]
charlieSort(x:xs)=charlieSort(filter(cmpLen(>)x)xs)+[x]++
charlieSort(filter(cmpLen)(我在第8章,所以我不是老手,但我更喜欢
areListsEqual x:xs y:ys = (x == y) && (areListsEqual xs ys)
areListsEqual [] [] = True
areListsEqual _ _ = False
这似乎更符合哈斯克尔的风格
同样地
charlieSort [] = []
charlieSort (x:[]) = [x]
charlieSort (x1:x2:xs) = blah blah
swapPairIfNeed按原样工作,因为您只使用first和second作为其参数(按该顺序)调用它,但您可能是指
swapPairIfNeed a b = if (length a >= length b)
then [b, a]
else [a, b]
事实上,我更喜欢charlieSort的第三个案例
charlieSort (x1:x2:xs) = if not (areListsEqual x1:x2:xs wip)
then charlieSort wip
else wip
where swapPairIfNeeded a b = if (length a >= length b)
then (b, a)
else (a, b)
wip = f (swapPairIfNeeded first second)
f (a, b) = a : (charlieSort b:xs)
我想第三章已经涵盖了所有这些
现在,让我们检查一下算法。即使使用气泡排序,排序后也不需要检查整个列表。相反,如果需要,我们可以交换前两个元素,然后对列表的尾部排序。如果头部比排序后尾部的头部短,我们就完成了
charlieSort (x1:x2:xs) = if (length a <= length (head sortedTail))
then a : sortedTail
else charlieSort (a : sortedTail)
where sortedTail = charlieSort (b:xs)
(a, b) = if (length x1 >= length x2)
then (x2, x1)
else (x1, x2)
charlieSort(x1:x2:xs)=if(长度a=长度x2)
然后(x2,x1)
else(x1,x2)
我首先要开始使用模式匹配
areListsEqual :: Eq a => [a] -> [a] -> Bool
areListsEqual [ ] [ ] = True
areListsEqual [ ] _ = False
areListsEqual _ [ ] = False
areListsEqual (x:xs) (y:ys) = x == y && areListsEqual xs ys
请注意,当避免使用头部
和尾部
时,这将更具可读性
charlieSort :: Eq a => [[a]] -> [[a]]
charlieSort [ ] = []
charlieSort [x ] = [x]
charlieSort xs@(first:second:theRest)
| areListsEqual xs wip = wip
| otherwise = charlieSort wip
where
swapPairIfNeeded a b
| length a >= length b = [second,first]
| otherwise = [first,second]
modifiedPair = swapPairIfNeeded first second
wip = take 1 modifiedPair ++ charlieSort (drop 1 modifiedPair ++ theRest)
我将if
-然后
-else
更改为一个保护,以略微提高可读性
(YMMV)。而不是检查列表中是否至少有两个具有
调用length
我们使用模式匹配,这也允许我们命名
第一个
,第二个
,第二个
直接返回。name@pattern
模式
根据模式匹配输入
,并将整个输入命名为name
现在,我想避免使用take
和drop
来提取这两个元素
的modifiedPair
,因此最后两行更改为
[shorter,longer] = swapPairIfNeeded first second
wip = [shorter] ++ charlieSort ([longer] ++ theRest)
在那里你可以把最后一行写成
wip = shorter : charlieSort (longer : theRest)
如果您愿意。但是为什么swapairifneeded
应该返回较短的和
列表中第一个
和第二个
列表的较长
?为什么不使用
成对的
swapPairIfNeeded a b
| length a >= length b = (second,first)
| otherwise = (first,second)
(shorter,longer) = swapPairIfNeeded first second
?在大多数情况下,最好将元组用于固定数量的
值(可能是不同类型的),并使用列表来显示可变数量的
值(必须是相同的类型)。但奇怪的是
swapPairIfNeeded
比较其参数a
和b
,然后返回
first
和second
无论如何。在这种情况下,不要让它返回a
和b
成对,我将删除swapPairIfNeeded
:
(shorter,longer)
| length first >= length second = (second,first)
| otherwise = (first,second)
将的主体“展开”到的定义中
(短,长)
现在charlieSort的代码如下
charlieSort :: Eq a => [[a]] -> [[a]]
charlieSort [ ] = []
charlieSort [x ] = [x]
charlieSort xs@(first:second:theRest)
| areListsEqual xs wip = wip
| otherwise = charlieSort wip
where
(shorter,longer)
| length first >= length second = (second,first)
| otherwise = (first,second)
wip = shorter : charlieSort (longer : theRest)
最后,我应该指出,charlieSort
并没有真正实现
冒泡排序,因为对charlieSort
的递归调用
让一个“气泡”沿着列表传递,但也要对列表进行完全排序
longer:rest
,以便在该递归调用之后必须执行的所有操作
(在返回一个“升级”之前)可能会将shorter
过滤到其
正确的位置。您声称冒泡排序是最简单的排序算法,但这里的情况并非如此。冒泡排序适用于数组,在数组中可以线性索引到数组中。适用于Haskell的链表
wsort :: [[a]] -> [[a]]
wsort [] = []
wsort [x] = [x]
wsort (x:xs) = winsert x (wsort xs)
areListsEqual [] [] = True
areListsEqual (x:xs) (y:ys) = x == y && areListsEqual xs ys
areListsEqual _ _ = False
charlieSort [] = []
charlieSort [x] = x
charlieSort (x1:x2:xs) = if ...