函数中的语法(预期类型为 `* -> Constraint',但 `Int' 的类型为 `*')

Nyo*_*rok 1 haskell

我开始学习 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)

And*_*Ray 8

您的类型定义不正确。双箭头用于显示所需的类型类(又名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函数。)


lef*_*out 7

根据经验,编写某种形式的东西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)