通过 Functor 实例将 Rose (Board, Int) 转换为 Rose Int
Converting Rose (Board, Int) to Rose Int through Functor instance
data Rose a = MkRose a [Rose a]
deriving (Eq, Show)
-- Rose Int with two children
t1 = MkRose 3 [MkRose 9 [], MkRose 2 []]
data Field = X | O | B
deriving (Eq, Ord)
type Row = (Field, Field, Field)
type Board = (Row, Row, Row)
minimax :: Player -> Rose Board -> Rose Int
-- MkRose -1 [MkRose 1 [..], MkRose -1 [..], MkRose 1 [..] ]
minimax P1 (MkRose b bs)
= let bs' = minimax' (MkRose b bs)
-- :t bs' = MkRose (Board, Int)
-- [MkRose (Board,Int) [], MkRose (Board,Int) [] ]
in fmap snd bs'
如果我有 Rose (Board, Int)
,我希望能够将其转换为 Rose Int
。我从尝试 Functor
实例切换到仅在列表中使用 fmap
和 snd
,如上更新,这给了我这个错误:
error:
• No instance for (Functor Rose) arising from a use of ‘fmap’
• In the expression: fmap snd bs'
In the expression: let bs' = minimax' (MkRose b bs) in fmap snd bs'
In an equation for ‘minimax’:
minimax P1 (MkRose b bs)
= let bs' = minimax' (MkRose b bs) in fmap snd bs'
|
259 | in fmap snd bs'
如何在 Haskell 中完成此操作?或者我可以只写一个函数,如果那样更容易的话。
你不需要fmap
:
rmap :: (a -> b) -> Rose a -> Rose b
rmap f (MkRose a as) = MkRose (f a) (map (rmap f) as)
但是有
instance Functor Rose where fmap = rmap
让您可以像 (<$)
一样做一些整洁的事情,您不必一直记住 map
、rmap
、vmap
等
(另外,{-# LANGUAGE DeriveFunctor #-}
,你可以简单写成data Rose a = MkRose a [a] deriving Functor
,实例给你计算。)
只需将 Functor
添加到 deriving
列表中:
data Rose a = MkRose a [Rose a]
deriving (Eq, Show, Functor)
您可能必须启用扩展程序 DeriveFunctor
。
那你就可以用fmap snd
.
对于任何类型 a
和 b
,它会将 Rose (a,b)
转换为 Rose b
。特别是,对于 (Board, Int)
,它会将 Rose (Board, Int)
转换为 Rose Int
,方法是简单地剥离树中每个值位置中元组的第一个组件。
fmap :: Functor f => (a -> b) -> f a -> f b
fmap snd :: Functor f => f (a, b) -> f b
fmap @ Rose :: (a -> b) -> Rose a -> Rose b
fmap @ Rose @ (Board, Int) snd :: Rose (Board, Int) -> Rose Int
这使用 TypeApplications
但您不需要它,类型将根据您提供的数据自动选择,即您将应用 fmap snd
的变量。例如:
Prelude> t1 = MkRose (0,3) [MkRose (0,9) []]
Prelude> fmap snd t1
MkRose 3 [MkRose 9 []]
Prelude>
您在评论中所写的语法无效
bs' = MkRose (Board, Int)
[MkRose (Board,Int) [], MkRose (Board,Int) [] ]
如果你有这个作为代码,逐字记录。
你不能那样做。 Board
是一种类型的名称。 Int
是一种类型的名称。但是变量 bs'
应该引用一段 数据 。如果该数据是Rose (Bord, Int)
类型,则意味着在每个出现类型变量a
的地方,在数据类型定义中,
data Rose a = MkRose a [Rose a]
-- ^ ^
应该会出现 一条 (Board, Int)
类型的数据 -- 而不是简单地键入 names。这是一个包含两个实际值的元组,一个是 Board
类型,另一个是 Int
类型。例如,Rose (String, Int)
:
t2 :: Rose (String, Int)
t2 = MkRose ("a", 1) [MkRose ("b", 2) [], MkRose ("c", 3) []]
fmap snd t2
=> MkRose 1 [MkRose 2 [], MkRose 3 []]
data Rose a = MkRose a [Rose a]
deriving (Eq, Show)
-- Rose Int with two children
t1 = MkRose 3 [MkRose 9 [], MkRose 2 []]
data Field = X | O | B
deriving (Eq, Ord)
type Row = (Field, Field, Field)
type Board = (Row, Row, Row)
minimax :: Player -> Rose Board -> Rose Int
-- MkRose -1 [MkRose 1 [..], MkRose -1 [..], MkRose 1 [..] ]
minimax P1 (MkRose b bs)
= let bs' = minimax' (MkRose b bs)
-- :t bs' = MkRose (Board, Int)
-- [MkRose (Board,Int) [], MkRose (Board,Int) [] ]
in fmap snd bs'
如果我有 Rose (Board, Int)
,我希望能够将其转换为 Rose Int
。我从尝试 Functor
实例切换到仅在列表中使用 fmap
和 snd
,如上更新,这给了我这个错误:
error:
• No instance for (Functor Rose) arising from a use of ‘fmap’
• In the expression: fmap snd bs'
In the expression: let bs' = minimax' (MkRose b bs) in fmap snd bs'
In an equation for ‘minimax’:
minimax P1 (MkRose b bs)
= let bs' = minimax' (MkRose b bs) in fmap snd bs'
|
259 | in fmap snd bs'
如何在 Haskell 中完成此操作?或者我可以只写一个函数,如果那样更容易的话。
你不需要fmap
:
rmap :: (a -> b) -> Rose a -> Rose b
rmap f (MkRose a as) = MkRose (f a) (map (rmap f) as)
但是有
instance Functor Rose where fmap = rmap
让您可以像 (<$)
一样做一些整洁的事情,您不必一直记住 map
、rmap
、vmap
等
(另外,{-# LANGUAGE DeriveFunctor #-}
,你可以简单写成data Rose a = MkRose a [a] deriving Functor
,实例给你计算。)
只需将 Functor
添加到 deriving
列表中:
data Rose a = MkRose a [Rose a]
deriving (Eq, Show, Functor)
您可能必须启用扩展程序 DeriveFunctor
。
那你就可以用fmap snd
.
对于任何类型 a
和 b
,它会将 Rose (a,b)
转换为 Rose b
。特别是,对于 (Board, Int)
,它会将 Rose (Board, Int)
转换为 Rose Int
,方法是简单地剥离树中每个值位置中元组的第一个组件。
fmap :: Functor f => (a -> b) -> f a -> f b
fmap snd :: Functor f => f (a, b) -> f b
fmap @ Rose :: (a -> b) -> Rose a -> Rose b
fmap @ Rose @ (Board, Int) snd :: Rose (Board, Int) -> Rose Int
这使用 TypeApplications
但您不需要它,类型将根据您提供的数据自动选择,即您将应用 fmap snd
的变量。例如:
Prelude> t1 = MkRose (0,3) [MkRose (0,9) []]
Prelude> fmap snd t1
MkRose 3 [MkRose 9 []]
Prelude>
您在评论中所写的语法无效
bs' = MkRose (Board, Int)
[MkRose (Board,Int) [], MkRose (Board,Int) [] ]
如果你有这个作为代码,逐字记录。
你不能那样做。 Board
是一种类型的名称。 Int
是一种类型的名称。但是变量 bs'
应该引用一段 数据 。如果该数据是Rose (Bord, Int)
类型,则意味着在每个出现类型变量a
的地方,在数据类型定义中,
data Rose a = MkRose a [Rose a]
-- ^ ^
应该会出现 一条 (Board, Int)
类型的数据 -- 而不是简单地键入 names。这是一个包含两个实际值的元组,一个是 Board
类型,另一个是 Int
类型。例如,Rose (String, Int)
:
t2 :: Rose (String, Int)
t2 = MkRose ("a", 1) [MkRose ("b", 2) [], MkRose ("c", 3) []]
fmap snd t2
=> MkRose 1 [MkRose 2 [], MkRose 3 []]