在 haskell 中使用仿函数
Using functor in haskell
我有一个这样定义的 World 数据类型:
data World = World
{ resolution :: (Int, Int)
, direction :: Snake_direction
, snake_scale :: Int
, snake :: [(Int, Int)]
, isStuck :: Bool
, gen :: R.StdGen
, food :: (Int, Int)
, superFood :: (Int, Int)
} deriving (Read, Show)
并且我想使用一个仿函数,它在 snake 列表上使用 fmap,它是 world 数据类型的参数。我正在为仿函数语法而苦苦挣扎
instance Functor (World) where
fmap f (World) = World {fmap f snake}
但是编译器说
error: parse error on input ‘f’
如果我们检查 Functor
类型 class,我们会看到:
class Functor (f <b>:: * -> *</b>) where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
{-# MINIMAL fmap #-}
所以f
的种类应该是* -> *
,一个带类型参数的类型。这里不是这种情况,所以我们不能声明 World
一个 Functor
的实例。由于用户可以使用任何函数 f :: a -> b
将 World a
映射到 World b
,但根本没有 World a
。
如果您仍想将其设为 Functor
,我们可以先 "upgrade" World
类型,使其具有类型参数:
data World <b>a</b> = World
{ resolution :: (Int, Int)
, direction :: Snake_direction
, snake_scale :: Int
, snake :: [(<b>a</b>, <b>a</b>)]
, isStuck :: Bool
, gen :: R.StdGen
, food :: (Int, Int)
, superFood :: (Int, Int)
} deriving (Read, Show)
那么我们可以定义一个fmap
如下:
instance Functor World where
<b>fmap f w = w {snake = fmap (\(x,y) -> (f x, f y)) (snake w)}</b>
或者如果您想 fmap
直接越过 snake
,而不是越过 snake
的 坐标 :
data World <b>a</b> = World
{ resolution :: (Int, Int)
, direction :: Snake_direction
, snake_scale :: Int
, snake :: <b>a</b>
, isStuck :: Bool
, gen :: R.StdGen
, food :: (Int, Int)
, superFood :: (Int, Int)
} deriving (Read, Show)
那么我们可以定义一个fmap
如下:
instance Functor World where
fmap f w = w {snake = <b>f (snake w)</b>}
另一种选择是不使World
成为仿函数,因为您真正想要的只是一种将函数映射到World
值。
snakeMap :: ((Int, Int) -> (Int, Int)) -> World -> World
snakeMap f w = w { snake = fmap f (snake w) }
我有一个这样定义的 World 数据类型:
data World = World
{ resolution :: (Int, Int)
, direction :: Snake_direction
, snake_scale :: Int
, snake :: [(Int, Int)]
, isStuck :: Bool
, gen :: R.StdGen
, food :: (Int, Int)
, superFood :: (Int, Int)
} deriving (Read, Show)
并且我想使用一个仿函数,它在 snake 列表上使用 fmap,它是 world 数据类型的参数。我正在为仿函数语法而苦苦挣扎
instance Functor (World) where
fmap f (World) = World {fmap f snake}
但是编译器说
error: parse error on input ‘f’
如果我们检查 Functor
类型 class,我们会看到:
class Functor (f <b>:: * -> *</b>) where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
{-# MINIMAL fmap #-}
所以f
的种类应该是* -> *
,一个带类型参数的类型。这里不是这种情况,所以我们不能声明 World
一个 Functor
的实例。由于用户可以使用任何函数 f :: a -> b
将 World a
映射到 World b
,但根本没有 World a
。
如果您仍想将其设为 Functor
,我们可以先 "upgrade" World
类型,使其具有类型参数:
data World <b>a</b> = World
{ resolution :: (Int, Int)
, direction :: Snake_direction
, snake_scale :: Int
, snake :: [(<b>a</b>, <b>a</b>)]
, isStuck :: Bool
, gen :: R.StdGen
, food :: (Int, Int)
, superFood :: (Int, Int)
} deriving (Read, Show)
那么我们可以定义一个fmap
如下:
instance Functor World where
<b>fmap f w = w {snake = fmap (\(x,y) -> (f x, f y)) (snake w)}</b>
或者如果您想 fmap
直接越过 snake
,而不是越过 snake
的 坐标 :
data World <b>a</b> = World
{ resolution :: (Int, Int)
, direction :: Snake_direction
, snake_scale :: Int
, snake :: <b>a</b>
, isStuck :: Bool
, gen :: R.StdGen
, food :: (Int, Int)
, superFood :: (Int, Int)
} deriving (Read, Show)
那么我们可以定义一个fmap
如下:
instance Functor World where
fmap f w = w {snake = <b>f (snake w)</b>}
另一种选择是不使World
成为仿函数,因为您真正想要的只是一种将函数映射到World
值。
snakeMap :: ((Int, Int) -> (Int, Int)) -> World -> World
snakeMap f w = w { snake = fmap f (snake w) }