トポロジカルソート

前方参照できる型推論をするには依存関係を調べて順番に並べる必要があります。
どう調べたら良いのかと調べてたらトポロジカルソートをするのが基本みたいでした。

https://gist.github.com/ThiporKong/4399695

tsort.scalaで検索したら凄く短いけど、分からないので普段使わない関数は書き換えていつも使っている関数に書き直してみました。
それでもうまく説明が出来ないので、検索してみると以下のページが分かりやすかったです。

http://ameblo.jp/mingw/entry-10389158344.html

参照されていない物から取り除いて無くなるまで繰り返し、参照されていない物がないのに、まだ、残っていれば循環参照があるのでエラーにすればよいのです。

もしくは、逆に参照していない物から取り除けばよいのです。githubにあったソースは参照していない物から取り除く物でした。

以下ソースです。
余計なprintlnも書いてありますが、動きを把握するのに入れたので邪魔であれば消すと良いかと思います。

package tsort

object main extends App {

  // 参照してない物から取り除く
  def tsort[A](toPreds: Map[A, Set[A]], done: List[A]): Iterable[A] = {
    println("tsort "+toPreds+" done "+done)

    // 参照していないものと参照しているものを分ける
    val (noPreds, hasPreds) = toPreds.foldLeft((Map[A,Set[A]](),Map[A,Set[A]]())) {
      case ((no,has),(a1,a2)) =>
        if(a2.isEmpty) (no+(a1->a2),has) else (no,has+(a1->a2))
    }

    println("no  = "+noPreds)
    println("has = "+hasPreds)

    // 参照していない集合が空
    if (noPreds.isEmpty) {
      // 参照している集合も空なら終わり
      if (hasPreds.isEmpty) done
      // 参照をもっている物があれば循環参照があるのでエラー
      else sys.error(hasPreds.toString)
    } else {
      // 参照していない物を取り出す
      val found = noPreds.map { case (a1, a2) => a1 }
      println("found=" + found)
      // 参照している集合から、参照していない名前を取り除く
      val nextPreds = hasPreds.map{ case (p, a) => (p, a -- found) }
      // 再帰呼び出しする
      tsort(nextPreds, done ++ found)
    }
  }

  // 参照されてない人から取り除く
  def tsort2(src:Map[String,Set[String]], done: List[String]):List[String] = {
    // 参照されていないひとを探す

    // 参照されている人の集合を作る
    val finds = src.foldLeft(Set[String]()){
      case (s,(a1,a2)) => s ++ a2
    }
    println("finds="+finds)
    // 参照されてない人と、参照されている人を分ける
    val (no,has) = src.foldLeft(List[String](), Map[String,Set[String]]()) {
      case ((no,has),(a1,a2)) => if (finds.contains(a1)) (no,has+(a1->a2)) else (a1::no,has)
    }
    println("no ="+no)
    println("has="+has)
    // 参照されていない人がいない
    if(no.isEmpty) {
      // 参照されている人もいない
      if(has.isEmpty) {
        return done
      } else {
        throw new Exception("error "+has)
      }
    }
    // 参照されていない人がいる
    tsort2(has,no:::done)
  }

  val graph = Map(
   "ast" -> Set[String](),
   "ast1" -> Set[String](),
   "main" -> Set("parse", "type"),
   "parse" -> Set("ast", "type"),
   "type" -> Set("ast"))
  println(tsort(graph, List()))

  println(tsort2(graph,List()))
}

四則演算

Haskellの型システムが気になって何年かぶりにHaskellを使ってみました。
もう殆ど忘れていたのだけど、一から勉強するよりは楽に使えたのだと思います。
正規表現ライブラリを使って標準入力の引数を四則演算するだけの物を作ってみました。

import Text.Regex.Posix
import System.Environment 

data E
  = EInt Integer
  | EVar String
  | EAdd E E
  | ESub E E
  | EMul E E
  | EDiv E E
  deriving(Show, Eq)

data Tk
  = TkInt Integer
  | TkVar String
  | TkOp String
  deriving(Show, Eq)

main = do
  v <- getArgs
  e <- return (head v)
  print e
  b <- return (let (c,_) = parse e in c)
  print b
  print (eval b)

