我正在尝试通过创建棋盘游戏来学习Haskell。我目前有一个[[Char]]的游戏,我正在尝试创建另一个具有字符“a”的相同列和行的板。我该怎么做呢?您还可以解释如何存储值和访问权限吗?
答案 0 :(得分: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]
如果你想深入了解,你可以让编译器为你编写这段代码。 Functor
类型类将map
概括为不是简单列表的结构:
class Functor f where
fmap :: (a -> b) -> f a -> f b
这在什么意义上概括map
?如果您将f
替换为[]
,则可以看到fmap
与map
具有相同的签名:
fmap :: (a -> b) -> [a] -> [b]
实际上,这就是[]
Functor
实例的实施方式:
instance Functor [] where
fmap = map
无论如何,GHC知道如何单独编写Functor
个实例。我将为2D列表定义一个newtype
包装,并说出 deriving Functor
的神奇单词!
{-# LANGUAGE DeriveFunctor #-}
import Data.Functor
newtype TwoDimensional a = TwoDimensional { getTwoDimensional :: [[a]] } deriving Functor
生成的fmap
将具有以下签名:
fmap :: (a -> b) -> TwoDimensional a -> TwoDimensional b
现在,您可以使用标准位机械来替换具有固定值的元素:
replaceWithA :: TwoDimensional a -> TwoDimensional Char
replaceWithA = ('a' <$)
当您获得Haskell及其Functor
标准抽象的经验时,您会更好地发现给定操作是更一般模式的实例。仔细设置类型允许您将大量样板委托给编译器,使您能够简洁地声明性地解决问题的有趣部分。