簡體   English   中英

學習Haskell,了解數據結構

[英]Learning Haskell, understanding data structures

我實際上在學習Haskell,並且正在嘗試制作一個簡單的FizzBu​​zz Kata。

這個想法是將一個數字列表作為輸入,並產生一個數字列表。 遵循以下規則的字符串:

  • fizzBu​​zz :: [StringInt]-> [StringInt]
  • 每3的倍數,列表中的項目應為“ Fizz”
  • 每5的倍數,列表中的項目應為“嗡嗡聲”
  • 否則應該是數字

這是我產生的代碼:

module FizzBuzz where 

data StringInt a = Int a | String a

handleRule:: StringInt a -> a
handleRule x
    | x % 3 == 0 = StringInt "Fizz"
    | x % 5 == 0 = StringInt "Buzz"
    | otherwise = x

run:: [StringInt a] -> [a]
run = map handleRule

嘗試運行以下測試時:

module FizzBuzzSpec (spec) where

    import Test.Hspec
    import FizzBuzz

    spec :: Spec
    spec = describe "FizzBuzz#run" $ do
        it "should have displayed Fizz for number 3" $
            run [1..10]:2 `shouldBe` "Fizz"
        it "should have displayed Buzz for number 5" $
            run [1..10]:4 `shouldBe` "Buzz"

我有以下輸出:

• Occurs check: cannot construct the infinite type: a ~ StringInt a
• In the expression: x
  In an equation for ‘handleRule’:
      handleRule x
        | (%) x 3 == 0 = StringInt "Fizz"
        | (%) x 5 == 0 = StringInt "Buzz"
        | otherwise = x
• Relevant bindings include
    x :: StringInt a (bound at src/FizzBuzz.hs:6:12)
    handleRule :: StringInt a -> a (bound at src/FizzBuzz.hs:6:1)

| 9 | | 否則= x

重要說明:我真的是Haskell的新手,如果我在那做可怕的事情,對不起。

你知道我在做什么錯嗎?


編輯:

我嘗試使用:

module FizzBuzz where 

type StringInt = Either Int String

handleRule:: Int -> StringInt
handleRule x
    | x `mod` 3 == 0 = Right "Fizz"
    | x `mod` 5 == 0 = Right "Buzz"
    | otherwise      = Left x

run:: [Int] -> [StringInt]
run = map handleRule

module FizzBuzzSpec (spec) where

    import Test.Hspec
    import FizzBuzz

    spec::Spec
    spec = describe "FizzBuzz#run" $ do
        it "should have displayed Fizz for number 3" $
            run [1..10]:2 `shouldBe` Right "Fizz"
        it "should have displayed Buzz for number 5" $
            run [1..10]:4 `shouldBe` Right "Buzz"

但這總是拋出

    • Couldn't match expected type ‘[[StringInt]]’
                  with actual type ‘Either a0 [Char]’
    • In the second argument of ‘shouldBe’, namely ‘Right "Fizz"’
      In the second argument of ‘($)’, namely
        ‘run [1 .. 10] : 2 `shouldBe` Right "Fizz"’
      In a stmt of a 'do' block:
        it "should have displayed Fizz for number 3"
          $ run [1 .. 10] : 2 `shouldBe` Right "Fizz"
  |
9 |                         run [1..10]:2 `shouldBe` Right "Fizz"
  |                                                  ^^^^^^^^^^^^

/Users/pc/Soft/haskell/hello-stack/test/FizzBuzzSpec.hs:11:50: error:
    • Couldn't match expected type ‘[[StringInt]]’
                  with actual type ‘Either a1 [Char]’
    • In the second argument of ‘shouldBe’, namely ‘Right "Buzz"’
      In the second argument of ‘($)’, namely
        ‘run [1 .. 10] : 4 `shouldBe` Right "Buzz"’
      In a stmt of a 'do' block:
        it "should have displayed Buzz for number 5"
          $ run [1 .. 10] : 4 `shouldBe` Right "Buzz"
   |
11 |                         run [1..10]:4 `shouldBe` Right "Buzz"
   |                              

                ^^^^^^^^^^^^

無法指出要點...

謝謝你們的幫助

規則應該是這樣的:

data StringInt = SI_Str String
               | SI_Int Int

handleRule:: Int -> StringInt
handleRule x
    | x `mod` 3 == 0 = SI_Str "Fizz"
    | x `mod` 5 == 0 = SI_Str "Buzz"
    | otherwise      = SI_Int x

當描述“數據”時,實際上是在描述數據類型。 等式的左側是類型的名稱,在這種情況下,類型的名稱是StringInt。 在等式的右側,您描述了如何創建數據類型的構造函數(或本例中的構造函數)。 在這種情況下,我們有2個構造函數可以創建StringInt類型的“數據”-SI_Str構造函數和SI_Int構造函數。 如何區分它們並訪問它們的“數據內容”稱為模式匹配。 但是,為了不破壞學習的樂趣,我建議從那里開始進行學習。

我假設通過以下行:

data StringInt a = Int a | String a

您將定義一個求和類型。 但實際上,它需要提供數據構造函數:

data StringInt = Left Int | Right String

或者,已經有Either類型,可以幫助定義求和類型,因此您只需創建類型別名即可。 因此,您的程序將如下所示

type StringInt = Either Int String

handleRule:: Int -> StringInt
handleRule x
    | mod x 3 == 0 = Right "Fizz"
    | mod x 5 == 0 = Right "Buzz"
    | otherwise = Left x

run:: [Int] -> [StringInt]
run = map handleRule

並且還應該修改測試,因為返回值不僅是一個字符串,而且是包裝在Right的字符串:

module FizzBuzzSpec (spec) where

import Test.Hspec
import FizzBuzz

spec::Spec
spec = describe "FizzBuzz#run" $ do
    it "should have displayed Fizz for number 3" $
        run [1..10] !! 2 `shouldBe` (Right "Fizz")
    it "should have displayed Buzz for number 5" $
        run [1..10] !! 4 `shouldBe` (Right "Buzz")

main :: IO()
main = hspec spec

要運行測試:

runhaskell Tests.hs

順便說一下,您現在可以跳過求和類型,只需返回數字的字符串表示形式(如果不能將其除以35

handleRule:: Int -> String
handleRule x
    | mod x 3 == 0 = "Fizz"
    | mod x 5 == 0 = "Buzz"
    | otherwise = show x

run:: [Int] -> [String]
run = map handleRule

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM