Fth*_*der 6 haskell functional-programming currying typeclass
在制作我的自定义时Either,Functor为了理解更清晰的类型和类型类,我发现了以下情况:
Functor
module Functor (Functor, fmap) where
import Prelude hiding(Functor, fmap)
class Functor f where
fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
Either
module Either(Either(..)) where
import Prelude hiding(Either(..), Functor, fmap)
data Either a b = Left a | Right b deriving(Show)
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap _ (Left x) = Left x
Run Code Online (Sandbox Code Playgroud)
上面显示的代码编译得很好但是,如果我将其更改为使用id,则无法编译:
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap _ = id
Run Code Online (Sandbox Code Playgroud)
为什么??我错过了什么?以下代码也不起作用:
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f all@(Left x) = all
Run Code Online (Sandbox Code Playgroud)
...这在我看来非常奇怪,因为下面的代码编译:
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
data Point = Point Float Float deriving (Show)
test :: Shape -> String
test (Circle _ x) = show x
test all@(Rectangle _ x) = show all ++ " - "++ show x
Run Code Online (Sandbox Code Playgroud)
先感谢您
让我们看一下专门用于仿Either函数的fmap类型:
fmap :: (a -> b) -> Either e a -> Either e b
Run Code Online (Sandbox Code Playgroud)
正如我们由此可以看出,在fmap f all@(Left _),类型all为Either e a.这Either e b与签名规定的预期结果类型不匹配fmap,因此fmap f all@(Left _) = all不是很好的类型.
同样适用于使用的情况id.
你要做的是归结为:
f :: Either a Bool -> Either a ()
f (Right _) = Right ()
f left = left
Run Code Online (Sandbox Code Playgroud)
有错误:
foo.hs:3:7:
Couldn't match type ‘Bool’ with ‘()’
Expected type: Either a ()
Actual type: Either a Bool
In the expression: left
In an equation for ‘f’: f left = left
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
left绑定到函数参数.所以类型检查器知道它的类型Either a Bool.然后它被用作返回值.我们从类型f :: Either a Bool -> Either a ()中知道返回值必须是类型Either a ().如果left是有效的返回值,则其类型必须与返回类型匹配f.所以Either a ()必须等于Either a Bool; 它不是,因此类型检查器拒绝该程序.
反过来,它基本上是这个问题:
? let l = Left () :: Either () ()
l :: Either () ()
? l
Left ()
it :: Either () ()
? l :: Either () Bool
<interactive>:10:1:
Couldn't match type ‘()’ with ‘Bool’
Expected type: Either () Bool
Actual type: Either () ()
In the expression: l :: Either () Bool
In an equation for ‘it’: it = l :: Either () Bool
Run Code Online (Sandbox Code Playgroud)
我们提供l了绑定和类型,然后尝试将其用作不同类型.那是无效的(通过它id也不会改变它的类型).即使对于类型的值Left ()也是有效的源代码文本Either () Bool,这并不意味着可以使用已知可以使用Either () ()源文本定义的类型的特定值Left (),就像它是类型一样Either () Bool.
如果您有多态值,则可以执行以下操作:
? let l = Left ()
l :: Either () b
? l :: Either () ()
Left ()
it :: Either () ()
? l :: Either () Bool
Left ()
it :: Either () Bool
Run Code Online (Sandbox Code Playgroud)
请注意,l这里的原始值是多态的b; 它可以被用来作为Either () b用于任何湾
但是你的fmap情况略有不同.该函数 fmap是多态的b,但其参数的值是"在多态的范围内"; 在你有你的论证的时候,fmap的调用者b已经选择了某种特定的类型,所以它是"某种未知的类型,可以通过任何东西",而不是"我想选择的任何类型".无法以某种方式将类型的值转换为类型的值,因此您必须提取值,然后创建包含它的值.Either a bEither a caEither a c