lexx :: String -> [Tk]
lexx src = 
   case (src =~ "^[ \n\t\r]*(([0-9]+)|([_a-zA-Z][_a-zA-Z0-9]*)|([+*/\\-]+))" :: [[String]]) of
    [] -> []
    [[k1,_,i,"",""]] -> (TkInt (read i :: Integer)) : (lexx (drop (length k1) src))
    [[k1,_,"",id,""]] -> (TkVar id) : (lexx (drop (length k1) src))
    [[k1,_,"","",op]] -> (TkOp op) : (lexx (drop (length k1) src))


parse :: String -> (E,[Tk])
parse l = expr (lexx l)

expr :: [Tk] -> (E,[Tk])
expr xs = rep(term xs)
  where
    rep(x1,(TkOp "+"):xs2) = let (x3,xs3) = term xs2 in rep(EAdd x1 x3, xs3)
    rep(x1,(TkOp "-"):xs2) = let (x3,xs3) = term xs2 in rep(ESub x1 x3, xs3)
    rep(x,xs) = (x, xs)

term :: [Tk] -> (E,[Tk])
term xs = rep(fact xs)
  where
    rep(x1,(TkOp "*"):xs2) = let (x3,xs3) = fact xs2 in rep(EMul x1 x3, xs3)
    rep(x1,(TkOp "/"):xs2) = let (x3,xs3) = fact xs2 in rep(EDiv x1 x3, xs3)
    rep(x1,xs1) = (x1,xs1)

fact :: [Tk] -> (E,[Tk])
fact ((TkInt i):xs) = (EInt i, xs)
fact ((TkVar id):xs) = (EVar id, xs)
fact xs = (EInt 0, xs)

eval :: E -> Integer
eval(EInt a) = a
eval(EAdd a b) = (eval a) + (eval b)
eval(ESub a b) = (eval a) - (eval b)
eval(EMul a b) = (eval a) * (eval b)
eval(EDiv a b) = (eval a) `div` (eval b)

追記:

一般的なHaskellでのパーサはParsec3やattoparsecを使います。*1 *2
正規表現については*3*4を参考にしました。

*1:Utotch Blog:Haskell で parser を書くには 初心者編 http://utotch.blogspot.jp/2011/12/haskell-parser.html

*2:とりあえず雑記帳:04 attoparsec https://sites.google.com/site/toriaezuzakki/haskell/attoparsec

*3:sirocco の書いてもすぐに忘れるメモ:Haskell正規表現すげー !!http://d.hatena.ne.jp/sirocco/20090416/1239852340

*4:すぐに忘れる脳みそのためのメモ:Haskell正規表現 http://jutememo.blogspot.jp/2008/07/haskell.html

C2E6

いい加減な実装ですけど、関数を追加しました。ラムダ計算だと簡単に追加出来ていいです。

{val add = (a)=>(b)=>a+b; add(1)(2)}

1+2=3を計算出来ます。

{(a)=>(b)=>a+b}(1)(2)だと名前無しで実行出来る。

ひたすら手計算で環境をああしてこうしてって考えていたので、環境を保存する考えが今までよりより直感的に分かっていたのでさくっと実装出来た。

package C2E6

import util.parsing.combinator._

object parser extends RegexParsers{

  def expr: Parser[E] = term~rep("+"~>term) ^^ {
    case a ~ b => b.foldLeft[E](a){case (a, b)=> EAdd(a,b)}
  }

  def term : Parser[E] = app~rep("*"~>app) ^^ {
    case a ~ b => b.foldLeft[E](a){case(a, b) => EMul(a,b)}
  }

  def app : Parser[E] = factor~rep("("~>factor<~")") ^^ {
    case a ~ b => b.foldLeft[E](a){case(a, b) => EApp(a,b)}
  }

  def factor: Parser[E] = intLiteral | valExpr | id | fun | "("~>expr<~")" | block | unit

  def fun: Parser[E] = ("("~>id<~")") ~ ("=>"~> expr) ^^ {
    case (EId(a)~b) => EFun(Map(),a,b)
  }

  def unit: Parser[E] = ";" ^^ {
    a => EUnit
  }

