我开始学习 Haskell 并且我在函数中的语法上苦苦挣扎。我正在尝试创建一个接收数字“e”和数字“n”的函数,返回一个包含“n”次“e”的列表。
示例:repn 3 5将返回[3,3,3,3,3]:
repn :: Int a => a -> a -> [a]
repn e n
| n >= 1 = (take n (repeat e))
| otherwise = []
Run Code Online (Sandbox Code Playgroud)
但我收到此错误:
* Expected kind `* -> Constraint', but `Int' has kind `*'
* In the type signature: replica :: Int a => a -> a
Run Code Online (Sandbox Code Playgroud)
您的类型定义不正确。双箭头用于显示所需的类型类(又名kind * -> Constraint),或对类型的约束。但是,Int它本身是一种类型(又名kind *)。
您不能以这种方式指定类型。在您的实现中,n必须是Int,但e可以是任何东西。但是,由于您指定它应该是一个数字,因此您可以使用Num类型类来限制它。因此,您签名的正确版本是:
repn :: Num a => a -> Int -> [a]
Run Code Online (Sandbox Code Playgroud)
如果你想e被限制在一个Int,那么你的签名应该是
repn :: Int -> Int -> [Int]
Run Code Online (Sandbox Code Playgroud)
如果您不需要任何限制e,您的签名可以是
repn :: a -> Int -> [a]
Run Code Online (Sandbox Code Playgroud)
这些都是您编写的函数的有效类型签名。(尽管在实际代码中,我只是将您指向内置replicate函数。)
根据经验,编写某种形式的东西Foo a => ...才有意义Foo是一个类型 class。与 OO 语言不同,Haskell 中的类和类型是完全不同的东西。Int是一种类型,因此不能以这种方式使用;相反,您应该简单地使用
repn :: Int -> Int -> [Int]
Run Code Online (Sandbox Code Playgroud)
...虽然实际上根本没有理由限制列表元素类型,但签名也可以是
repn :: a -> Int -> [a]
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用类型类:“类 int 类型”的类是Integral. 那么你不能take直接使用,因为这仅限于Int反论点;但是您可以将任何整数类型转换为Int:
repn :: Integral n => a -> n -> [a]
repn e n = take (fromIntegral n) $ repeat e
-- Note no case distinction is needed, because `take` already yields
-- an empty list if `n<1`.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
738 次 |
| 最近记录: |