Scala 如何表达函数类型?
我目前正在阅读Hutton和Meijer关于Haskell中分析组合词的论文。为了实现它,我正在尝试在scala中实现它们。我想构造一些易于编码、扩展并且简单优雅的东西。我为下面的haskell代码提供了两种解决方案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
/* 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] {...}