Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.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
Sorting 不使用Prelude以外的任何东西对文件系统数据进行排序_Sorting_Haskell - Fatal编程技术网

Sorting 不使用Prelude以外的任何东西对文件系统数据进行排序

Sorting 不使用Prelude以外的任何东西对文件系统数据进行排序,sorting,haskell,Sorting,Haskell,我通过以下方式定义了一种称为FS的数据类型: type Name= String data Ext where { Txt::Ext ; Mp3::Ext ; Jar::Ext ; Doc::Ext ; Hs::Ext } deriving (Eq, Show) data FS where { A :: (Name,Ext) -> FS; Dir :: Name-> [FS] -> FS } deriving (Eq, Show

我通过以下方式定义了一种称为FS的数据类型:

type Name= String

data Ext where { Txt::Ext ; Mp3::Ext ; Jar::Ext ; Doc::Ext ; Hs::Ext }
  deriving (Eq, Show)


data FS where {  A :: (Name,Ext) -> FS;
                 Dir :: Name-> [FS] -> FS }
  deriving (Eq, Show)
(A代表文件,Dir代表目录)
我试图创建一个函数,给定一个
FS
(目录),它返回相同的
FS
,但在所有级别按字母顺序排列,我目前的尝试如下:

orderFS :: FS-> FS
orderFS (Dir x y) = Dir x (map orderFS (sort y));
orderFS (A (x,y)) = A (x,y);
我唯一缺少的是一个名为“sort”的函数,它接受一个
[FS]
,并按
名称
字段的字母顺序返回它。
我读到有一些函数,比如从
Data.List
排序,可以提供帮助,但我必须在不使用任何其他函数的情况下执行此操作,而不是使用
Prelude


那么我应该如何实现这样的功能呢?提前感谢

我不相信Prelude中有任何排序功能,但像
Data.List这样的模块中没有。请注意,
Data.List
位于GHC的基本包中,因此基本上在
Prelude
可用的任何情况下,我都可以想象
Data.List
也可以——您不需要下载/包含任何其他包来使用它

也就是说,如果您确实想编写自己的排序函数,那么最好采用现有的简单排序算法并使用它。在Haskell中有非常简洁/简单的编写快速排序和合并排序的方法,尽管显而易见的实现有时并不像您预期的那样具有完全相同的性能特征。例如,Merge-sort具有大致相同的渐近性,但将列表分成两部分实际上需要一些时间,因为列表是单独链接的,因此必须遍历其中的一半才能将其拆分。但是,它可以是一个非常好的短函数,看起来非常像算法,并且可能值得作为一个学习练习来做

另外,我注意到您正在将
Ext
FS
类型定义为GADT,我并不确定其动机;我建议使用非GADT语法,这在本例中要简单得多:

type Name = String
data Ext = Txt | Mp3 | Jar | Doc | Hs deriving (Eq, Show)
data FS = A Name Ext | Dir Name [FS] deriving (Eq, Show)
为了按名称对它们进行排序,可能需要编写一个简单的访问器函数来获取FS的名称:

name :: FS -> Name
name (A   n _) = n
name (Dir n _) = n
另一种方法是找出这两种情况的共同点(名称):

data FS = NamedFS { name :: Name, fs :: UnnamedFS }
data UnnamedFS = A Ext | Dir [FS]
这里的第一个条目使用记录语法,其中包括自动生成
name::FS->name
访问器以及
FS::FS->UnnamedFS

对于实际排序,它看起来很像合并排序的算法描述。首先,让我们编写一个函数将列表一分为二:

split :: [a] -> ([a], [a])
split xs = splitAt (length xs `div` 2) xs
我们还需要一个函数来合并两个排序列表:

merge :: Ord a => [a] -> [a] -> [a]
merge [] x = x
merge x [] = x
merge (x:xs) (y:ys) | x < y     = x:merge xs (y:ys)
                    | otherwise = y:merge (x:xs) ys
现在,我们可以像往常一样实现mergesort:

mergeSort :: (a -> a -> Bool) -> [a] -> [a]
mergeSort _ []  = []
mergeSort _ [x] = [x]
mergeSort f l   = merge f (mergeSort f left) (mergeSort f right)
  where (left, right) = split l
就这样说吧:

-- fss is some [FS]
mergeSort (\x y -> name x < name y) fss

我不相信Prelude中有任何排序功能,但像
Data.List
这样的模块中没有。请注意,
Data.List
位于GHC的基本包中,因此基本上在
Prelude
可用的任何情况下,我都可以想象
Data.List
也可以——您不需要下载/包含任何其他包来使用它

也就是说,如果您确实想编写自己的排序函数,那么最好采用现有的简单排序算法并使用它。在Haskell中有非常简洁/简单的编写快速排序和合并排序的方法,尽管显而易见的实现有时并不像您预期的那样具有完全相同的性能特征。例如,Merge-sort具有大致相同的渐近性,但将列表分成两部分实际上需要一些时间,因为列表是单独链接的,因此必须遍历其中的一半才能将其拆分。但是,它可以是一个非常好的短函数,看起来非常像算法,并且可能值得作为一个学习练习来做

另外,我注意到您正在将
Ext
FS
类型定义为GADT,我并不确定其动机;我建议使用非GADT语法,这在本例中要简单得多:

type Name = String
data Ext = Txt | Mp3 | Jar | Doc | Hs deriving (Eq, Show)
data FS = A Name Ext | Dir Name [FS] deriving (Eq, Show)
为了按名称对它们进行排序,可能需要编写一个简单的访问器函数来获取FS的名称:

name :: FS -> Name
name (A   n _) = n
name (Dir n _) = n
另一种方法是找出这两种情况的共同点(名称):

data FS = NamedFS { name :: Name, fs :: UnnamedFS }
data UnnamedFS = A Ext | Dir [FS]
这里的第一个条目使用记录语法,其中包括自动生成
name::FS->name
访问器以及
FS::FS->UnnamedFS

对于实际排序,它看起来很像合并排序的算法描述。首先,让我们编写一个函数将列表一分为二:

split :: [a] -> ([a], [a])
split xs = splitAt (length xs `div` 2) xs
我们还需要一个函数来合并两个排序列表:

merge :: Ord a => [a] -> [a] -> [a]
merge [] x = x
merge x [] = x
merge (x:xs) (y:ys) | x < y     = x:merge xs (y:ys)
                    | otherwise = y:merge (x:xs) ys
现在,我们可以像往常一样实现mergesort:

mergeSort :: (a -> a -> Bool) -> [a] -> [a]
mergeSort _ []  = []
mergeSort _ [x] = [x]
mergeSort f l   = merge f (mergeSort f left) (mergeSort f right)
  where (left, right) = split l
就这样说吧:

-- fss is some [FS]
mergeSort (\x y -> name x < name y) fss

Data.List
中可以帮助您的函数是 这与函数
getName::FS->Name
一起允许您通过比较
Name
s进行排序

如果无法使用
Data.List
中的函数,则必须自己实现排序算法(其中有许多可供选择)。一个例子是本书中实现的“快速排序”:


Data.List
中可以帮助您的函数是 这与函数
getName::FS->Name
一起允许您通过比较
Name
s进行排序

如果无法使用
Data.List
中的函数,则必须自己实现排序算法(其中有许多可供选择)。一个例子是本书中实现的“快速排序”:


在我看来,Haskell中最自然的列表排序函数是自下而上的mergesort(Peter Amidon的答案给出了自上而下的mergesort)。假设您从列表开始

[25,1,22,2,10,8,6,20,13,28,5,3,11]
第一步是将列表转换为列表列表。傻瓜
[[1,2,6,8,10,20,22,25],[3,5,11,13,28]]
[[1,2,3,5,6,8,10,11,13,20,22,25,28]]
infixr 5 :::
data LL a = ![a] ::: LL a | Nil
breakUp :: (a -> a -> Ordering) -> [a] -> LL a
breakUp _cmp [] = Nil
breakUp _cmp xs@[a] = xs ::: Nil
breakUp cmp (x1 : x2 : xs)
  | GT <- cmp x1 x2 = [x2,x1] ::: breakUp cmp xs
  | otherwise = [x1,x2] ::: breakUp cmp xs
merge :: (a -> a -> Ordering)
      -> [a] -> [a] -> [a]
merge _cmp [] ys = ys
merge _cmp xs [] = xs
merge cmp xss@(x:xs) yss@(y:ys)
  | GT <- cmp x y = y : merge cmp xss ys
  | otherwise = x : merge cmp xs yss
mergePairwise :: (a -> a -> Ordering)
              -> LL a -> LL a
mergePairwise _cmp Nil = Nil
mergePairwise _cmp xs@(_ ::: Nil) = xs
mergePairwise cmp (xs1 ::: xs2 ::: xss)
  = merge cmp xs1 xs2 ::: mergePairwise cmp xss
mergeAll :: (a -> a -> Ordering)
         -> LL a -> [a]
mergeAll _cmp Nil = []
mergeAll _cmp (xs ::: Nil) = xs
mergeAll cmp xss = mergeAll cmp (mergePairwise cmp xss)
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
sortBy cmp = mergeAll cmp . breakUp cmp

sort :: Ord a => [a] -> [a]
sort = sortBy compare
data NonEmpty a = a :| [a]
data LL a = (:::) {-# UNPACK #-} !(NonEmpty a) (LL a) | Nil