Haskell - 创建类的实例(如何正确执行?)

时间:2014-07-03 19:18:53

标签: haskell tree instance instances hackage

我在“了解你一个haskell”中阅读了关于该主题的章节,并尝试在不同的网站上找到一些提示 - 但仍然无法解决以下任务。 我m a haskell newbie (6 weeks of "experience") and it是我第一次使用实例。 所以这是任务,我的代码必须通过HUnit测试和结束。我试图实现这些实例,但似乎我错过了那里的东西。希望你能帮我! THX

module SemiGroup where

{-

A type class 'SemiGroup' is given. It has exactly one method: a binary operation
called '(<>)'. Also a data type 'Tree' a newtype 'Sum' and a newtype 'Max' are
given. Make them instances of the 'SemiGroup' class.
The 'Tree' instance should build a 'Branch' of the given left and right side.
The 'Sum' instance should take the sum of its given left and right side. You need
a 'Num' constraint for that.
The 'Max' instance should take the maximum of its given left and right side. You
also need a constraint for that but you have to figure out yourself which one.
This module is not going to compile until you add the missing instances.

-}

import Test.HUnit (runTestTT,Test(TestLabel,TestList),(~?=))


-- | A semigroup has a binary operation.
class SemiGroup a where
    (<>) :: a -> a -> a

-- Leaf = Blatt, Branch = Ast
-- | A binary tree data type.
data Tree a = Leaf a
            | Branch (Tree a) (Tree a)
                deriving (Eq,Show)


-- | A newtype for taking the sum.
newtype Sum a = Sum {unSum :: a}


-- | A newtype for taking the maximum.
newtype Max a = Max {unMax :: a}

instance SemiGroup Tree where
    (<>) x y = ((x) (y))

instance SemiGroup (Num Sum) where
    (<>) x y = x+y

instance SemiGroup (Eq Max) where
    (<>) x y = if x>y then x else y



-- | Tests the implementation of the 'SemiGroup' instances.
main :: IO ()
main = do
    testresults <- runTestTT tests
    print testresults

-- | List of tests for the 'SemiGroup' instances.
tests :: Test
tests = TestLabel "SemiGroupTests" (TestList [
    Leaf "Hello" <> Leaf "Friend" ~?= Branch (Leaf "Hello") (Leaf "Friend"),
    unSum (Sum 4 <> Sum 8) ~?= 12,
    unMax (Max 8 <> Max 4) ~?= 8])

我尝试过类似的事情:

class SemiGroup a where
    (<>) :: a -> a -> a

-- Leaf = Blatt, Branch = Ast
-- | A binary tree data type.
data Tree a = Leaf a
            | Branch (Tree a) (Tree a)
                deriving (Eq,Show)


-- | A newtype for taking the sum.
newtype Sum a = Sum {unSum :: a}


-- | A newtype for taking the maximum.
newtype Max a = Max {unMax :: a}

instance SemiGroup Tree where
    x <> y = Branch x y

instance Num a => SemiGroup (Sum a) where
    x <> y = x+y

instance Eq a => SemiGroup (Max a) where
    x <> y = if x>y then x else y

但还有一些失败!至少是“chi”提到的包裹/展开的东西。但我不知道。也许是另一个暗示? :/

2 个答案:

答案 0 :(得分:1)

我没有看到如何将Tree a转变为半群(除非必须将其视为某种东西)。

对于Sum a newtype,您需要要求a属于Num类。然后,您需要围绕值包装/解包Sum构造函数,以便:1)您将两个Sum a,2)转换为两个a,这是一个合适的类型其中+已定义,3)您对它们求和,4)您将结果转换回Sum a

您可以尝试从

开始自己编写以上代码
instance Num a => Semigroup (Sum a) where
   x <> y = ...   -- Here both x and y have type (Sum a)

Max a实例将需要类似的包装/解包代码。


进一步提示:要将Sum a展开到a,您可以使用该功能

unSum :: Sum a -> a

a打包成Sum a,而不是

Sum :: a -> Sum a

请注意,Sum, unSum声明已经隐式定义了两个函数newtype,因此您不必定义它们(您已经这样做了)。

或者,您可以使用模式匹配来展开您的值。而不是定义

x <> y = ... -- x,y have type Sum a (they are wrapped)

你可以写

Sum x <> Sum y = ...   -- x,y have type a (they are unwrapped)

答案 1 :(得分:0)

注意类型。无论是手动还是在GHCi的帮助下,找出你正在编写的函数的类型 - 你会发现它们与类型类实例所需的类型不匹配。您将使用包装和展开来调整类型,直到它们工作。