  def block: Parser[E] = "{" ~> rep(expr) <~ "}" ^^ {
    a =>
      def c2e(l:List[E]):E = {
        l match {
          case List() => EUnit
          case List(a) => a
          case ELet(a,b,EUnit)::c => ELet(a, b, c2e(c))
          case a::b => ELet(null, a, c2e(b))
        }
      }
      ELet(null,EUnit,c2e(a.filter{a=>a != EUnit}))
  }

  def valExpr : Parser[E] = ("val"~>id)~("="~>expr) ^^ {
    case(EId(a) ~ b) => ELet(a, b, EUnit)
  }

  def intLiteral : Parser[E] = """-?[1-9][0-9]*|0""".r ^^ {
    a => EInt(a.toInt)
  }

  def id : Parser[EId] = """[_a-zA-Z][_a-zA-Z0-9]*""".r ^^ {
    a => EId(a)
  }

  def parse(str:String) = {
    parseAll(expr, str) match {
      case Success(tree,_) => tree
      case e => throw new Exception(""+e)
    }
  }
}

sealed trait E

case class EInt(a:Int) extends E
case class EAdd(a:E,b:E) extends E
case class EMul(a:E,b:E) extends E
case class ELet(a:String, b:E, c:E) extends E
case class EId(a:String) extends E
case class EFun(m:Map[String,E], a:String, b:E) extends E
case class EApp(a:E, b:E) extends E

object EUnit extends E

object Main {

  def main(argv:Array[String]) {

    test(Map(),"1",EInt(1))
    test(Map("a"->EInt(1)),"a", EId("a"))
    test(Map(),"1+2", EAdd(EInt(1),EInt(2)))
    test(Map(),"val a = 1", ELet("a",EInt(1),EUnit))
    test(Map(),"{}", ELet(null, EUnit, EUnit))

    test(Map(),"{1}",ELet(null,EUnit,EInt(1)))
    test(Map("a"->EInt(1)),"{a}", ELet(null,EUnit,EId("a")))
    test(Map(),"{1+2}", ELet(null,EUnit,EAdd(EInt(1),EInt(2))))
    test(Map(),"{val a = 1}", ELet(null,EUnit,ELet("a",EInt(1),EUnit)))
    test(Map(),"{{}}", ELet(null, EUnit,ELet(null, EUnit, EUnit)))

    test(Map(),"{1 1}",ELet(null, EUnit,ELet(null,EInt(1),EInt(1))))
    test(Map(),"{1 2 3}",ELet(null, EUnit, ELet(null,EInt(1),ELet(null, EInt(2), EInt(3)))))
    test(Map(),"{val a = 1 a}", ELet(null,EUnit,ELet("a",EInt(1),EId("a"))))
    test(Map(),"{val a = 1 val b = 2}",ELet(null,EUnit, ELet("a",EInt(1),ELet("b",EInt(2),EUnit))))
    test(Map(),"{{ val a = 1} val b = 2}",ELet(null,EUnit, ELet(null,ELet(null,EUnit, ELet("a",EInt(1),EUnit)),ELet("b",EInt(2),EUnit))))
    test("{val a = 5 { val a = 1 {}} val b = 2 a}", EInt(5))
    test(Map(),"(a)=>a", EFun(Map(),"a", EId("a")))
    test(Map(),"((a)=>a)(2)", EApp(EFun(Map(), "a", EId("a")),EInt(2)))
    test("((a)=>a+a)(4)", EInt(8))
    test("((a)=>(b)=>a+b)(4)(5)", EInt(9))
    test("{val f4=((a)=>(b)=>a+b)(4) val f2=((a)=>(b)=>a+b)(2) f4(5)+f2(8)}", EInt(19))
    test("{(a)=>(b)=>(c)=>a+b*c}(4)(5)(6)", EInt(34))
    test("{val a = 1 val f=(b)=>a+b f(2)}", EInt(3))
    test("{val a = 1 a}", EInt(1))
    test("{1}", EInt(1))
  }

  def test(env:Map[String,E],s:String,e:E) {
    val e2 = parser.parse(s)
    if (e2 != e) throw new Exception("error "+s+"  expected "+e+" but found "+e2)
    println(s+"="+eval(env,e2))
  }

