【问题标题】:How do I solve this ambiguous type variable error in Haskell?如何解决 Haskell 中的这种模棱两可的类型变量错误?
【发布时间】:2020-06-14 13:37:57
【问题描述】:

我在几个模棱两可的类型变量错误问题中找不到我的问题的答案。 我目前正在尝试获取我发现可以工作的代码。 (https://gist.github.com/kirelagin/3886243)

我的代码:

import Control.Arrow
import Data.List
import qualified Data.Map as M
import Data.Function

main = do
    putStrLn "Start test"
    let foo = "Hello World"
    let freqTest = freqList foo
    putStrLn "Frequentie list"
    print freqTest
    putStrLn "Done.."
    let treeTest = buildTree freqTest
    putStrLn "Huffman Tree"
    print treeTest
    putStrLn "Done.."
    let codeMaphTest = buildCodemap treeTest
    putStrLn "Codemap ding"
    -- print codeMaphTest
    putStrLn "Done.."




--This typeclass is supposed to make life _a bit_ easier.

class Eq a => Bits a where
    zer :: a
    one :: a

instance Bits Int where
    zer = 0
    one = 1

instance Bits Bool where
    zer = False
    one = True

-- Codemap is generated from a Huffman tree. It is used for fast encoding.

type Codemap a = M.Map Char [a]

-- Huffman tree is a simple binary tree. Each leaf contains a Char and its weight.
-- Fork (node with children) also has weight = sum of weights of its children.

data HTree  = Leaf Char Int
            | Fork HTree HTree Int
            deriving (Show)

weight :: HTree -> Int
weight (Leaf _ w)    = w
weight (Fork _ _ w)  = w

-- The only useful operation on Huffman trees is merging, that is we take
-- two trees and make them children of a new Fork-node.

merge t1 t2 = Fork t1 t2 (weight t1 + weight t2)

-- `freqList` is an utility function. It takes a string and produces a list
-- of pairs (character, number of occurences of this character in the string).

freqList :: String -> [(Char, Int)]
freqList = M.toList . M.fromListWith (+) . map (flip (,) 1)

-- `buildTree` builds a Huffman tree from a list of character frequencies
-- (obtained, for example, from `freqList` or elsewhere).
-- It sorts the list in ascending order by frequency, turns each (char, freq) pair
-- into a one-leaf tree and keeps merging two trees with the smallest frequencies
-- until only one tree is remaining.

buildTree :: [(Char, Int)] -> HTree
buildTree = bld . map (uncurry Leaf) . sortBy (compare `on` snd)
    where   bld (t:[]) = t
            bld (a:b:cs) = bld $ insertBy (compare `on` weight) (merge a b) cs

-- The next function traverses a Huffman tree to obtain a list of codes for
-- all characters and converts this list into a `Map`.

buildCodemap :: Bits a => HTree -> Codemap a
buildCodemap = M.fromList . buildCodelist
    where   buildCodelist (Leaf c w) = [(c, [])]
            buildCodelist (Fork l r w) = map (addBit zer) (buildCodelist l) ++ map (addBit one) (buildCodelist r)
                where addBit b = second (b :)

-- Simple functions to get a Huffman tree or a `Codemap` from a `String`.

stringTree :: String -> HTree
stringTree = buildTree . freqList

stringCodemap :: Bits a => String -> Codemap a
stringCodemap = buildCodemap . stringTree

-- Time to do the real encoding and decoding!

-- Encoding function just represents each character of a string by corresponding
-- sequence of `Bit`s.

encode :: Bits a => Codemap a -> String -> [a]
encode m = concat . map (m M.!)

encode' :: Bits a => HTree -> String -> [a]
encode' t = encode $ buildCodemap t

-- Decoding is a little trickier. We have to traverse the tree until
-- we reach a leaf which means we've just finished reading a sequence
-- of `Bit`s corresponding to a single character.
-- We keep doing this to process the whole list of `Bit`s.

decode :: Bits a => HTree -> [a] -> String
decode tree = dcd tree
    where   dcd (Leaf c _) [] = [c]
            dcd (Leaf c _) bs = c : dcd tree bs
            dcd (Fork l r _) (b:bs) = dcd (if b == zer then l else r) bs

输出:

huffmancompress.hs:17:24: error:
    * Ambiguous type variable `a0' arising from a use of `buildCodemap'
      prevents the constraint `(Bits a0)' from being solved.
      Relevant bindings include
        codeMaphTest :: Codemap a0 (bound at huffmancompress.hs:17:9)
      Probable fix: use a type annotation to specify what `a0' should be.
      These potential instances exist:
        instance Bits Bool -- Defined at huffmancompress.hs:35:10
        instance Bits Int -- Defined at huffmancompress.hs:31:10
    * In the expression: buildCodemap treeTest
      In an equation for `codeMaphTest':
          codeMaphTest = buildCodemap treeTest
      In the expression:
        do putStrLn "Start test"
           let foo = "Hello World"
           let freqTest = freqList foo
           putStrLn "Frequentie list"
           ....
   |
17 |     let codeMaphTest = buildCodemap treeTest
   |                        ^^^^^^^^^^^^^^^^^^^^^

我尝试了一些我在互联网上找到的东西,但说实话没有什么值得一提的。

也许你们中的任何人都可以帮助我!

【问题讨论】:

    标签: variables haskell typeerror huffman-code ambiguous


    【解决方案1】:

    在第 17 行,错误指向您:

    let codeMaphTest = buildCodemap treeTest
    

    codeMaphTest 是什么类型?应该是Codemap Int?还是Codemap String?或者,也许,Codemap Bool?函数buildCodemap 可以返回任何类型,只要它具有Bit 的实例即可。那么应该是什么类型呢?

    编译器不知道。无处可收集这些信息。模棱两可。

    这正是编译器告诉你的:“模糊类型变量”。

    解决此问题的一种方法是提供类型注释(顺便说一下,正如错误消息所说):

    let codeMaphTest :: Codemap Int = buildCodemap treeTest
    

    请注意,我选择Int 只是作为示例,因为我不知道您指的是哪种类型(在这方面我有点像编译器)。请替换您自己的类型 - 您真正想要的类型。

    【讨论】:

      【解决方案2】:

      您的代码确实模棱两可。 buildCodemap treeTest 有一个多态类型Bits a => Codemap a,因此它可以用作Codemap IntCodemap Bool,或者如果您定义了Bits 的更多实例,甚至可以用作另一种类型。

      这本身不是问题,但稍后你会尝试使用这个值(例如,打印它),所以我们真的需要选择一个具体的类型a

      您可以在定义点选择a

      let codeMaphTest :: Codemap Int
          codeMaphTest = buildCodemap treeTest
      

      或者,您也可以稍后选择a,在哪里使用它

      print (codeMaphTest :: Codemap Int)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-18
        • 2012-10-18
        • 1970-01-01
        • 2018-10-25
        • 2010-09-30
        • 2020-07-08
        • 1970-01-01
        相关资源
        最近更新 更多