如何为由Either和Maybe组成的Type创建Functor实例

时间:2017-12-20 06:11:21

标签: purescript

我遇到一个类型的Functor实例有问题,该类型基本上只是嵌套了Either和Maybe。

data Tuple a b = Tuple a b
data Primitive = String String | Boolean Boolean | Number Number | Null
data JsonValue = Object (Map String JsonValue) | Array (List JsonValue) | Primitive
type Path = List String
data JsonGraphValue = JsonGraphObject (Map String JsonGraphValue) | Atom JsonValue | Ref Path | Error JsonValue | JsonPrimitive Primitive

newtype JsonGraphRecResult a = JsonGraphRecResult (Either String (Tuple (Maybe a) (List Path)))
instance jsonGraphRecResultFunctor :: Functor JsonGraphRecResult where
  map f (JsonGraphRecResult (Right (Tuple (Just value) paths))) = JsonGraphRecResult (Right (Tuple (Just (f value)) paths))
  map f value = value

我收到以下错误,指向上面代码末尾的“value”字。

  Could not match type

    a1

  with type

    b0


while trying to match type JsonGraphRecResult a1
  with type JsonGraphRecResult b0
while checking that expression value
  has type JsonGraphRecResult b0
in value declaration jsonGraphRecResultFunctor

where b0 is a rigid type variable
      a1 is a rigid type variable

我不清楚为什么JsonGraphRecResult与以下编译好的Blah类型有任何不同:

newtype Blah a = Blah (Maybe a)
instance blahFunctor :: Functor Blah where
  map f (Blah (Just x)) = Blah (Just (f x))
  map f value = value

以下gist可以直接粘贴到“Try PureScript”在线REPL中,以便复制错误。

2 个答案:

答案 0 :(得分:0)

找出问题所在。在Either为Left的情况下,我不能简单地返回map函数的输入值,因为输入值不是正确的类型。这是问题的简化版本。

-- This is wrong because value is a Functor a, whereas map must return Functor b
map value@Nothing f = value

-- This is right, because even though both sides are Nothing, the right-hand side is a Maybe b vs. Maybe a
map Nothing f = Nothing

答案 1 :(得分:0)

您应该能够为您的类型派生Functor个实例。但是,在为最终类型派生实例之前,您应该为Tuple类型派生它(或者只使用Tuple中的Data.Tuple; - )):

data Tuple a b = Tuple a b
derive instance functorTuple :: Functor (Tuple a)

正如您所看到的,Functor实例只能为类型* -> *定义,因此在这种情况下,我们可以map超过类型占用"最后位置"在Tuple

为了导出JsonGraphRecResult的实例,您必须更改其内部Tuple中的类型顺序才能实现"最后位置"要求:

newtype JsonGraphRecResult a =
  JsonGraphRecResult (Either String (Tuple (List Path) (Maybe a)))
derive instance functorJsonGraphRecResult :: Functor JsonGraphRecResult

Heretrypurescript.org上相关的交互式代码段,因此您可以使用此实现。

您可以使用此衍生机制的更多类型类:OrdEqGenericNewtype ...

在这种情况下也值得指出的是,在Purescript中你有额外的派生选项,即" newtype derivedving"。它的语法略有不同,因为它在newtype之后包含derive个关键字 - 例如:

derive newtype instance someClassMyType :: SomeClass MyType

Newtype derived用于newtype"包装"用于派生给定newtype内部类型的类的实例已经定义了实例。换句话说,如果您有newtype T = T a,则可以为T具有a实例的每个类派生Data.Generic.Rep的新类型实例。

还有另一种策略 - 您还可以使用为Generic中的某些类型类定义的方法的泛型实现。这些实现可用于{{1}}类实例的类型......但这是另一个故事; - )

您可以在菲尔" 24天的Purescript"中找到更多关于推导的信息。系列:

https://github.com/paf31/24-days-of-purescript-2016