  def test(s:String,e:E) {
    val e2 = parser.parse(s)
    println("test "+s)
    val e3 = eval(Map(), e2)
    if (e3 != e) throw new Exception("error "+s+"  expected "+e+" but found "+e3)
    println(s+"="+e3)
  }

  def eval(env:Map[String,E], e:E):E = {
    println("eval "+env+" |- "+e)
    e match {
    case EInt(a) => EInt(a)
    case EAdd(a, b) =>
      (eval(env,a),eval(env, b)) match {
        case (EInt(a1), EInt(b1)) => EInt(a1 + b1)
        case _ => throw new Exception("error "+e)
      }
    case EMul(a, b) =>
      (eval(env,a),eval(env, b)) match {
        case (EInt(a1), EInt(b1)) => EInt(a1 * b1)
        case _ => throw new Exception("error "+e)
      }
    case ELet(null, b, c) => eval(env,b); eval(env,c)
    case ELet(a, b, c) => eval(env+(a->eval(env,b)),c)
    case EId(a) => env(a)
    case EFun(m,a,b) => EFun(env,a,b) 
    case EApp(a, b) =>
      (eval(env,a),eval(env, b)) match {
        case (EFun(m,name,body), b1:E) => eval(m+(name->b1), body)
        case _ => throw new Exception("error "+e)
      }
    case EUnit => EUnit
    }
  }
}

C2Eを変えてみる

パーサ追加して、簡単な評価器を付けてみましたよ。
これをどんどん拡張していけば、バックエンドはmincamlとかと同じ物を使ったり出来て楽しいのではないかと思います。

package C2E5

import util.parsing.combinator._

object parser extends RegexParsers {

  def expr: Parser[E] = term~rep("+"~>term) ^^ {
    case a ~ b => b.foldLeft[E](a){case (a, b)=> EAdd(a,b)}
  }

  def term : Parser[E] = factor~rep("*"~>factor) ^^ {
    case a ~ b => b.foldLeft[E](a){case(a, b) => EMul(a,b)}
  }

  def factor: Parser[E] = intLiteral | valExpr | id | "("~>expr<~")" | block | unit

  def unit: Parser[E] = ";" ^^ {
    a => EUnit
  }

  def block: Parser[E] = "{" ~> rep(expr) <~ "}" ^^ {
    a =>
      def c2e(l:List[E]):E = {
        l match {
          case List() => EUnit
          case List(a) => a
          case ELet(a,b,EUnit)::c => ELet(a, b, c2e(c))
          case a::b => ELet(null, a, c2e(b))
        }
      }
      ELet(null,EUnit,c2e(a.filter{a=>a != EUnit}))
  }

  def valExpr : Parser[E] = ("val"~>id)~("="~>expr) ^^ {
    case(EId(a) ~ b) => ELet(a, b, EUnit)
  }

  def intLiteral : Parser[E] = """-?[1-9][0-9]*|0""".r ^^ {
    a => EInt(a.toInt)
  }

  def id : Parser[EId] = """[_a-zA-Z][_a-zA-Z0-9]*""".r ^^ {
    a => EId(a)
  }

  def parse(str:String) = {
    parseAll(expr, str) match {
      case Success(tree,_) => tree
      case e => throw new Exception(""+e)
    }
  }
}

sealed trait E

case class EInt(a:Int) extends E
case class EAdd(a:E,b:E) extends E
case class EMul(a:E,b:E) extends E
case class ELet(a:String, b:E, c:E) extends E
case class EId(a:String) extends E
object EUnit extends E

