как перевести Хаскель в Скалаз? - PullRequest
7 голосов
/ 30 марта 2012

Один из моих старшеклассников и я попытаемся сделать порт библиотеки комбинатора парсеров Parsec на Haskell в Scala.(По сравнению со встроенной библиотекой разбора Scala у нее есть преимущество, заключающееся в том, что вы можете довольно легко передавать состояние, потому что все анализаторы являются монадами.)

Первое, с чем я столкнулся, пытается выяснить, как работает Functor.в скалазе.Может кто-нибудь объяснить, как преобразовать этот код на 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

в 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]

и знаю, что должен заставить 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]()

В чем я не уверен, так это ReplySU[A] тип.Фактический Functor в Haskell равен Reply s u с каррированными типами и отсутствующим типом a.Это то, как я должен делать то же самое в Scala или я слишком усложняю вещи?

Ответы [ 2 ]

10 голосов
/ 30 марта 2012

В Functor[F[_]] F означает, что это конструктор типа , то есть параметризованный тип, который должен принимать некоторый другой тип в качестве параметра, чтобы стать полностью квалифицированным типом. Например, если F равно List, то List[Int] является экземпляром типа этого параметризованного типа.

Таким образом, когда вы определяете значение типа Functor[List], это означает, что это объект, описывающий природу функтора List s, и что объект функтора будет использовать тип высшего порядка List для создания различных экземпляры типа, такие как List[A] и List[B].

Кроме того, вы должны понимать разницу между классами Scala и классами Haskell. Экземпляр класса в Haskell лучше всего моделируется неявным значением в Scala, а не реализацией интерфейса; в то время как вам нужен экземпляр объекта , чтобы также иметь экземпляр интерфейса в Java / Scala, вы можете иметь экземпляр класса в Haskell без имеющий экземпляр типа значения, с которым имеет дело класс.

Представьте, например, как вы реализуете класс Read из Haskell в Scala. Класс Read десериализует значения из строк; есть функция с именем read с типом Read a => String -> a, поэтому для любого типа a с экземпляром Read можно преобразовать String в экземпляр типа a. Если вы смоделируете его с использованием интерфейса в Scala, такого как class Foo implements Read[Foo], как бы вы тогда преобразовали строку в экземпляр Foo? Вы не можете позвонить Foo.read, потому что у вас еще нет Foo; read функция должна возвращать один!

Вместо этого вы создаете отдельный объект ReadFoo: Read[Foo], который содержит реализации функций Read для типа Foo. Затем вы можете позвонить на номер ReadFoo.read(string: String): Foo и получить Foo обратно - безопасно.

Для экземпляра функтора вам нужно следующее:

// 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
    }
  }
}
2 голосов
/ 30 марта 2012

Ах, вы имеете в виду такой порт: https://github.com/runarorama/scarpia ? В общем, эта сторона используется не очень (к сожалению): https://wiki.scala -lang.org / дисплей / SW / Инструменты + и + Библиотеки

...