如何将Haskell翻译成Scalaz?

TOB*_*TOB 7 haskell scala functor scalaz

我的一个高中生和我将尝试将一个Haskell的Parsec解析器组合库移植到Scala中.(它比Scala的内置解析库更有优势,你可以相当容易地传递状态,因为所有的解析器都是monad.)

我遇到的第一个故障是试图弄清楚Functor在scalaz中的工作原理.有人可以解释如何转换此Haskell代码:

data Reply s u a = Ok a !(State s u) ParseError
                 | Error ParseError


instance Functor (Reply s u) where
    fmap f (Ok x s e) = Ok (f x) s e
    fmap _ (Error e) = Error e -- XXX
Run Code Online (Sandbox Code Playgroud)

进入Scala(我假设使用Scalaz).我得到了

sealed abstract class Reply[S, U, A]
case class Ok[S, U, A](a: A, state: State[S, U], error: ParseError)
    extends Reply[S, U, A]
case class Error[S, U, A](error: ParseError) extends Reply[S, U, A]
Run Code Online (Sandbox Code Playgroud)

并知道我应该Reply扩展这个scalaz.Functor特性,但我无法弄清楚如何做到这一点.(大多数情况下,我无法弄清楚F[_]参数的作用.)

任何帮助赞赏!

谢谢,托德

根据dflemstr的回答,我想出了这个:

sealed abstract class Reply[S, U, A]
object Reply {
  implicit def ReplyFunctor[S, U]  = {
    type ReplySU[A] = Reply[S, U, A]
    new Functor[ReplySU] {
      def fmap[A, B](r: ReplySU[A], f: A => B) = r match {
        case Ok(a, state, error) => Ok(f(a), state, error)
        case Error(error) => Error[S, U, B](error)
      }
    }
  }
}
case class Ok[S, U, A](a: A, state: State[S, U], error: ParseError) 
    extends Reply[S, U, A]()
case class Error[S, U, A](error: ParseError) extends Reply[S, U, A]()
Run Code Online (Sandbox Code Playgroud)

我不确定的是那种ReplySU[A]类型.FunctorHaskell中的实际内容是Reply s ucurried类型,a缺少类型.这是我在Scala中应该做同样的事情还是我过于复杂的事情?

dfl*_*str 10

Functor[F[_]],它F意味着它是一个类型构造函数,即一个参数化类型,必须将一些其他类型作为参数才能成为完全限定类型.例如,if Fis List,则List[Int]是该参数化类型的类型实例.

因此,当您定义类型的值时Functor[List],意味着它是描述Lists 的函子性质的对象,并且仿函数对象将使用高阶类型List来构造各种类型实例,例如List[A]List[B].

此外,您必须了解Scala的类和Haskell类之间的区别.Haskell中的类实例最好用Scala中的隐式值建模,而不是接口的实现; 虽然您需要一个对象实例在Java/Scala中也有一个接口实例,但您可以在Haskell中拥有一个类的实例,而不需要该类处理的值类型的实例.

想象一下,例如,如何Read在Scala中实现Haskell中的类.的Read类从字符串反序列化值; 有一个read带有类型的函数,Read a => String -> a因此对于任何a具有Read实例的类型,您可以将a String转换为类型的实例a.如果您使用Scala中的接口对其进行建模,那么class Foo implements Read[Foo],您如何将字符串转换为Foo?的实例?你不能打电话,Foo.read因为你还没有Foo; 该read功能应该返回一个!

相反,您创建一个单独的ReadFoo: Read[Foo]对象,其中包含Read该类型的函数的实现Foo.然后你可以安全地打电话ReadFoo.read(string: String): FooFoo后卫.

对于仿函数实例,您需要的是以下内容:

// All implicits in the companion object of Reply are automatically brought into
// scope when Reply is imported
object Reply {
  // Describes how to treat a `Reply` as a functor
  implicit val ReplyFunctor: Functor[Reply] = new Functor[Reply] {
    def fmap[A, B](r: Reply[A], f: A => B) = r match {
      case Ok(x, s, e) => Ok(f(x), s, e)
      case err         => err // leave value unchanged
    }
  }
}
Run Code Online (Sandbox Code Playgroud)