Scala中的类型孔?

时间:2015-12-27 02:47:30

标签: scala haskell

Haskell提供typed holes

示例:

f :: Int -> String -> Bool
f x y = if (x > 10) then True else (g y)

g :: String -> Bool
g s = _

汇编:

Prelude> :l HoleEx.hs
[1 of 1] Compiling Main             ( HoleEx.hs, interpreted )

HoleEx.hs:6:7:
    Found hole `_' with type: Bool
    Relevant bindings include
      s :: String (bound at HoleEx.hs:6:3)
      g :: String -> Bool (bound at HoleEx.hs:6:1)
    In the expression: _
    In an equation for `g': g s = _
Failed, modules loaded: none.

在Scala中编程时,我通常使用???作为我尚未编写的Scala代码中的占位符。

但是,对我来说,使用打字孔似乎更有用。请注意,我可以将else (g y)替换为else (g 55),但我会收到编译时错误:

Prelude> :l HoleEx.hs
[1 of 1] Compiling Main             ( HoleEx.hs, interpreted )

HoleEx.hs:3:39:
    Couldn't match type `Int' with `[Char]'
    Expected type: String
      Actual type: Int
    In the first argument of `g', namely `x'
    In the expression: (g x)
Failed, modules loaded: none.

虽然我可以在Scala中使用???来获取占位符实现来编译,但与洞不同,我会在???时遇到运行时错误。

scala> def g(x: Int): Int = ???
g: (x: Int)Int

scala> g(5)
scala.NotImplementedError: an implementation is missing

Scala是否有打孔?

3 个答案:

答案 0 :(得分:3)

Scala的30只是抛出异常的简写,相当于Haskell的int columnCount = 4; int rowCount = 13; this.tableLayoutPanel1.ColumnCount = columnCount; this.tableLayoutPanel1.RowCount = rowCount; this.tableLayoutPanel1.ColumnStyles.Clear(); this.tableLayoutPanel1.RowStyles.Clear(); this.tableLayoutPanel1.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single; this.tableLayoutPanel1.BackColor = Color.White; this.tableLayoutPanel1.AutoSize = true; for (int i = 0; i < columnCount; i++) { this.tableLayoutPanel1.ColumnStyles.Add( new ColumnStyle(SizeType.Percent, 100 / columnCount)); } for (int i = 0; i < rowCount; i++) { this.tableLayoutPanel1.RowStyles.Add( new RowStyle(SizeType.Absolute, 30)); } this.tableLayoutPanel1.SuspendLayout(); for (var i = 1; i <= 50; i++) { var label = new Label(); label.Text = i.ToString(); label.Font = new Font(label.Font, FontStyle.Bold); label.AutoSize = false; label.Size = new Size(30, 30); label.Image = Properties.Resources.Circle; label.ImageAlign = ContentAlignment.MiddleCenter; label.TextAlign = ContentAlignment.MiddleCenter; label.Dock = DockStyle.Fill; this.tableLayoutPanel1.Controls.Add(label); } this.tableLayoutPanel1.ResumeLayout(); ???或类似的。

然而,据我所知,Scala编译器不支持打字孔。但是,您可以使用undefined并检查IDE或Emacs + Ensime中的类型,以查看其推断类型。

另请注意,与Haskell的Hindley-Milner类型系统的完整类型推断相比,Scala的类型推断非常小,因此在Scala编译器中使用类似的类型的东西甚至不会太有意义,直到Martin Odersky和维护者决定Scala需要升级类型推断,我认为不太可能很快发生(但Typelevel人群可能会做一些烹饪)。

答案 1 :(得分:2)

对我来说,程序中的漏洞可以帮助我推进实施。它通过告诉我接下来需要什么类型来做到这一点。你可以通过触发常规的Scala类型错误来获得类似的东西。

诀窍是定义一个你知道错误的类型,然后使用它。例如:

object hole

然后,您可以在代码中使用它,您将获得适当的类型错误:

screen shot of a compiler error when using a hole

这里的错误告诉我“漏洞”必须是B,这表明我可以通过某种方式使用g来取得进展。如果我将代码推进到a => f(g(hole)),编译器会告诉我hole需要A

这是一种洞,但与其他语言(伊德里斯等)不同......

  • 我的程序只是没有编译,而是没有一个公认的漏洞;
  • 没有任何帮助告诉我范围内的类型(虽然IDE代码完成我提出了一些建议);
  • 我不能很好地命名一个洞;
  • 我无法自动将孔提升到功能定义;
  • 我不能自动解决这个洞(有时像伊德里斯那样);
  • 必须键入预期的返回值,否则Scala会推断hole是可接受的类型!
  • ......可能还有很多其他功能。

正如您所说???是一个有用的占位符,但它的类型为Nothing - 这意味着程序可以编译,但它无助于您填写实现。 至少object hole虽然有点微不足道,但它确实可以为您提供一些类型信息。

答案 2 :(得分:0)

Chris Birchall提供了一个名为scala-typed-holes的Scala编译器插件,该插件可实现类型化的孔:

package example

object Example {

  def foo(x: Int, y: String): Boolean = {
    if (y.length == x) {
       ??? // TODO implement!
    } else {
     true
   }
} 

def bar(x: Int): String = x match {
    case 0 => "zero"
    case 1 => "one"
    case _ => ???
  }
}

生成:

[warn] /Users/chris/code/scala-typed-holes/src/test/scala/example/Example.scala:7:7:
[warn] Found hole with type: Boolean
[warn] Relevant bindings include
[warn]   x: Int (bound at Example.scala:5:11
[warn]   y: String (bound at Example.scala:5:19)
[warn]
[warn]       ??? // TODO implement!
[warn]       ^
[warn] /Users/chris/code/scala-typed-holes/src/test/scala/example/Example.scala:16:15:
[warn] Found hole with type: String
[warn] Relevant bindings include
[warn]   x: Int (bound at Example.scala:13:11)
[warn]
[warn]     case _ => ???
[warn]               ^