Haskell类型组合

Ara*_*ian 6 haskell

假设我想使用类型类编写一个带有一些表示抽象的数独求解器.所以我想为行和矩阵创建一个类型类:

{-# LANGUAGE FlexibleInstances #-}

class Row r where
  (!) :: r -> Int -> Int

class Sudoku a where
  row :: (Row r) => Int -> a -> r
Run Code Online (Sandbox Code Playgroud)

显然,我会添加更多,但只是这些功能足以让我遇到麻烦.现在让我们说我想用嵌套列表来实现它.试:

instance Row r => Sudoku [r] where
  row n s = s !! (n - 1)
Run Code Online (Sandbox Code Playgroud)

让我在热水中:

Couldn't match expected type `r1' against inferred type `r'
  `r1' is a rigid type variable bound by
       the type signature for `row' at 96b.hs:7:14
  `r' is a rigid type variable bound by
      the instance declaration at 96b.hs:12:13
In the expression: s !! (n - 1)
In the definition of `row': row n s = s !! (n - 1)
In the instance declaration for `Sudoku [r]'
Run Code Online (Sandbox Code Playgroud)

第二次刺伤:

instance Row [Int] where
  r ! n = r !! (n - 1)

instance Sudoku [[Int]] where
  row n s = s !! (n - 1)
Run Code Online (Sandbox Code Playgroud)

票价不错:

Couldn't match expected type `r' against inferred type `[Int]'
  `r' is a rigid type variable bound by
      the type signature for `row' at 96b.hs:8:14
In the expression: s !! (n - 1)
In the definition of `row': row n s = s !! (n - 1)
In the instance declaration for `Sudoku [[Int]]'
Run Code Online (Sandbox Code Playgroud)

我似乎错过了一些东西.建模像这样的简单场景的正确方法是什么?

ham*_*mar 9

你的Sudoku班级没有表明a和之间有任何关系r.它目前说如果你有一个数独,你可以从它获得任何类型的行.您的实例仅显示如何从数独中获取一种特定类型的行,因此不符合任何行类型应该起作用的要求.

有两种常见的方法可以解决这个问题.一种方法是使用类型族将行类型与数独类型相关联:

{-# LANGUAGE TypeFamilies, FlexibleInstances #-}

class Sudoku a where
    type RowType a :: *
    row :: Int -> a -> RowType a

instance Row r => Sudoku [r] where
    type RowType [r] = r
    row n s = s !! (n - 1)
Run Code Online (Sandbox Code Playgroud)

您还可以使用功能依赖项获得相同的结果.然后,我们将行类型作为附加参数添加到Sudoku类中,并通过使用函数依赖关系指示sudoku确定行类型的关系| a -> r:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies,
             FlexibleInstances #-}

class Row r where
  (!) :: r -> Int -> Int

instance Row [Int] where
  r ! n = r !! (n - 1)

class Sudoku a r | a -> r where
    row :: (Row r) => Int -> a -> r

instance Row r => Sudoku [r] r where
    row n s = s !! (n - 1)
Run Code Online (Sandbox Code Playgroud)