如何解决Haskell中的这个模棱两可的类型变量错误?

问题描述 投票:0回答:1

在几个模糊类型变量错误问题中,我找不到问题的答案。目前我正在尝试让我找到的这段代码工作。(https:/gist.github.comkirelagin3886243。)

我的代码:

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 ambiguous
1个回答
3
投票

在第17行,错误指向你的地方。

let codeMaphTest = buildCodemap treeTest

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

编译器不知道。没有地方可以收集这些信息。它是模棱两可的。

而这正是编译器告诉你的。"歧义型变量".

解决这个问题的一个方法是提供一个类型注释(顺便说一下,和错误信息说的一模一样)。

let codeMaphTest :: Codemap Int = buildCodemap treeTest

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


1
投票

你的代码确实是含糊不清的。buildCodemap treeTest 有一个多态类型 Bits a => Codemap a因此,它可以作为一个 Codemap Int, a Codemap Bool的实例,甚至可以作为另一种类型,如果你定义了更多的 Bits.

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

你可以选择 a 在定义点。

let codeMaphTest :: Codemap Int
    codeMaphTest = buildCodemap treeTest

或者,你也可以选择 a 后面你用它

print (codeMaphTest :: Codemap Int)
© www.soinside.com 2019 - 2024. All rights reserved.