【问题标题】:Haskell - Couldn't match type `(Int, Integer)' with `Pos'Haskell - 无法将类型“(Int,Integer)”与“Pos”匹配
【发布时间】:2017-11-14 21:42:46
【问题描述】:

我目前正在学习 Haskell,但目前遇到了问题。

这是我的代码:

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]]

我必须使用那个特定的数据类型,因此我遇到了一些小问题。

如果代码是这样编写的,则该代码可以正常工作:

type Pos = (Int, Int)
allCoordinates :: [(Int, Int)]
allCoordinates = concat [(zip (allHelper x) [0..8]) | x<-[0..8]]

但我需要编辑这一点:

concat [(zip (allHelper x) [0..8]) | x<-[0..8]]

使其适用于:

allCoordinates :: [Pos]

这可能是一个简单的问题,我有一点心理障碍,但是有人可以帮忙吗?

谢谢

【问题讨论】:

    标签: haskell


    【解决方案1】:

    如果你写:

    type Pos = (Int, Int)
    

    没有构造了一个新类型:你构造了一个类型别名,所以你可以在代码中将Pos(Int, Int) 互换。所以签名为f :: [(Int,Int)]的函数等价于f :: [Pos]

    你可以清理代码并编写:

    allCoordinates :: [Pos]
    allCoordinates = [ (x,y) | x <- [0..8], y <- [0..8]]
    

    或者更干净(但可能有点难以理解):

    allCoordinates :: [Pos]
    allCoordinates = (,) <$> [0..8] <*> [0..8]
    

    使用类型签名这一事实的一个缺点是,可能会在该类型上定义很多函数,并且您可能希望使用 同名 定义函数(以防万一类型类),但具有不同的实现。在这种情况下,您可以定义一个数据类型

    <b>data</b> Pos = Pos (Int,Int)

    现在我们已经定义了一个 new 类型,带有一个构造函数Pos。现在上面的代码将不再工作,但我们可以通过调用我们生成的元组的构造函数来轻松地改变它。所以:

    allCoordinates :: [Pos]
    allCoordinates = [ Pos (x,y) | x <- [0..8], y <- [0..8]]

    如果您使用 one 构造函数定义类型并且该构造函数具有 one 参数,我们可以使用newtype。现在我们已经定义了一个类型,但是 Haskell 可以对其进行优化,使其在内部不会在构造函数中包装和解包,而是简单地以另一种方式处理元组:

    <b>newtype</b> Pos = Pos (Int,Int)

    【讨论】:

    • 非常感谢!彻底解决了我的问题!
    【解决方案2】:

    type 定义了一个类型别名。也就是说,写作:

    type Pos = (Int, Int)
    

    意味着每当您在代码中编写Pos 时,编译器都会看到(Int, Int)。在这种情况下,要构造Pos,您可以只写(1, 2),因为(Int, Int)Pos 无法区分。

    但是,data 定义了一个新的数据类型。你的例子是:

    data Pos = Pos (Int, Int)
    

    Pos 是由函数Pos :: (Int, Int) -&gt; Pos 构造的类型。 这些不相等!在这种情况下,要构造一个Pos,你可以写Pos (1, 2)

    要更正您的代码,请编写:

    data Pos = Pos (Int, Int)
    allCoordinates :: [(Int, Int)]
    allCoordinates = concat [zipWith (curry Pos) (allHelper x) [0..8] | x<-[0..8]]
    

    在哪里zipWith :: (a -&gt; b -&gt; c) -&gt; [a] -&gt; [b] -&gt; [c]

    但是,除非您希望在类型类中有不同的行为,否则最好使用类型别名,否则,您应该使用 newtype

    【讨论】:

    • 我现在收到此错误:无法匹配类型 Pos' with Integer -> (Int, Int)' 预期类型:(Int, Int) -> Integer -> (Int, Int)实际类型:(Int, Int) -> Pos
    • @JamesHolliday 我的错误。将zipWith Pos 替换为zipWith (curry Pos)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多