Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.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
Scala 如何表达函数类型?_Scala_Haskell_Functional Programming_Existential Type - Fatal编程技术网

Scala 如何表达函数类型?

Scala 如何表达函数类型?,scala,haskell,functional-programming,existential-type,Scala,Haskell,Functional Programming,Existential Type,我目前正在阅读Hutton和Meijer关于Haskell中分析组合词的论文。为了实现它,我正在尝试在scala中实现它们。我想构造一些易于编码、扩展并且简单优雅的东西。我为下面的haskell代码提供了两种解决方案 /* Haskell Code */ type Parser a = String -> [(a,String)] result :: a -> Parser a result v = \inp -> [(v,inp)] zero :: Parser a ze

我目前正在阅读Hutton和Meijer关于Haskell中分析组合词的论文。为了实现它,我正在尝试在scala中实现它们。我想构造一些易于编码、扩展并且简单优雅的东西。我为下面的haskell代码提供了两种解决方案

/* Haskell Code */
type Parser a = String -> [(a,String)]

result :: a -> Parser a
result v = \inp -> [(v,inp)]

zero :: Parser a
zero = \inp -> []

item :: Parser Char
item = \inp -> case inp of
            [] -> []
            (x:xs) -> [(x,xs)]


/* Scala Code */
object Hutton1  {

  type Parser[A] = String => List[(A, String)]

  def Result[A](v: A): Parser[A] = str => List((v, str))
  def Zero[A]: Parser[A] = str => List()
  def Character: Parser[Char] = str => if (str.isEmpty) List() else List((str.head, str.tail))

}

object Hutton2 {
  trait Parser[A] extends (String => List[(A, String)])

  case class Result[A](v: A) extends Parser[A] {
    def apply(str: String) = List((v, str))
  }

  case object Zero extends Parser[T forSome {type T}] {
    def apply(str: String) = List()
  }

  case object Character extends Parser[Char] {
    def apply(str: String) = if (str.isEmpty) List() else List((str.head, str.tail))
  }
}


object Hutton extends App {
  object T1 {
    import Hutton1._

    def run = {
      val r: List[(Int, String)] = Zero("test") ++ Result(5)("test")
      println(r.map(x => x._1 + 1) == List(6))
      println(Character("abc") == List(('a', "bc")))
    }
  }

  object T2 {
    import Hutton2._

    def run = {
      val r: List[(Int, String)] = Zero("test") ++ Result(5)("test")
      println(r.map(x => x._1 + 1) == List(6))
      println(Character("abc") == List(('a', "bc")))
    }
  }

  T1.run
  T2.run
}
问题1 在Haskell中,零是一个可以按原样使用的函数值,用于排除所有失败的解析器,无论它们是Parser[Int]类型还是Parser[String]类型。在scala中,我们通过调用函数Zero(第一种方法)实现了同样的效果,但通过这种方式,我相信每次调用Zero时,我都会生成一个不同的函数。这句话是真的吗?有没有办法缓解这种情况

问题2 在第二种方法中,零大小写对象使用存在的
类型解析器[T forSome{type T}]
扩展解析器。如果我用
Parser[\u]
替换类型,我会得到编译错误

Error:(19, 28) class type required but Hutton2.Parser[_] found
      case object Zero extends Parser[_] {
                           ^
我认为这两个表达式在哪里是等价的。是这样吗

问题3 在这两种方法中,您认为哪种方法能够在优雅和简单的方面表达出更好的结果

我使用scala 2.11.8

问题1 我认为你是对的,原因如下:
Zero1
下面每次使用它都会打印
hello
。解决方案是使用
val

def Zero1[A]: Parser[A] = { println("hi"); str => List() }
val Zero2: Parser[Nothing] = str => List()
问题2 不知道。我还是从Scala开始。希望有人能回答这个问题

问题3 trait one将更好地使用Scala的
for
(因为您可以定义自定义
flatMap
map
),它(有点)类似于Haskell的
do
。以下是您所需要的全部内容

trait Parser[A] extends (String => List[(A, String)]) {
  def flatMap[B](f: A => Parser[B]): Parser[B] = {
      val p1 = this
      new Parser[B] {
        def apply(s1: String) = for {
          (a,s2) <- p1(s1)
          p2 = f(a)
          (b,s3) <- p2(s2)
      } yield (b,s3)
    }
  }

  def map[B](f: A => B): Parser[B] = {
    val p = this
    new Parser[B] {
      def apply(s1: String) = for ((a,s2) <- p(s1)) yield (f(a),s2) 
    }
  }
}
然后,您可以编写如下内容:

val parser: Parser[(Char,Char)] = for {
  x <- choice(unit('x'),char)
  y <- char
} yield (x,y)
val解析器:解析器[(Char,Char)]=for{

注:我没有编译它,但我知道问题所在,可以提出两种解决方案

  • 更为Haskellish的方法是不使用子类型,而是将
    zero
    定义为多态值。在这种风格中,我建议将解析器定义为一个case类的值,而不是从函数类型派生的
    object
    s:

    final case class Parser[T](run: String => List[(T, String)])
    def zero[T]: Parser[T] = Parser(...)
    
    如@Alec所示,是的,每次都会产生一个新值,因为
    def
    被编译成一个方法

  • 如果您想使用子类型,您需要使
    解析器
    协变。然后您可以给
    一个底部结果类型:

    trait Parser[+A] extends (String => List[(A, String)])
    case object Zero extends Parser[Nothing] {...}
    

  • 在某种程度上,这些都是非常相关的;在系统F_+1中,感谢您回答第一个和第三个问题。我没有想到使用scala的底部类型,但它似乎是有效的!注意:您可以跳过
    val p=this
    ,方法是在trait中使用self类型“易于编码、扩展且简单优雅”一个真正的函数式程序员!我也在考虑多态值,但我不知道你是否可以在scala中做类似的事情。协方差为+1
    trait Parser[+A] extends (String => List[(A, String)])
    case object Zero extends Parser[Nothing] {...}