如何在Haskell中以多态的方式为多个类型编写多个函数定义?

伊恩·道林

给定我的类型定义:

data Tile = Revealed | Covered deriving (Eq, Show)
data MinePit = Clean | Unsafe deriving (Eq, Show)
data Flag = Flagged | Unflagged deriving (Eq, Show)
type Square = (Tile, MinePit, Flag)
type Board = [[Square]]

我创建了两个函数:

  1. createBoard生成值的元组的二维列表-或“ Board”初始化所有相同值的维度n * m列表。
createBoard :: Int -> Int -> Board
createBoard 0 _ = [[]]
createBoard _ 0 = [[]]
createBoard 1 1 = [[(Covered, Clean, Unflagged)]]
createBoard n m = take n (repeat (take m (repeat (Covered, Clean, Unflagged))))

一个例子:

λ> createBoard 2 3
[[(Covered,Clean,Unflagged),(Covered,Clean,Unflagged),(Covered,Clean,Unflagged)],[(Covered,Clean,Unflagged),(Covered,Clean,Unflagged),(Covered,Clean,Unflagged)]]
  1. 定义函数defineIndices的目的是为了创建由createBoard生成的Board的索引的顺序列表。
defineIndices :: Int -> Int -> [[(Int,Int)]]
defineIndices n m = [[(i,j) | j <- [1..m]] | i <- [1..n]]

它的行为类似于:

λ> defineIndices 2 3
[[(1,1),(1,2),(1,3)],[(2,1),(2,2),(2,3)]]

从这里开始,我创建了一个函数来创建MapBoard,在该函数中可以根据给定的Square值查找特定Square的值。

type MapBoard = Map (Int, Int) Square

createMapBoard :: [[(Int,Int)]] -> [[Square]] -> MapBoard
createMapBoard indices squares = M.fromList $ zip (concat indices) (concat squares)

但是,对我来说似乎合理的是,我还应该编写一种方法,在该方法中,我可以直接从一对Int(一个或多个)中创建MapBoard,以实现我以前的功能。可能看起来像:

createMapBoard2 :: Int -> Int -> MapBoard
createMapBoard2 n m = createMapBoard indices squares where
  indices = defineIndices n m
  squares = createBoard n m

但是,我检查了是否可以使用createMapBoard在这种情况下实现多态,然后将createMapBoard2改为createMapBoard。我在网上发现这就是所谓的Ad-Hoc多态现象,例如

class Square a where
    square :: a -> a
    
instance Square Int where
    square x = x * x

instance Square Float where
    square x = x * x 

尝试自己写类似的东西,我能想到的最好的方法如下:

class MyClass a b MapBoard where
  createMapBoard :: a -> b -> MapBoard

instance createMapBoard [[(Int,Int)]] -> [[Square]] -> MapBoard where
  createMapBoard indices squares = M.fromList $ zip (concat indices) (concat squares)

instance createMapBoard Int -> Int -> MapBoard where
  createMapBoard n m = createMapBoard indices squares where
  indices = defineIndices n m
  squares = createBoard n m

尝试编译它会导致编译错误:

src/minesweeper.hs:35:19-26: error: …
    Unexpected type ‘MapBoard’
    In the class declaration for ‘MyClass’
    A class declaration should have form
      class MyClass a b c where ...
   |
Compilation failed.
λ> 

对于为什么不允许在类定义中使用非代数类型(例如MapBoard),我感到困惑。

class MyClass a b MapBoard where

用另一个代数类型c替换MapBoard会导致另一个编译错误,这对我来说是丢失的。

src/minesweeper.hs:37:10-63: error: …
    Illegal class instance: ‘createMapBoard [[(Int, Int)]]
                             -> [[Square]] -> MapBoard’
      Class instances must be of the form
        context => C ty_1 ... ty_n
      where ‘C’ is a class
   |
src/minesweeper.hs:39:10-46: error: …
    Illegal class instance: ‘createMapBoard Int -> Int -> MapBoard’
      Class instances must be of the form
        context => C ty_1 ... ty_n
      where ‘C’ is a class
   |
Compilation failed.

我是否可以实现createMapBoard的临时多态性?我是否可以创建一个类定义,该类定义对所有实例的返回类型必须为MapBoard进行严格限制?

编辑:

纠正了语法错误后,我的代码现在是:

class MyClass a b where
  createMapBoard :: a -> b
instance createMapBoard [[(Int,Int)]] [[Square]] where
  createMapBoard indices squares = M.fromList $ zip (concat indices) (concat squares)
instance createMapBoard Int Int where
  createMapBoard n m = createMapBoard indices squares where
  indices = defineIndices n m
  squares = createBoard n m

这会导致另一个编译错误:

src/minesweeper.hs:37:10-23: error: …
    Not in scope: type variable ‘createMapBoard’
   |
src/minesweeper.hs:39:10-23: error: …
    Not in scope: type variable ‘createMapBoard’
   |
Compilation failed.

我倾向于认为,我对类的理解仍然存在错误。

到处走走

您想这样写:

class MyClass a b where createMapBoard :: a -> b -> MapBoard

instance MyClass [[(Int,Int)]] [[Square]] where
    createMapBoard indices squares = M.fromList $ zip ...

instance MyClass Int Int where
    createMapBoard n m = createMapBoard indices squares where
        ...

... -> ... -> MapBoard已经在createMapBoard方法的签名,这并不在类/实例头属于。

