[英]Haskell - Couldn't match type `(Int, Integer)' with `Pos'
I am currently learning Haskell and I am currently having an issue. 我目前正在学习Haskell,目前遇到问题。
This is my code: 这是我的代码:
data Pos = Pos (Int, Int) deriving (Show, Eq)
allCoordinates :: [Pos]
allCoordinates = concat [(zip (allHelper x) [0..8]) | x<-[0..8]]
allHelper ::Int -> [Int]
allHelper x = [x | y<-[0..8]]
I have to use that specific data type and I am having a little issue due to this. 我必须使用该特定的数据类型,因此,我遇到了一个小问题。
This code works perfectly fine if the code is written like this: 如果代码是这样写的,则此代码可以正常工作:
type Pos = (Int, Int)
allCoordinates :: [(Int, Int)]
allCoordinates = concat [(zip (allHelper x) [0..8]) | x<-[0..8]]
but I need to edit this bit: 但我需要编辑此位:
concat [(zip (allHelper x) [0..8]) | x<-[0..8]]
so that it works with: 这样就可以使用:
allCoordinates :: [Pos]
It is probably a simple issue and I having a bit of a mental block however can anyone help? 这可能是一个简单的问题,我有点精神障碍,但是任何人都可以帮忙吗?
Thank you 谢谢
If you write: 如果您写:
type Pos = (Int, Int)
You have not constructed a new type: you have constructed a type alias, so you can interchange Pos
with (Int, Int)
in the code. 您尚未构造新的类型: 尚未构造类型别名,因此可以在代码中将
Pos
与(Int, Int)
互换。 So a function with signature f :: [(Int,Int)]
is equivalent to f :: [Pos]
. 因此,具有签名
f :: [(Int,Int)]
函数等效于f :: [Pos]
。
You can clean up the code and write: 您可以清理代码并编写:
allCoordinates :: [Pos]
allCoordinates = [ (x,y) | x <- [0..8], y <- [0..8]]
Or even more clean (but probably somewhat harder to understand): 甚至更干净(但可能更难理解):
allCoordinates :: [Pos]
allCoordinates = (,) <$> [0..8] <*> [0..8]
A disadvantage of the fact that you work with a type signature is that there can be a lot of functions defined on that type, and perhaps you want to define functions with the same name (in case of type classes), but with a different implementation. 使用类型签名的事实的一个缺点是,在该类型上可能定义了很多函数,也许您想使用相同的名称 (对于类型类)定义函数,但使用不同的实现。 In that case you can define a datatype :
在这种情况下,您可以定义一个数据类型 :
data Pos = Pos (Int,Int)
Now we have defined a new type, with a constructor Pos
. 现在,我们使用构造函数
Pos
定义了一个新类型。 Now the above code will no longer work, but we can easily alter it by calling the constructor on the tuples we produce. 现在,上面的代码将不再起作用,但是我们可以通过对生成的元组调用构造函数来轻松地对其进行更改。 So:
所以:
allCoordinates :: [Pos]
allCoordinates = [
Pos (x,y) | x <- [0..8], y <- [0..8]]
In case you define a type with one constructor and that constructor has one parameter, we can use newtype
. 如果您使用一个构造函数定义一个类型并且该构造函数具有一个参数,则可以使用
newtype
。 Now we have defined a type, but Haskell can optimize it such that internally, it will not wrap and unwrap in a constructor, but simply treat the tuple in another way: 现在我们已经定义了一个类型,但是Haskell可以对其进行优化,以使其在内部不会在构造函数中进行包装和解包,而只是以另一种方式处理元组:
newtype Pos = Pos (Int,Int)
type
defines a Type alias . type
定义一个Type别名 。 That is to say, writing: 也就是说,写:
type Pos = (Int, Int)
means that whenever you write Pos
in your code, the compiler sees (Int, Int)
. 意味着无论何时在代码中编写
Pos
,编译器都会看到(Int, Int)
。 To construct a Pos
in this case, you can just write (1, 2)
, since an (Int, Int)
and a Pos
are indistinguishable. 在这种情况下,要构造一个
Pos
,您可以只写(1, 2)
,因为(Int, Int)
和Pos
是无法区分的。
However, data
defines a new datatype. 但是,
data
定义了新的数据类型。 Your example is: 您的示例是:
data Pos = Pos (Int, Int)
Pos
is a type constructed by the function Pos :: (Int, Int) -> Pos
. Pos
是由功能Pos :: (Int, Int) -> Pos
构造的类型。 These are not equal ! 这些不相等 ! To construct a
Pos
in this case, you would write Pos (1, 2)
. 在这种情况下,要构造一个
Pos
,您可以编写Pos (1, 2)
。
To correct your code, write: 要更正您的代码,请编写:
data Pos = Pos (Int, Int)
allCoordinates :: [(Int, Int)]
allCoordinates = concat [zipWith (curry Pos) (allHelper x) [0..8] | x<-[0..8]]
Where zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
. 其中
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
However, unless you want different behaviour in typeclasses, using a type alias would be best, otherwise, you should use a newtype . 但是,除非您希望在类型类中具有不同的行为,否则最好使用类型别名,否则,应使用newtype 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.