-1

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

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”提到的包装/打开的东西。但我不知道。也许另一个提示?:/

4

2 回答 2

1

我看不到如何Tree a变成半群(除非必须考虑到某些事情)。

对于新Sum a类型,您需要要求a是 class 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实例将需要类似的包装/解包代码。


进一步提示:要将 a 解包Sum a 成 ana您可以使用该函数

unSum :: Sum a -> a

将 an 包装aSum 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)
于 2014-07-03T20:14:21.623 回答
0

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

于 2014-07-04T18:11:02.037 回答