顺便说一句,我不认为在这里开设一门课真的很有意义。拥有两个单独命名的createMapBoard函数没有错如果您可以实际在其上编写多态函数,则只有走一类的路要走,但是在这种情况下,我对此表示怀疑–您宁愿遇到需要一个版本或另一个版本的具体情况。然后就不需要一个类了,只需硬编写所需的版本即可。

宁愿使用单独的函数而不使用类方法的一个原因是,它使类型检查器的工作更加容易。一旦参数createMapBoard是多态的,它们就可能具有任何类型(至少就类型检查器而言)。因此,只能使用其类型在其他位置完全确定的参数来调用它。现在,在其他编程语言中,您可能想要传递的值的类型通常无论如何都是固定的,但是在Haskell中,实际上也很常见也具有多态值最简单的例子是数字文字–它们没有类型Int,而是Num a => a

我个人发现“反向多态性”通常比“正向多态性”更适合使用:不要使函数参数成为多态性,而要使结果多变这样,由环境固定表达式的最外面的类型就足够了,并且类型检查器会自动推断所有子表达式。反之,则必须固定所有单个表达式的类型,并且编译器可以推断最终结果类型...这几乎没有用,因为您可能仍想通过签名对其进行修复。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在Haskell中编写具有中间多态类型的函数

来自分类Dev

如何在Haskell中编写自定义的show函数

来自分类Dev

如何在Minitest中为TCPSocket编写多个测试

来自分类Dev

如何在 JS 函数中编写多个 HTML div

来自分类Dev

如何在C ++中为多个类类型指定相同的模板化成员函数?

来自分类Dev

如何在SAM模板中为lambda函数定义多个触发器?

来自分类Dev

如何在TypeScript迭代中定义多个产量类型?

来自分类Dev

如何在Haskell中编写showIt函数?

来自分类Dev

如何在 Typescript 中管理多个函数返回类型?

来自分类Dev

如何在Groovy中为多个目标定义注释?

来自分类Dev

如何在Groovy中为多个目标定义注释?

来自分类Dev

如何在Passport.js中定义多个isAuthenticated函数?

来自分类Dev

如何在javascript中为多个输入使用单个函数

来自分类Dev

记录类型Haskell中的多态函数

来自分类Dev

如何从Haskell中的函数返回多个值?

来自分类Dev

如何在一个函数或类中为拖放中的多个组件处理多个放置?

来自分类Dev

用Pythonic编写多个函数的方式?

来自分类Dev

如何在Rascal中定义通用(多态)函数?

来自分类Dev

如何在Rascal中定义通用(多态)函数?

来自分类Dev

如何在laravel中为url中的多个参数编写路由?

来自分类Dev

如何在熊猫分组的DataFrame中的多个列上应用多个自定义函数?

来自分类Dev

如何在Haskell中定义数组类型

来自分类Dev

如何在Haskell中定义数组类型

来自分类Dev

如何编写多个javascript函数?

来自分类Dev

java中的泛型类型:如何定义一个返回多个不同类型的函数

来自分类Dev

如何在多个应用程序中编写自定义django manage.py命令

来自分类Dev

用多个包含的类型定义Haskell类型

来自分类Dev

如何在此 marqup 中为自定义帖子类型编写循环

来自分类Dev

如何在Spark中基于多个值为DataFrame编写条件

Related 相关文章

  1. 1

    在Haskell中编写具有中间多态类型的函数

  2. 2

    如何在Haskell中编写自定义的show函数

  3. 3

    如何在Minitest中为TCPSocket编写多个测试

  4. 4

    如何在 JS 函数中编写多个 HTML div

  5. 5

    如何在C ++中为多个类类型指定相同的模板化成员函数?

  6. 6

    如何在SAM模板中为lambda函数定义多个触发器?

  7. 7

    如何在TypeScript迭代中定义多个产量类型?

  8. 8

    如何在Haskell中编写showIt函数?

  9. 9

    如何在 Typescript 中管理多个函数返回类型?

  10. 10

    如何在Groovy中为多个目标定义注释?

  11. 11

    如何在Groovy中为多个目标定义注释?

  12. 12

    如何在Passport.js中定义多个isAuthenticated函数?

  13. 13

    如何在javascript中为多个输入使用单个函数

  14. 14

    记录类型Haskell中的多态函数

  15. 15

    如何从Haskell中的函数返回多个值?

  16. 16

    如何在一个函数或类中为拖放中的多个组件处理多个放置?

  17. 17

    用Pythonic编写多个函数的方式?

  18. 18

    如何在Rascal中定义通用(多态)函数?

  19. 19

    如何在Rascal中定义通用(多态)函数?

  20. 20

    如何在laravel中为url中的多个参数编写路由?

  21. 21

    如何在熊猫分组的DataFrame中的多个列上应用多个自定义函数?

  22. 22

    如何在Haskell中定义数组类型

  23. 23

    如何在Haskell中定义数组类型

  24. 24

    如何编写多个javascript函数?

  25. 25

    java中的泛型类型:如何定义一个返回多个不同类型的函数

  26. 26

    如何在多个应用程序中编写自定义django manage.py命令

  27. 27

    用多个包含的类型定义Haskell类型

  28. 28

    如何在此 marqup 中为自定义帖子类型编写循环

  29. 29

    如何在Spark中基于多个值为DataFrame编写条件

热门标签

归档