简体   繁体   English

F#中的Quicksort - 语法问题

[英]Quicksort in F# - syntax question

I have a simple f# quick sort function defined as: 我有一个简单的f#快速排序功能,定义如下:

let rec qsort(xs:List<int>) =

let smaller = xs |> List.filter(fun e -> e < xs.Head)
let larger = xs |> List.filter(fun e -> e > xs.Head)
match xs with
| [] -> []
| _ -> qsort(smaller)@[xs.Head]@qsort(larger)

Is there a way in f# to write it more like Haskell: 在f#中是否有一种方法可以像Haskell一样编写它:

qsort       :: [Int] -> [Int]
qsort []     = []
qsort (x:xs) =
qsort smaller ++ [x] ++ qsort larger
where
  smaller = [a | a <- xs, a <= x]
  larger  = [b | b <- xs, b >= x]

I know the f# algorithm is missing a <= and >=. 我知道f#算法缺少<=和> =。 The question is more about syntax/readibility. 问题更多的是语法/可读性。

Thanks. 谢谢。

This is the most 'Haskellian' way I can think of, the only thing missing is being able to declare smaller/larger as a 'where' clause: 这是我能想到的最“Haskellian”方式,唯一缺少的是能够将较小/较大的声明声明为'where'子句:

let rec qsort:int list -> int list = function
    | [] -> []
    | x::xs -> let smaller = [for a in xs do if a<=x then yield a]
               let larger =  [for b in xs do if b>x then yield b]
               qsort smaller @ [x] @ qsort larger

I know it's not part of your question, but I'd use List.partition to split the list in smaller/larger in a single pass: 我知道这不是你问题的一部分,但是我会使用List.partition在一次传递中将列表拆分为更小/更大:

let rec qsort = function
    | [] -> []
    | x::xs -> let smaller,larger = List.partition (fun y -> y<=x) xs
               qsort smaller @ [x] @ qsort larger

You want your second match clause to be x :: xs , and to use the @ (append) operator where your Haskell example uses ++: 您希望第二个匹配子句为x :: xs ,并使用@(append)运算符,其中Haskell示例使用++:

let rec qsort xs =
  match xs with
  | [] -> []
  | x :: xs ->
      let smaller = qsort (xs |> List.filter(fun e -> e <= x))
      let larger  = qsort (xs |> List.filter(fun e -> e >  x))
      smaller @ [x] @ larger

It's not quite the same as the Haskell definition by cases syntax, but hopefully similar enough for you! 它与案例语法中的Haskell定义并不完全相同,但希望对您来说足够相似!

This seems to be as concise as it can get (combining the ideas from other answers, and using currying for operators): 这似乎是尽可能简洁(结合其他答案的想法,并为运营商使用currying):

let rec qsort = function
| [] -> []
| (x:int) :: xs ->
    let smaller = List.filter ((>=) x) xs
    let larger  = List.filter ((<) x) xs
    qsort smaller @ [x] @ qsort larger

...Or you could make a tail recursive qsort by using CPS: ...或者你可以使用CPS做一个尾递归qsort:

let qSort lst = 
   let rec qs l cont = 
       match l with
       | []      -> cont []
       | (x::xs) -> qs (List.filter (fun e -> e <= x) xs) (fun smaller ->
                    qs (List.filter (fun e -> e >  x) xs) (fun larger  ->
                        smaller @ (x :: larger) |> cont))
   qs lst id

haskell 'where' syntax, which lets you use the name of a function before its definition, kind of maps to f# 'let rec ... and' haskell'where'语法,它允许你在定义之前使用函数的名称,一种映射到f#'let rec ...和'

let qsort xs =
    let rec sort xs = 
        match ls with
        |[] -> ....
        |h::t -> (smaller t) @ h @ (larger t)

    and smaller ls =    //the 'and' lets you define the 
                        //  function after where it is used, 
                        //  like with 'where' in haskell
         ... define smaller in terms of sort
    and larger ls =
         ... same

    sort xs

Don't forget that List has a partition method, so 不要忘记List有一个分区方法,所以

let rec quicksort ls =
    match ls with
    | [] -> []
    | h :: t -> let fore, aft = List.partition (fun i -> i < h) t
                (quicksort fore) @ (h :: quicksort aft)
let  rec QuickSort l =
        match   l with  
        |  []  ->  []
        |   _   ->  QuickSort([for e in l do if e < (List.head l) then yield e]) @[(List.head l)]@ QuickSort([for e in l do if e > (List.head l) then yield e])

I had done some analysis of sorting algorithms in F# a few years ago in a very imperative style; 几年前我以非常强制的方式对F#中的排序算法做了一些分析; I was trying to beat the .NET stock implementation, and managed to do so here . 我试图击败.NET股票实施,并设法在这里这样做。 Went to make the following reply to myself today, but FPish won't let me create an account. 我今天要回复自己,但是FPish不会让我创建一个帐户。 Argh! 哎呀! Gotta make my post somewhere, and here's as good as anywhere, lol... 要在某处做我的帖子,这里和其他地方一样好,哈哈...

While reading "Learn You a Haskell For Great Good" yesterday, the author set up an example for implementing quicksort. 在阅读昨天的“了解大好的Haskell”时,作者为实现快速排序设置了一个示例。 The description was quite clear and even before I got to the sample code, an elegant recursive solution (in Haskell) popped into my head. 描述非常清楚,甚至在我得到示例代码之前,一个优雅的递归解决方案(在Haskell中)突然出现在我脑海中。 Guess I had never really had an intuitive feel for how quicksort does its thing, because the trivial solution is quite easy, if not very efficient. 猜猜我从来没有真正对quicksort如何做到这一点有直觉,因为这个简单的解决方案非常简单,如果效率不高的话。

Here is my version in F#: 这是我在F#中的版本:

let rec quicksort = function
    | [] -> []
    | pivot :: xs ->
        (left pivot xs) @ pivot :: (right pivot xs)
and left pivot xs = quicksort [ for x in xs do if x <= pivot then yield x ]
and right pivot xs = quicksort [ for x in xs do if x > pivot then yield x ]

And, the equivalent Haskell (I like this one... clean!): 而且,等效的Haskell(我喜欢这个......干净!):

quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (pivot : xs) =
    left ++ pivot : right
    where
        left = quicksort [ x | x <- xs, x <= pivot ]
        right = quicksort [ x | x <- xs, x > pivot ]

For grins, here's another F# version (mostly tail-recursive) that's about 2x the speed of the trivial version. 对于笑话,这是另一个F#版本(主要是尾递归),大约是普通版本速度的2倍。 Haven't bothered to time this against my original post, though, so no idea how it stacks up to the mutable version in my OP on FPish.net (FSHub) from a few years ago... 尽管如此,还没有打算把它放在原来的帖子上,所以不知道它是如何在几年前在FPish.net(FSHub)上的OP中加入可变版本的......

let rec quicksort' xs =
    let rec aux pivot left right = function
        | [] -> (quicksort' left) @ pivot :: (quicksort' right)
        | x :: xs ->
            if x <= pivot then
                aux pivot (x :: left) right xs
            else
                aux pivot left (x::right) xs
    match xs with
    | [] -> []
    | x :: xs -> aux x [] [] xs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM