为什么我不能制作(Functor f)=> ConcreteType - > f String实例Functor(( - >)ConcreteType)?

时间:2014-11-23 07:58:33

标签: haskell types functor arrows

我构建类型的方式,我相信这将遵循Functor法则,该法律规定应该有一个身份函数,fmap将返回原始函子。

代码:

-- apply a style function to a shell prompt functor
-- e.g.
-- bold & fgColor red `style` gitCurrentBranch
style :: (String -> ShellPromptType -> String) -> ShellPromptSegment String
           -> ShellPromptType -> ShellPromptSegment String
style f segment = \shType -> (flip f) shType <$> segment

-- this is fine
style' :: (String -> ShellPromptType -> String) 
            -> (ShellPromptType -> ShellPromptSegment String)
            -> ShellPromptType -> ShellPromptSegment String
style' f makeSegment = flip f >>= \g shellType -> fmap g $ makeSegment shellType

-- this apparently is not.  Compiler complains that it wants the type (String -> String) -> ShellPromptType -> b
-- for my lambda function there, but it gets (String -> String) -> ShellPromptType -> ShellPromptSegment String
-- instead.  I guess 'b' is not allowed to be a functor?
instance Functor ((->) ShellPromptType) where
  fmap f makeSegment = ((flip f) :: ShellPromptType -> String -> String)
                        >>= ((\g shellType -> fmap g $ makeSegment shellType) 
                              :: (String -> String) -> ShellPromptType -> (ShellPromptSegment String))

错误讯息:

LambdaLine/Shells/ShellPromptSegment.hs|81 col 30 error| Couldn't match type `ShellPromptType -> String'
||               with `ShellPromptSegment String'
|| Expected type: (String -> String) -> ShellPromptType -> b
||   Actual type: (String -> String)
||                -> ShellPromptType -> ShellPromptSegment String
|| In the second argument of `(>>=)', namely
||   `((\ g shellType -> fmap g $ makeSegment shellType) ::
||       (String -> String)
||       -> ShellPromptType -> (ShellPromptSegment String))'
|| In the expression:
||   ((flip f) :: ShellPromptType -> String -> String)
||   >>=
||     ((\ g shellType -> fmap g $ makeSegment shellType) ::
||        (String -> String)
||        -> ShellPromptType -> (ShellPromptSegment String))
|| In an equation for `fmap':
||     fmap f makeSegment
||       = ((flip f) :: ShellPromptType -> String -> String)
||         >>=
||           ((\ g shellType -> fmap g $ makeSegment shellType) ::
||              (String -> String)
||              -> ShellPromptType -> (ShellPromptSegment String))
LambdaLine/Shells/ShellPromptSegment.hs|81 col 56 error| Couldn't match type `[Char]' with `ShellPromptSegment String'
|| Expected type: ShellPromptSegment String
||   Actual type: a
|| In the return type of a call of `makeSegment'
|| In the second argument of `($)', namely `makeSegment shellType'
|| In the expression: fmap g $ makeSegment shellType

2 个答案:

答案 0 :(得分:6)

你已经过度专业化了。

仿函数的定义如下:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

这个想法是它需要一个正常的功能并将其提升到一些上下文中。但它不止于此:它的想法是它需要任何正常函数并将其提升到上下文中。对于列表仿函数,fmap可以使用任何函数并在适当类型的列表上执行。

你所做的事情总是从你的仿函数中返回相同的类型,这会破坏它作为仿函数的目的,因此Haskell不允许这样做。

答案 1 :(得分:1)

考虑Functor

的定义
class Functor f where
    fmap :: (a -> b) -> f a -> f b

该类或方法不限制类型ab,因此您定义的任何fmap都必须适用于任何类型a和{ {1}}。您可以定义自己的类型类,例如:

b

但这不会是class MyFunctor f where myfmap :: (String -> String) -> f String -> f String