Cha*_*ers 7 sorting haskell functional-programming
我正在通过Real World Haskell工作,目前正在进行第3章末尾的练习.
我采取了一种不同寻常的方法:尽管我知道有些语言功能尚未涵盖,但这对我有帮助,我只是尝试使用他们明确涵盖的内容进行这些练习.为什么?真的很有趣.感觉它强迫我给我的大脑一些额外的递归练习.
所以我刚刚完成了如下所示的练习:"创建一个函数,根据每个子列表的长度对列表列表进行排序.(您可能需要查看Data.List模块中的sortBy函数.)"
现在,他们提出了关于Data.List模块的提示.但是他们没有说出可以找到参考文档的地方,关于如何导入东西等等.所以我决定推出自己的排序,看看我是否可以做到.我使用冒泡排序,因为它是最简单的算法.
结果如下.我想让你的Haskell专家对它进行批评......但是请注意以下几点: 如果你建议改进,请将它们建立在真实世界Haskell第3章所涵盖的语言特性之上(或者你猜测那些特性)可能没有找到它的麻烦).我知道有很多令人敬畏的语言功能等着我,这将让我更好地编写代码,但是现在具体的挑战是使用到目前为止涵盖的"原始"功能来实现.
我确定有些情况下我会绕到我的肩膀以划伤我的肘部,当递归和模式匹配可以为我做更多事情时,我使用显式控制流的情况等等.我确信代码可以是更短,更可读.我打赌有一些我不知道的好习惯,可以用于我限制自己的原始语言功能.这些都是我喜欢的提示.
这可能是我用任何语言引以为傲的最丑陋的代码(至少,我记得).我用函数式语言首次尝试了"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)
Run Code Online (Sandbox Code Playgroud)
小智 6
我首先要开始使用模式匹配.
areListsEqual :: Eq a => [a] -> [a] -> Bool
areListsEqual [ ] [ ] = True
areListsEqual [ ] _ = False
areListsEqual _ [ ] = False
areListsEqual (x:xs) (y:ys) = x == y && areListsEqual xs ys
Run Code Online (Sandbox Code Playgroud)
注意这是多么可读,何时head和tail避免.
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)
Run Code Online (Sandbox Code Playgroud)
我改变了if- then- else到后卫略有改善可读性(因人而异).取而代之的检查列表有一个电话至少两个元素,length我们使用模式匹配,这也让我们的名字
first,second,theRest直接.该name @ pattern模式既对输入匹配pattern 和名称整个输入作为name.
现在,我想避免使用take和drop提取两个元素modifiedPair,所以最后两行被改为
[shorter,longer] = swapPairIfNeeded first second
wip = [shorter] ++ charlieSort ([longer] ++ theRest)
Run Code Online (Sandbox Code Playgroud)
你可以写最后一行的地方
wip = shorter : charlieSort (longer : theRest)
Run Code Online (Sandbox Code Playgroud)
如果你愿意的话.但是,为什么要swapPairIfNeeded返回shorter和longer的first和second列表的列表?为什么不使用像这样的一对
swapPairIfNeeded a b
| length a >= length b = (second,first)
| otherwise = (first,second)
(shorter,longer) = swapPairIfNeeded first second
Run Code Online (Sandbox Code Playgroud)
?在大多数情况下,最好将元组用于固定数量的值(可能是不同类型),并将列表用于可变数量的值(必须具有相同类型).但似乎奇怪的是,
swapPairIfNeeded相比较它的参数a和b,但随后返回
first并second无妨.在这种情况下,我将完全删除而不是让它返回a
并b成对出现swapPairIfNeeded:
(shorter,longer)
| length first >= length second = (second,first)
| otherwise = (first,second)
Run Code Online (Sandbox Code Playgroud)
"展开"的身体swapPairIfNeeded进入了定义
(shorter,longer).
所以现在的代码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)
Run Code Online (Sandbox Code Playgroud)
最后,我应该注意到它charlieSort并没有真正实现冒泡排序,因为递归调用charlieSort不仅会使列表中的一个"冒泡"传递,而且还会对列表进行完全排序
longer : theRest,以便所有必须完成的操作在这个递归调用之后(在返回一个"升级"之前)可能会渗透shorter到其合法的位置.
| 归档时间: |
|
| 查看次数: |
770 次 |
| 最近记录: |