Haskell:多态函数解释

时间:2010-09-20 02:21:33

标签: haskell

所以我得到了这个

intCMP :: Int -> Int -> Ordering
intCMP a b | a == b = EQ
     | a < b = LT
     | otherwise = GT

intCMPRev :: Int -> Int -> Ordering
intCMPRev a b | a == b = EQ
     | a < b = GT
        | otherwise = LT

floatCMP :: Float -> Float -> Ordering
floatCMP a b | a == b = EQ
       | a < b = LT
       | otherwise = GT

我需要写这个函数

sort3 :: Ord a => (a -> a-> Ordering) -> [a] -> [a]
sort3 cmp xs =

通过比较,将对3个或更少的元素进行排序。没有递归。我想知道这是如何工作的传递说intCMP。你为什么要把它传递给sort函数?在排序和返回排序列表时它是否有用?我不确定如何在没有任何递归调用的情况下手动进行比较,所以我只是想更好地理解它。

我正在考虑进行3次比较,然后将元素移动到列表中的某个位置,但我真的不知道我怎么能在haskell中做到这一点。关于如何开始这个的任何线索都会很棒。也许是某种模式?

感谢。

3 个答案:

答案 0 :(得分:3)

对问题第一部分的部分回答:

intCMP传递给sort3可让您控制排序的完成方式。据推测,sort3 intCMP [7,3,6]将返回[3,6,7],而sort3 intCMPRev [7,3,6]将返回[7,6,3]。你甚至可以制作自己奇怪的排序函数,比如首先是所有偶数,然后是所有奇数排序函数,如下所示:

intCMPWeird :: Int -> Int -> Ordering
intCMPWeird a b
    | even a && even b = intCMP a b -- even numbers compare as usual
    | odd a  && odd b  = intCMPRev a b  -- odd numbers compare in reverse order
    | even a && odd b  = LT -- evens are all 'smaller' than odds
    | odd a  && even b = GT -- odds are all 'greater' than evens

使用此功能,sort3 intCMPWeird [7,3,6]应该提供[6,7,3]

intCMP...函数之一传递给sort3时,在类型检查期间会发生什么(简而言之),编译器首先尝试匹配sort3的类型参数(a -> a -> Ordering)使用提供的值(Int -> Int -> Ordering)的类型,并通过使a等于Int成功完成此操作。然后需要检查Ord a是否满足约束Int,这有效!最后,编译器可以确定sort3 intCMP的类型是[Int] -> [Int]。同样,sort3 floatCMP的类型为[Float] -> [Float]

我不能100%确定为什么Ord约束的类型为sort3,因为您可以从传入的比较函数中获取所需的信息 - 你确定你已经输入正确吗?

编辑:提示如何使用where子句来获得可读的定义,你仍然需要填写一些内容并添加更多的子句:

sort3 cmp [x,y,z] 
    | x <= y && somethingElse1 = listWithXyzInSomeOrder1
    | x <= z && somethingElse2 = listWithXyzInSomeOrder2
        where a <= b = cmp a b /= GT

答案 1 :(得分:2)

这是一个提示:

  • 如果您有一个空列表,显然排序结果将是一个空列表。
  • 同样,只有一个元素的列表也已经排序。
  • 如果您有2个元素的列表,则只有2个可能的排序,因此您的函数只有2个可能的返回值。
  • 如果您有一个3元素列表,则有6种可能的排序(第一个元素可以是3个输入元素中的1个,下一个元素可以是剩下的2个中的1个,最后一个元素只留下1个选项)。您可以轻松记下6种不同的条件,使您返回3个元素的6个可能列表中的1个。

答案 2 :(得分:0)

你不是在编写多态函数(根据定义,它是一个需要多种类型的函数)。先写一个:

cmp :: Ord a => a -> a -> Ordering
cmp x y =
  | x == y = EQ
  | x < y  = LT
  | otherwise = GT

您将以上述方式编写比较排序中元素的功能,而不必是排序的一部分。对列表进行排序本质上是递归的:至少长度是未定义的。要实现这一点,只需编写一个可以使用自定义比较的排序,这里是quick sort,尽管您可以编写不同类型的排序。

sort3 :: (Ord a) => [a] -> [a]  
sort3 [] = []  
sort3 (x:xs) =   
    let smallerSorted = filter (<=)
        biggerSorted = filter(>)
    in  smallerSorted ++ [x] ++ biggerSorted