object Main {
  def main(argv:Array[String]) {

    test(Map(),"1",EInt(1))
    test(Map("a"->1),"a", EId("a"))
    test(Map(),"1+2", EAdd(EInt(1),EInt(2)))
    test(Map(),"val a = 1", ELet("a",EInt(1),EUnit))
    test(Map(),"{}", ELet(null, EUnit, EUnit))

    test(Map(),"{1}",ELet(null,EUnit,EInt(1)))
    test(Map("a"->1),"{a}", ELet(null,EUnit,EId("a")))
    test(Map(),"{1+2}", ELet(null,EUnit,EAdd(EInt(1),EInt(2))))
    test(Map(),"{val a = 1}", ELet(null,EUnit,ELet("a",EInt(1),EUnit)))
    test(Map(),"{{}}", ELet(null, EUnit,ELet(null, EUnit, EUnit)))

    test(Map(),"{1 1}",ELet(null, EUnit,ELet(null,EInt(1),EInt(1))))
    test(Map(),"{1 2 3}",ELet(null, EUnit, ELet(null,EInt(1),ELet(null, EInt(2), EInt(3)))))
    test(Map(),"{val a = 1 a}", ELet(null,EUnit,ELet("a",EInt(1),EId("a"))))
    test(Map(),"{val a = 1 val b = 2}",ELet(null,EUnit, ELet("a",EInt(1),ELet("b",EInt(2),EUnit))))
    test(Map(),"{{ val a = 1} val b = 2}",ELet(null,EUnit, ELet(null,ELet(null,EUnit, ELet("a",EInt(1),EUnit)),ELet("b",EInt(2),EUnit))))
    test("{val a = 5 { val a = 1} val b = 2 a}", 5)

  }
  def test(env:Map[String,Int],s:String,e:E) {
    val e2 = parser.parse(s)
    if (e2 != e) throw new Exception("error "+s+"  expected "+e+" but found "+e2)
    println(s+"="+eval(env,e2))
  }
  def test(s:String,e:Int) {
    val e2 = parser.parse(s)
    val e3 = eval(Map(), e2)
    if (e3 != e) throw new Exception("error "+s+"  expected "+e+" but found "+e3)
    println(s+"="+e3)
  }
  def eval(env:Map[String,Int], e:E):Int = e match {
    case EInt(a) => a
    case EAdd(a, b) => eval(env,a) + eval(env, b)
    case EMul(a, b) => eval(env,a) * eval(env, b)
    case ELet(a, b, c) => eval(env+(a->eval(env,b)),c)
    case EId(a) => env(a)
    case EUnit => 0
  }
}

C2E

C言語様な言語をML様な言語に変換するプログラムを作ってみました。

package C2E

trait C
case class CInt(a:Int) extends C
case class CId(a:String) extends C
case class CAdd(a:C,b:C) extends C
case class CVal(a:String, b:C) extends C
case class CBlock(a:List[C]) extends C

trait E
case class EInt(a:Int) extends E
case class EAdd(a:E,b:E) extends E
case class ELet(a:String, b:E, c:E) extends E
case class EId(a:String) extends E
object EUnit extends E

object Main {
  def main(argv:Array[String]) {
    test(CInt(1),EInt(1))
    test(CId("a"), EId("a"))
    test(CAdd(CInt(1),CInt(2)), EAdd(EInt(1),EInt(2)))
    test(CVal("a", CInt(1)), ELet("a",EInt(1),EUnit))
    test(CBlock(List()), EUnit)

    test(CBlock(List(CInt(1))),EInt(1))
    test(CBlock(List(CId("a"))), EId("a"))
    test(CBlock(List(CAdd(CInt(1),CInt(2)))), EAdd(EInt(1),EInt(2)))
    test(CBlock(List(CVal("a", CInt(1)))), ELet("a",EInt(1),EUnit))
    test(CBlock(List(CBlock(List()))), EUnit)

    test(CBlock(List(CInt(1),CInt(1))),ELet("_",EInt(1),EInt(1)))
    test(CBlock(List(CInt(1),CInt(2),CInt(3))),ELet("_",EInt(1),ELet("_", EInt(2), EInt(3))))
    test(CBlock(List(CVal("a",CInt(1)),CId("a"))),ELet("a",EInt(1),EId("a")))
    test(CBlock(List(CVal("a",CInt(1)),CVal("b",CInt(2)))),ELet("a",EInt(1),ELet("b",EInt(2),EUnit)))
    // {{ val a = 1}; val b = 2}
    test(CBlock(List(CBlock(List(CVal("a",CInt(1)))),CVal("b",CInt(2)))),ELet("_",ELet("a",EInt(1),EUnit),ELet("b",EInt(2),EUnit)))
  }

  def test(c:C,e:E) {
    val e2 = c2e(c)
    if (e2 != e) throw new Exception("error "+c+"  expected "+e+" but found "+e2)
  }
}

