2014-11-23 53 views
0

我有我的类型构造的方式,我相信这将遵循函数法则,其中规定应该有一个身份函数fmap返回原函子。为什么我不能在一个实例Functor(( - >)ConcreteType)中创建一个(Functor f)=> ConcreteType - > f String?

代码:

-- 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 

回答

6

你已经过分专注。

函子的定义如下:

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

的想法是,它需要一个正常的功能,它提高到一定范围内。但不止于此:这个想法是需要的任何正常的功能,并将其引入到上下文中。对于列表函子,fmap可以使用任何函数并通过适当类型的列表执行它。

你所做的总是从你的函子返回相同的类型,这破坏了它作为函子的目的,因此Haskell不允许。

1

考虑的Functor定义:

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

类或方法不限制类型ab ,所以你定义的任何fmap必须适用于任何类型的ab。你可以定义自己的类型类,例如:

class MyFunctor f where 
    myfmap :: (String -> String) -> f String -> f String 

但不会是Functor

+0

好点 - 我认为我有类型的工作,但我想这是上午1点编码对你做的。我回去试图找出符合fmap的类型,但不能这样做。 – josiah 2014-11-23 17:57:24

相关问题