【问题标题】:How to create a custom parser Monad for SimpleJSON in PureScript?如何在 PureScript 中为 SimpleJSON 创建自定义解析器 Monad?
【发布时间】:2020-12-24 01:16:31
【问题描述】:

我有以下内容,直到我尝试定义readJSON'

newtype JSONWithErr a = JSONWithErr (Writer (Array Foreign.ForeignError) a)

derive newtype instance jsonWithErrApply :: Apply JSONWithErr
derive newtype instance jsonWithErrApplicative :: Applicative JSONWithErr
derive newtype instance jsonWithErrFunctor :: Functor JSONWithErr
derive newtype instance jsonWithErrBind :: Bind JSONWithErr
derive newtype instance jsonWithErrMonad :: Monad JSONWithErr
derive newtype instance jsonWithErrTell :: MonadTell (Array Foreign.ForeignError) JSONWithErr
derive newtype instance jsonWithErrWriter :: MonadWriter (Array Foreign.ForeignError) JSONWithErr

newtype JSONParse a = JSONParse (ExceptT (NonEmptyList ForeignError) JSONWithErr a)

derive newtype instance jsonParseApply :: Apply JSONParse
derive newtype instance jsonParseApplicative :: Applicative JSONParse
derive newtype instance jsonParseFunctor :: Functor JSONParse
derive newtype instance jsonParseBind :: Bind JSONParse
derive newtype instance jsonParseMonad :: Monad JSONParse
derive newtype instance jsonParseTell :: MonadTell (Array Foreign.ForeignError) JSONParse
derive newtype instance jsonParseWriter :: MonadWriter (Array Foreign.ForeignError) JSONParse
derive newtype instance jsonParseThrow :: MonadThrow (NonEmptyList ForeignError) JSONParse

generalize :: forall m a. Monad m => Identity a -> m a
generalize = unwrap >>> pure

-- type Except e = ExceptT e Identity
genExcept :: forall m e a. Monad m => ExceptT e Identity a -> ExceptT e m a
genExcept = unwrap >>> generalize >>> ExceptT

readJSON' :: forall a. JSON.ReadForeign a => String -> JSONParse a
readJSON' s = JSONParse $ genExcept $ (pure >>> JSONWithErr) <$> (JSON.readJSON' s) -}

这里的错误,涵盖了readJSON'的整个定义,是:

Could not match type

    JSONWithErr t2

  with type

    a0


while trying to match type JSONParse t1
  with type JSONParse a0
while checking that expression (apply JSONParse) ((apply genExcept) ((map (...)) (readJSON' s)))
  has type JSONParse a0
in value declaration readJSON'

where a0 is a rigid type variable
        bound at (line 0, column 0 - line 0, column 0)
      t1 is an unknown type
      t2 is an unknown type

我试着简化了一点,但我似乎遇到了约束问题;在下面的简化中,由于早期的错误,键入的孔不起作用:

tmp :: forall a. JSON.ReadForeign a => String -> ExceptT (NonEmptyList ForeignError) JSONWithErr a
tmp s = ?help (JSON.readJSON' s)

还有错误:

  No type class instance was found for

    Simple.JSON.ReadForeign t0

  The instance head contains unknown type variables. Consider adding a type annotation.

while applying a function readJSON'
  of type ReadForeign t0 => String -> ExceptT (NonEmptyList ForeignError) Identity t0
  to argument s
while inferring the type of readJSON' s
in value declaration tmp

【问题讨论】:

  • readJSON' 上的错误是什么?
  • 抱歉遗漏,已更新

标签: monads monad-transformers purescript


【解决方案1】:

我认为你只是被自己的聪明所困扰。

看看genExcept 期望什么类型的参数:ExceptT e Identity a,但你也可以知道e ~ (NonEmptyList ForeignError),因为genExcept 的结果稍后会被包裹在JSONParse

所以genExcept 所期望的参数类型,在readJSON' 的主体中实例化,是ExceptT (NonEmptyList ForeignError) Identity a,有一个方便的类型别名 - F

所以我们可以说它一定是:

(pure >>> JSONWithErr) <$> (JSON.readJSON' s) :: F a

但是look at the return type of JSON.readJSON':

readJSON' :: forall a. ReadForeign a => String -> F a

所以JSON.readJSON' s 已经属于F a 类型

然后你将它包装在一些 pure 中,然后在 JSONWithErr 中,所以整个表达式变成:

(pure >>> JSONWithErr) <$> (JSON.readJSON' s) :: F (JSONWithErr (b a))

对于某些bpure 确定。

这不是genExcept 所期望的。所以很自然地你会得到一个错误。

根据我对您的最终意图的假设,您似乎可以将JSON.readJSON' s 直接传递给genExcept,并且类型会起作用:

readJSON' :: forall a. JSON.ReadForeign a => String -> JSONParse a
readJSON' s = JSONParse $ genExcept $ JSON.readJSON' s

【讨论】:

  • 乔治,我很遗憾我错过了这一点,但很高兴解决方案与所有这些一样合理。我想我最初设置了那个表达式,然后确信我需要类似的东西,并且从未完全重新审视我正在处理的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多