Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 了解其中一个是函子的实例_Haskell_Typeclass_Functor_Either - Fatal编程技术网

Haskell 了解其中一个是函子的实例

Haskell 了解其中一个是函子的实例,haskell,typeclass,functor,either,Haskell,Typeclass,Functor,Either,在我的空闲时间我正在学习哈斯克尔,所以这是一个初学者的问题 在我的阅读资料中,我遇到了一个例子,说明了或如何成为函子的实例: instance Functor (Either a) where fmap f (Right x) = Right (f x) fmap f (Left x) = Left x 现在,我试图理解为什么在右值构造函数的情况下实现映射,而在左的情况下不映射 以下是我的理解: 首先让我将上面的实例重写为 instance Functor (Either a)

在我的空闲时间我正在学习哈斯克尔,所以这是一个初学者的问题

在我的阅读资料中,我遇到了一个例子,说明了
如何成为
函子的实例:

instance Functor (Either a) where
    fmap f (Right x) = Right (f x)
    fmap f (Left x) = Left x
现在,我试图理解为什么在
值构造函数的情况下实现映射,而在
的情况下不映射

以下是我的理解:

首先让我将上面的实例重写为

instance Functor (Either a) where
    fmap g (Right x) = Right (g x)
    fmap g (Left x) = Left x
现在:

  • 我知道
    fmap::(c->d)->fc->fd

  • 如果我们用
    a
    替换
    f
    ,我们得到
    fmap::(c->d)->a c->a d

  • Right(gx)
    的类型是
    a(gx)
    ,而
    gx
    的类型是
    d
    ,因此我们有
    Right(gx)
    的类型是
    或者是d
    ,这是我们从
    fmap
    中所期望的(见上文2)

  • 现在,如果我们看一下
    左(gx)
    ,我们可以用同样的推理说它的类型是
    要么(gx)b
    ,也就是
    要么db
    ,这不是我们从
    fmap
    中所期望的(见上文2)
    d
    应该是第二个参数,而不是第一个!因此,我们无法映射到
    左侧


  • 我的推理正确吗?

    这是正确的。这种行为还有另一个相当重要的原因:您可以将
    a b
    视为一个计算,它可能成功并返回
    b
    ,或者失败并显示错误消息
    a
    。(这也是monad实例的工作方式)。因此,函子实例不会触及
    Left
    值是很自然的,因为您希望映射到计算,如果计算失败,就没有什么可操作的了。

    您的帐户当然是正确的。也许我们在处理这样的实例时遇到困难的原因是我们实际上一次定义了无限多个函子实例——每个可能的
    类型一个。但是函子实例是一种对系统中无限多个类型进行操作的系统方法。因此,我们定义了无限多的系统操作方式,在系统中无限多的类型上进行操作。这个例子涉及两个方面的普遍性

    不过,如果你分阶段来做,也许就没那么奇怪了。这些类型中的第一种是使用单位类型
    ()
    及其唯一合法值
    ()
    的长篇版本

    在这里,我们可能会感到疲劳,并进行抽象:

    data Unless a b    = Mere a     | Genuine b
    
    现在我们创建函子实例,没有问题,第一个看起来很像
    的实例,可能是

    instance Functor MightBe where
      fmap f (Nope ()) = Nope ()   -- compare with Nothing
      fmap f (Yep x)   = Yep (f x) -- compare with Just (f x)
    
    instance Functor UnlessError where
      fmap f (Bad str) = Bad str   -- a more informative Nothing
      fmap f (Good x)  = Good (f x)
    
    instance Functor ElseInt where
      fmap f (Else n) = Else n 
      fmap f (Value b) = Value (f b)
    
    但是,再一次,为什么要麻烦呢,让我们做一个抽象:

    instance Functor (Unless a) where
      fmap f (Mere a) = Mere a
      fmap f (Genuine x) = Genuine (f x)
    
    由于未触及
    ()
    字符串
    Int
    值,因此不会触及
    仅仅是a
    术语

    现在,我想知道为什么 在应用程序中的实现映射 正确的值构造函数,但不正确 如果是左撇子

    在这里插上电源,可能会有意义

    假设a=String(错误消息) 您可以将a应用于Float

    所以你有一个f:Float->Integer,比如舍入

    (任意字符串)(浮点)=任意字符串浮点

    现在(FMAPF)::任意字符串浮点->任意字符串整数 那么你打算用f做什么?f不知道如何处理字符串,所以在那里你不能做任何事情。也就是说,显然您唯一可以操作的是右值,而左值保持不变

    换句话说,a是函子,因为有这样一个明显的fmap:

    • 对于正确的值,应用f
    • 对于左值,什么都不做

    正如其他人所提到的,
    类型在其两个参数中都是函子。但在Haskell中,我们只能(直接)在类型的最后一个参数中定义函子。在这种情况下,我们可以使用
    newtype
    s来绕过限制:

    newtype FlipEither b a = FlipEither { unFlipEither :: Either a b }
    
    因此,我们有一个构造函数
    flipother::other a b->flipother b a
    ,它用交换的类型参数将
    other
    包装到
    newtype
    中。我们有dectructor
    unflipother::flipother b a->或a b
    ,可以将其展开。现在我们可以在
    FlipOrther
    的最后一个参数中定义一个函子实例,它实际上是
    Orther
    的第一个参数:

    instance Functor (FlipEither b) where
        fmap f (FlipEither (Left x))  = FlipEither (Left (f x))
        fmap f (FlipEither (Right x)) = FlipEither (Right x)
    
    请注意,如果我们忘记了
    FlipOrther
    一段时间,我们只会得到
    Orther
    Functor
    的定义,只交换了
    Left
    /
    Right
    。现在,每当我们在
    任一
    的第一个类型参数中需要一个
    函子
    实例时,我们可以将该值包装到
    FlipOrther
    中,然后将其展开。例如:

    fmapE2 :: (a -> b) -> Either a c -> Either b c
    fmapE2 f = unFlipEither . fmap f . FlipEither
    

    更新:看一下,其中
    (,)
    是的实例。每个都有两个参数,每个参数中都有一个函子。这反映在
    Bifunctor
    的方法
    first
    second

    Bifunctor
    的定义非常对称:

    instance Bifunctor Either where
        bimap f _ (Left a)  = Left (f a)
        bimap _ g (Right b) = Right (g b)
    
        first  f = bimap f id
    
        second f = bimap id f
    

    我还没有了解单子:)我读到,
    或者a b
    按照您描述的方式使用,
    a
    表示错误信息:但这只是一个约定,对吗?@MarcoS:正确,这只是一个约定。任何一种都可以解释为析取:a b类型的值包含a类型的值或b类型的值,但不能同时包含两者;左右类型之间没有区别。但是作为一个函子,在这些例子中,你可以用fmap覆盖as(任意一个字符串),这是完全不对称的。进入具体函子insta的类型
    instance Bifunctor Either where
        bimap f _ (Left a)  = Left (f a)
        bimap _ g (Right b) = Right (g b)
    
        first  f = bimap f id
    
        second f = bimap id f