Direct Manipulation[Shneiderman, 1983]
Shneidermanによって提唱された対象が直感的、身体的に操作でき、すぐに結果がフィードバックされるインタラクションのスタイル
DMである例、そうでない例
Visual Programming Language
パーサ同士を組み合わせて新しいパーサをつくる技法。
Parser
"(10 20 30)"
List(10,20,30)
入力文字列
出力データ
abstract class Parser[+A] extends
(String => A)
Parser
"(10 20 30) (.... "
List(10,20,30)
+
"(..."
入力文字列
出力データ
+
続きの文字列
abstract class Parser[+A] extends
(String => (A, String))
"(10, 20, "
Error!!!
Parser
"(10 20 30) (.... "
List(10,20,30)
+
"(..."
abstract class Parser[+A] extends String => Result[A]
abstract class Result[+A]
case class Success[+A](item:A,next:String) extends Result[A]
case class Error(msg:String) extends Result[Nothing]
"(10, 20, "
Error!!!
Parser
"(10 20 30) (.... "
List(10,20,30)
+
"(..."
sum
60
f
"(10, 20, "
Error!!!
Parser
"(10 20 30) (.... "
List(10,20,30)
+
"(..."
sum
60
+
"(.."
f
Parser
sum
f
map
=
New Parser!!
abstract class Parser[+A] extends (String => Result[A]) { p =>
def map[B](f: A => B) : Parser[B] = new Parser[B]{
def apply(input: Text) : Result[B] =
p(input) match {
case Success(a, next) => Success(f(a), next)
case Error(msg) => Error(msg)
}
}
}
parserA map (x => x + 1)
Parser
flatMap
f
A
Parser
Parser1
List(10,20,30)
+
"(..."
f
Parser2
abstract class Parser[+A] extends (String => Result[A]) { p =>
def flatMap[B](f: A => Parser[B]) : Parser[B] = new Parser[B]{
def apply(input: Text) : Result[B] =
p(input) match {
case Success(a, next) =>
val newParser = f(a)
newParser(next)
case Error(msg) => Error(msg)
}
}
}
Parser1
"(10 20 30)
concat (.... "
List(10,20,30)
+
"concat (..."
Parser2
"concat (..."
Concat
+
"(..."
Parser
"(10 20 30)
concat (.... "
List(10,20,30)
+
"concat (..."
Concat
+
"(..."
Parser
(List(10,20,30)
+
Concat)
+
"(..."
abstract class Parser[+A] extends (String => Result[+A]) { p1 =>
def ~[B](p2: Parser[B]) : Parser = new Parser[(A,B)] {
val apply(input: String) => Result[(A,B)] = {
val p3 =
for{ a <- p1
b <- p2
} yield (a,b)
p3(input)
}
}
}
case class Add(x: Double, y: Double)
val double : Parser[Double] = ...
val plus : Parser[String] = ....
val add : Parser[Add] = (double ~ plus ~ double) map { ((x, _), y) => Add(x,y) }
Parser
"(10 20 30)"
List(10,20,30)
入力文字列
出力データ
Parser
List(10,20,30)
Seq[A]
出力データ
出力列
Parser
MoveUp
Seq[(Double,
Double)]
出力データ
出力列
abstract class Parser[Input,+T] extends (Input=>Result[Input, T])
abstract class Result[Input, +T]
case class Success[Input, +T] (t: T, input: Input) extends Result[Input, +T]
case class Error[Input](msg: String) extends Result[Input, Nothing]
case class Vector2(x:Double, y:Double)
class Gesture[+T] extends Parser[Vector2, T]
case class Vector2(x: Double, y: Double) {
def +(o: Vector2) = Vector2(x + o.x, y + o.y)
def -(o: Vector2) = Vector2(x - o.x, y - o.y)
def *(f: Double) = Vector2(x * f, y * f)
def *(o: Vector2) = x * o.x + y * o.y
def /(f: Double) = this * (1 / f)
def magnitude = math.sqrt(x * x + y * y)
def normalize = this / magnitude
def angle = math.atan2(y, x)
}
trait Parser {
type Elem
type Input = Reader[Elem]
...
abstract class Parser[+T] extends (Input => ParseResult[T])
....
}
abstract class Reader[+T] {
def atEnd: Boolean
def first: T
def pos: Position
def rest: Reader[T]
....
}
trait Position {
def line: Int
def column: Int
....
}
class GestureReader( val data: List[Vector2], override val offset: Int ) extends Reader[Vector2] {
def this( data: List[Vector2] ) = this( data, 0 )
class GesturePosition( val offset: Int ) extends Position
{
override val line = 1
override def column = offset + 1
override def lineContents: String = ""
}
override def atEnd = offset >= (data.length - 1)
override def first = data( offset )
override def pos = new GesturePosition( offset )
override def rest = new GestureReader( data, offset + 1 )
}
object Gesture{
trait Atom {
val pos : Vector2
}
object Atom {
case class Idle(pos:Vector2) extends Atom
case class Up(startPos:Vector2, pos:Vector2) extends Atom
case class Down (startPos:Vector2, pos:Vector2) extends Atom
case class Left (startPos:Vector2, pos:Vector2) extends Atom
case class Right (startPos:Vector2, pos:Vector2) extends Atom
}
}
case class Gesture(last:Gesture.Atom, history:List[Gesture.Atom])
case class Gesture(last:Gesture.Atom, history:List[Gesture.Atom])
(currentGesture:Gesture)=>(atom:Atom)=>Gesture
val pos : Parser[Vector2] = elem("POS", e => true)
def gesture(g:Gesture) : Parser[Gesture] =
atom(g).flatMap(gesture) | atom(g)
def atom(g:Gesture) = up(g) | down(g) | left(g) | right(g) | idle
def idle(g:Gesture) : Parser[Gesture] =
(pos ^^ { p => (p,g)}).filter { ... }
def move(g:Gesture) : Parser[Move] = { .. }
def up(g:Gesture) : Parser[Gesture] = ...
def down(g:Gesture) : Parser[Gesture] = ..
def left(g:Gesture) : Parser[Gesture] = ...
def right(g:Gesture): Parser[Gesture] = ...