object c2e {
  def apply(c:C):E = {
    c match {
      case CInt(a) => EInt(a)
      case CAdd(a,b) => EAdd(c2e(a), c2e(b))
      case CId(a) => EId(a)
      case CVal(a,b) => ELet(a, c2e(b), EUnit)
      case CBlock(a) => ls(a)
    }
  }
  def ls(l:List[C]):E = {
    l match {
      case List() => EUnit
      case List(a) => c2e(a)
      case CVal(a,b)::c => ELet(a, c2e(b), ls(c))
      case a::b => ELet("_", c2e(a), ls(b))
    }
  }
}

Scalaのパーサコンビネータで右結合

四則演算が出来るパーサに変数を追加して=演算子を使いたい場合に、右結合する演算子を作る必要性が出てきます。右再帰はしたいとかですね。LL文法では左再帰すると無限ループしてしまうので困るのですが、右再帰は特に問題ないはずです。しかし、現時点でググってみて、なかなかよい例が出て来なかったのでメモしておきます。

以下のように書く事で右結合する代入演算子のあるパーサを書く事が出来ます。

package calc

import util.parsing.combinator._

object parse extends RegexParsers {

  def exp:Parser[Any] = repsep(assign,",") ^^ {
    case a => a.reduceRight[Any] {
      case (a, b) => (a, ",", b)
    }
  }

  def assign:Parser[Any] = id ~ "=" ~ assign ^^ {
    case a ~ op ~ b => (a, op, b)
  } | add

  def add = term ~ rep(("+" | "-") ~ term) ^^ {
    case a ~ b => b.foldLeft[Any](a){
      case (a, op ~ r)=> (a, op, r)
    }
  }

  def term = fact ~ rep(("*" | "/") ~ fact) ^^ {
    case a ~ b => b.foldLeft[Any](a) {
      case(a, op ~ r) => (a, op, r)
    }
  }

  def fact = int | id | "("~>exp<~")"

  def id = "[a-zA-Z_][a-zA-Z_0-9]*".r

  def int = """-?[1-9][0-9]*|0""".r ^^ {
    a => a.toInt
  }

  def apply(str:String) = parseAll(exp, str) match {
    case Success(tree,_) => tree
    case e => throw new Exception(""+e)
  }
}

object Main {
  def main(argv:Array[String]) {
    println(parse("a=b=1"))
  }
}

上の例ではfoldLeftを使ったりreduceRightを使ったり書き方がまちまちで、統一感がありません。

reduceLeft,reduceRightだけで書くとより分かりやすく書く事ができます。
以下のように書くと右結合と左結合の書き分けをreduceLeftとreduceRightを書き換えるだけで済みます:

package calc

import util.parsing.combinator._

object parse extends RegexParsers {

  def exp:Parser[Any] = repsep(assign,",") ^^ {
    case a => a.reduceRight[Any] {
      case (a, b) => (a, ",", b)
    }
  }

  def assign = add ~ rep("=" ~> add) ^^ {
    case a ~ b => (a::b).reduceRight[Any] {
      case (a, b) => (a, "=", b)
    }
  }

  def add = term ~ rep(("+" | "-") ~ term) ^^ {
    case a ~ b => (a::b).reduceLeft[Any] {
      case (a, op ~ r)=> (a, op, r)
    }
  }

  def term = fact ~ rep(("*" | "/") ~ fact) ^^ {
    case a ~ b => (a::b).reduceLeft[Any] {
      case(a, op ~ r) => (a, op, r)
    }
  }

  def fact = int | id | "("~>exp<~")"

  def id = "[a-zA-Z_][a-zA-Z_0-9]*".r

  def int = """-?[1-9][0-9]*|0""".r ^^ {
    a => a.toInt
  }

  def apply(str:String) = parseAll(exp, str) match {
    case Success(tree,_) => tree
    case e => throw new Exception(""+e)
  }
}

object Main {
  def main(argv:Array[String]) {
    println(parse("a=1,b=2,a=b*2=1*2*3+3*4+1+2+3"))
  }
}

リストの生成とリストの変換の分性能は悪くなると思いますが、実験していないので詳しいことは分かりません。
b*2=3といった式も受理してしまいますのでご注意をお願いします。

