如何在Haskell中创建二维数组?

Ann*_*Hua 5 haskell functional-programming multidimensional-array

我正在尝试通过创建棋盘游戏来学习Haskell。我目前有一个[[Char]]游戏,我正在尝试创建另一个由相同字符组成的面板,并用字符“ a”填充。我该怎么做?您还可以解释如何存储值和访问吗?

Ben*_*son 4

与其创建大小相同但内容不同的新看板,不如将此操作视为替换现有看板的内容可能会有所帮助。当然,因为 Haskell 是一种不可变的语言,所以它相当于同样的事情 - 改变某些东西的唯一方法是生成它的新版本 - 但它应该帮助您看到这从根本上来说是一个映射操作。

replaceWithA :: [[a]] -> [[Char]]
replaceWithA xss = map (map (const 'a')) xss
-- or, point-free:
replaceWithA = map (map (const 'a'))
-- or, as a list comprehension:
replaceValues xss = [['a' | x <- xs] | xs <- xss]
Run Code Online (Sandbox Code Playgroud)

如果你想深入了解,你可以让编译器为你编写这段代码。类型Functor类概括map为不是简单列表的结构:

class Functor f where
    fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

这在什么意义上具有普遍性map?如果替换f为,[]您可以看到它fmap具有与以下相同的签名map

fmap :: (a -> b) -> [a] -> [b]
Run Code Online (Sandbox Code Playgroud)

事实上,这就是[]sFunctor实例的实现方式:

instance Functor [] where
    fmap = map
Run Code Online (Sandbox Code Playgroud)

不管怎样,GHC 知道如何Functor自己编写实例。我将为newtype2D 列表定义一个包装器并说出神奇的话语deriving Functor

{-# LANGUAGE DeriveFunctor #-}
import Data.Functor

newtype TwoDimensional a = TwoDimensional { getTwoDimensional :: [[a]] } deriving Functor
Run Code Online (Sandbox Code Playgroud)

生成的fmap将具有以下签名:

fmap :: (a -> b) -> TwoDimensional a -> TwoDimensional b
Run Code Online (Sandbox Code Playgroud)

现在您可以使用标准的机器来替换具有固定值的元素:

replaceWithA :: TwoDimensional a -> TwoDimensional Char
replaceWithA = ('a' <$)
Run Code Online (Sandbox Code Playgroud)

随着您获得 Haskell 及其标准抽象的经验,Functor您将能够更好地发现给定操作何时是更通用模式的实例。仔细设置类型可以让您将大量样板委托给编译器,从而使您能够简洁、声明性地解决问题中有趣的部分。