我想知道为什么以下是Pair类型的正确实现.具体来说,为什么Pair b a不Pair a b呢?
newtype Pair b a = Pair { getPair :: (a,b) }
Run Code Online (Sandbox Code Playgroud)
澄清,Pair a b不适用于以下内容:
instance Functor (Pair c) where
fmap f (Pair (x,y)) = Pair (f x, y)
Run Code Online (Sandbox Code Playgroud)
而且我不明白为什么.
除了下面的很多很棒的答案之外,我发现在ghci中做了以下有用的事情:
*Main> newtype Pair b a = Pair (a, b) deriving (Show, Eq)
*Main> :t Pair(True, "cat")
Pair(True, "cat") :: Pair [Char] Bool
*Main> newtype Pair a b = Pair (a, b) deriving (Show, Eq)
*Main> :t Pair(True, "cat")
Pair(True, "cat") :: Pair Bool [Char]
Run Code Online (Sandbox Code Playgroud)
newtype Pair b a = Pair { getPair :: (a,b) }
Run Code Online (Sandbox Code Playgroud)
注意它之前的段落(强调我的):
事实证明,为此编写实例有点困难.有了
Maybe,我们只说实例Functor Maybe,因为只有只有一个参数的类型构造函数才能成为Functor的一个实例.但似乎没有办法做类似的事情,(a,b)所以类型参数a最终成为我们使用时改变的那个fmap.为了解决这个问题,我们可以通过第二种类型参数表示元组中第一个组件的类型来新建我们的元组:
因此,在这种情况下,我们希望(底层)对的第一个元素的类型是类型构造函数中的最后一个类型Pair.毕竟,我们想fmap在LYAH的第一个参数上使用:
-- b
-- |
-- v a isn't here…
instance Functor (Pair c) where
-- but here!
--fmap :: (a -> x) -> Pair c a -> Pair c x
fmap f (Pair (x,y)) = Pair (f x, y)
Run Code Online (Sandbox Code Playgroud)
您当然可以将定义更改为newtype Pair b a = Pair { getPair :: (a,b) }.但是在这种情况下会发生什么?
-- a
-- |
-- v b isn't here…
instance Functor (Pair c) where
-- but here! v---- c ----v--------------------------+
--fmap :: (b -> x) -> Pair c b -> Pair c x |
fmap f (Pair (x,y)) = Pair (f x, y) -- |
-- ^^^ uh-oh - that doesn't seem right-+
Run Code Online (Sandbox Code Playgroud)
请记住,您的基础类型现在(a,b).但是,在您的Functor实例a中现在已修复,但您尝试应用fmap它.这不起作用.相反,您必须使用fmap第二个条目,它对应于b类型构造函数Pair a b:
-- a
-- |
-- v b isn't here…
instance Functor (Pair c) where
-- but here!
--fmap :: (b -> x) -> Pair c b -> Pair c x
fmap f (Pair (x,y)) = Pair (x, f y)
-- ^^^ everything fine now.
Run Code Online (Sandbox Code Playgroud)
但在这一点上,我们回到原来的(a,b)实例.