我实际上是在学习Haskell,并且正在尝试制作一个简单的FizzBuzz Kata。
这个想法是将一个数字列表作为条目,并生成一个数字列表|遵循以下规则的字符串:
这是我产生的代码:
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"
|
^^^^^^^^^^^^
无法弄清楚这里的意思...
感谢您的帮助人员
答案 0 :(得分:2)
规则应如下所示:
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构造函数。如何区分它们并访问它们的“数据内容”称为模式匹配。不过,为了不破坏学习的乐趣,我建议从那里开始进行学习。
答案 1 :(得分:1)
我假设是这样,
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
顺便说一下,您现在可以跳过求和类型,只需返回数字的字符串表示形式(如果不能用3
或5
除),就可以了:
handleRule:: Int -> String
handleRule x
| mod x 3 == 0 = "Fizz"
| mod x 5 == 0 = "Buzz"
| otherwise = show x
run:: [Int] -> [String]
run = map handleRule