プログラマに話しかけるタイミングについて

これはまぁ、非常に難しい問題ですけど、いろいろな要素があります。タスクスイッチコストがかかる作業中に話しかけられるのが問題なのです。

作業の難易度について

1. プログラマの作業はひたすらコピペレベルな非常に簡単なレベルがあります。このレベルの作業をしている時は話しながら作業する事が可能なので話しかけてもらっても全然OKです。

2. ちょいムズだけど集中が必要な仕事

 それほど頭を悩まさなくてもいいのだけど、話しながら作業が出来ないレベルの仕事もあります。この場合は、まぁ、タスクスイッチのコストはそれほど高くないので話しかけられてもあまり問題ありません。

3.結構難しい集中が必要な仕事

脳内のワーク領域全般を使った複雑なプログラムを行っている場合はタスクスイッチコストは非常に高くなります。このような作業をしているときに、話しかけられると頭の中で展開された複雑なワーク用データを一度格納しないといけないので話しかけられると困ります。

4.さらに時間のかかる難しい仕事

ここまで難しくなって来ると、脳内のワーク領域では足りなくて、もう体に染み付いたような状況になって行きます。ワーク領域自体をあまり使わなくても慣れきっているので、タスクスイッチコストは低くなります。そのため話しかけられてもたいした問題ではありません。

5.イヤイヤやる難しい仕事

本人の気が向かず、イヤイヤやる難しい仕事は非常にタスクスイッチコストが高くなります。まず、モチベーションアップをしなくてはならず、モチベーションを上げた所に、さらにワーク領域に考えを展開してそれから作業を始めなくてはならない為です。ようやくやる気が出て始めた仕事を横から口をだされて中断されると、ああ、せっかくやる気が出たというのに、という怒りの感情がさらにモチベーションを下げてしまうため非常に辞めて欲しい状況になります。

また、集中して作業する事は長時間行う事が出来ないので、集中して仕事をしているなぁって言う時から数時間経てば集中力は下がって来て飽きた状態になります。いろいろ考えた結果不要になった考えも残っていてそれは記憶から消した方が良い訳ですけど、残っているわけです。ストレスといってもいいでしょう。このような状態の場合は一度仕事を休んで気分転換をしたほうが作業効率があがったりします。他の作業があるならそちらの作業に切り替える絶好のタイミングでもあります。

仕事をしているときは特に話しかけて欲しくないタイミングと話しかけて欲しいタイミングというのがあって、そのタイミングが悪いと困る訳です。

話しかける内容について

話しかける内容によっても良い悪いがあります。

・差し入れでこれ食べてくださいとか言う話は、ありがたい事が多いです。五臓六腑に染み渡るありがたい。もっと頑張ろうって気持になったりします。
・どうでもいい世間話も、悪くないですが、忙しいときにどうでも良い話を永遠とされるのはさすがに困ります。
・嫌な込み入った話を嫌な込み入った作業をしているときにされるのが最悪のケースです。脳内は疲れているのにも関わらず難しい事を考えているというのにも関わらず、そこに突然難しい別の事を持って来られるのは溜まらなく困る事です。我慢ならないくらい大変な作業をさせられているところに、我慢ならない話をねじ込んで来られたら、切れる事もあり得ます。

このように、一見集中中のプログラマでもその内部状態は異なります。また、話しかける内容によっても結果は異なるのです。

だからまぁ、今話しかけてよいですか?
という話をして、いいよ、ちょっとまって、駄目という話が重要です。

いつも、いいよって行ってくれる人に好かれていて駄目って断る人には嫌われているって訳ではないのです。

でも、駄目ってタイミングを増やせばやはり嫌われてしまいます。話しかけるタイミングを変えてみたりするのがよいでしょう。ご飯のタイミングとか、お茶したいタイミングとかトイレに行って帰って来たタイミングとか出社したタイミングとか帰るタイミング等はかなり話しかけるのに良いタイミングですけど、移動中も考えたい時もあるし、考えながら移動して来て直ぐ作業したい事などもあるのでその時々によるんですよね。

ちょっと待ってとか、駄目だっていうタイミングが多いのがプログラマっていう仕事なのではないかと思います。