Haskell-如何使用函数体中类型签名中指定的类型参数?

时间:2019-03-19 21:46:09

标签: haskell

我有以下堆排序代码。

heapsort :: (Ord a) => [a] -> [a]
heapsort xs = Heap.toList (Heap.fromList $ xs :: Heap.MinHeap a)

这不会编译并出现以下错误-

mergeLists.hs:32:28: error:
    • Couldn't match type ‘a1’ with ‘a’
      ‘a1’ is a rigid type variable bound by
        an expression type signature:
          forall a1. Heap.MinHeap a1
        at mergeLists.hs:32:50-63
      ‘a’ is a rigid type variable bound by
        the type signature for:
          heapsort :: forall a. Ord a => [a] -> [a]
        at mergeLists.hs:31:1-33
      Expected type: Heap.MinHeap a1
        Actual type: Heap.Heap Heap.MinPolicy a
    • In the first argument of ‘Heap.toList’, namely
        ‘(Heap.fromList $ xs :: Heap.MinHeap a)’
      In the expression:
        Heap.toList (Heap.fromList $ xs :: Heap.MinHeap a)
      In an equation for ‘heapsort’:
          heapsort xs = Heap.toList (Heap.fromList $ xs :: Heap.MinHeap a)
    • Relevant bindings include
        xs :: [a] (bound at mergeLists.hs:32:10)
        heapsort :: [a] -> [a] (bound at mergeLists.hs:32:1)
   |
32 | heapsort xs = Heap.toList (Heap.fromList $ xs :: Heap.MinHeap a)
   |                            ^^^^^^^^^^^^^^^^^^

我认为这是因为函数主体中的a与函数签名中的a不同。例如,如果我启用部分类型签名并执行

heapsort :: (Ord a) => [a] -> [a]
heapsort xs = Heap.toList (Heap.fromList $ xs :: Heap.MinHeap _)

代码在编译时显示以下警告(但没有错误)。

λ> :load mergeLists
[1 of 1] Compiling Main             ( mergeLists.hs, interpreted )

mergeLists.hs:32:63: warning: [-Wpartial-type-signatures]
    • Found type wildcard ‘_’ standing for ‘a’
      Where: ‘a’ is a rigid type variable bound by
               the type signature for:
                 heapsort :: forall a. Ord a => [a] -> [a]
               at mergeLists.hs:31:1-33
    • In an expression type signature: Heap.MinHeap _
      In the first argument of ‘Heap.toList’, namely
        ‘(Heap.fromList $ xs :: Heap.MinHeap _)’
      In the expression:
        Heap.toList (Heap.fromList $ xs :: Heap.MinHeap _)
    • Relevant bindings include
        xs :: [a] (bound at mergeLists.hs:32:10)
        heapsort :: [a] -> [a] (bound at mergeLists.hs:32:1)
   |
32 | heapsort xs = Heap.toList (Heap.fromList $ xs :: Heap.MinHeap _)
   |                                                               ^
Ok, one module loaded.

那么,如何使用部分类型签名功能来实现此目的?通常,如何在函数定义中使用来自函数签名的类型参数?

1 个答案:

答案 0 :(得分:2)

如注释中所示,您可以使用ScopedTypeVariables扩展名来执行此操作。这使函数主体中使用的类型变量可以引用函数签名中使用的相同变量,但是您必须使用forall关键字“选择加入”:

{-# LANGUAGE ScopedTypeVariables #-}

import qualified Data.Heap as Heap

heapsort :: forall a . (Ord a) => [a] -> [a]
heapsort xs = Heap.toList (Heap.fromList xs :: Heap.MinHeap a)

在这种特定情况下,您可以通过将Heap.fromListHeap.toList专用于MinHeap来进行扩展。例如:

heapsort' :: (Ord a) => [a] -> [a]
heapsort' = Heap.toList . minHeapFromList
  where minHeapFromList :: (Ord a) => [a] -> Heap.MinHeap a
        minHeapFromList = Heap.fromList

在这里,aheapsort'的签名中的minHeapFromList类型变量是不相关的,但是,当然,它们在heapsort'的正文中是统一的。