vueで遊ぶ 第1回 〜プロジェクト作成

SPAをやりたくて今流行のvueで始めてみました。

vue cliのインストール

yarn global add @vue/cli

projectの作成

vue create ngiy-frontend
  1. manualを選択
  2. Typescriptを選択
  3. In package.jsonを選択
  4. Use Yarnを選択

projectの起動

cd ngiy-frontend
yarn serve

ブラウザが起動しました!
ここからコーディングスタート♪

モナドトランスフォーマー (1)

ListとList[Option]とOptionの共存

val intList: List[Int] = List(1, 2, 3, 5)
val strOptList: List[Option[String]] = List(Some("a"), Some("c"), None, Some("d"))
val option: Option[Int] = Option(1)

val t: OptionT[List, (Int, String, Int)] = for {
  i <- OptionT.liftF(intList)
  s <- OptionT(strOptList)
  o <- OptionT.fromOption[List](option)
} yield (i, s, o)

// List(Some((1,a,1)), Some((1,c,1)), None, Some((1,d,1)), Some((2,a,1)), Some((2,c,1)), None, Some((2,d,1)), Some((3,a,1)), Some((3,c,1)), None, Some((3,d,1)), Some((5,a,1)), Some((5,c,1)), None, Some((5,d,1)))
println(t.value)

プログラミングhaskell 9章 version scala 〜後半(ライフゲーム)〜

type Board = List[Pos]

val width: Int = 5
val height: Int = 5

def showcells(b: Board): IO[Unit] = seqn(b.map(p => writeat(p)("○")))
def isAlive(b: Board)(p: Pos): Boolean = b.contains(p)
def isEmpty(b: Board)(p: Pos): Boolean = !isAlive(b)(p)
def neighbs(p: Pos) = List(
  (p._1 - 1, p._2 - 1), (p._1, p._2 - 1),
  (p._1 + 1, p._2 - 1), (p._1 - 1, p._2),
  (p._1 + 1, p._2), (p._1 - 1, p._2 + 1),
  (p._1, p._2 + 1), (p._1 + 1, p._2 + 1)
).map(wrap)
def wrap(p: Pos): Pos =
  (((p._1 - 1) % width) + 1, ((p._2 - 1) % height) + 1)
def liveneigbs(b: Board)(p: Pos): Int =
  neighbs(p).count(isAlive(b))
def survivers(b: Board): List[Pos] =
  b.filter(p => List(2, 3).contains(liveneigbs(b)(p)))
def births(b: Board): List[Pos] =
  b.flatMap(p => neighbs(p))
    .distinct
    .filter(p => isEmpty(b)(p))
    .filter(p => liveneigbs(b)(p) == 3)
def nextgen(b: Board): List[Pos] =
  survivers(b) ++ births(b)

def life(b: Board): IO[Unit] =
  for {
    _ <- cls
    _ <- showcells(b)
    _ <- IO(Thread.sleep(500L))
    _ <- life(nextgen(b))
  } yield ()

life(List((4, 2), (2, 3), (4, 3), (3, 4), (4, 4))).unsafeRunSync()

Stateモナドの使い道 [フィボナッチ]

case class S(current: Int, next: Int) {
  def process() = S(next, current + next)
}

val fib: Stream[State[S, Int]] = Stream.continually(State(s => (s.process(), s.current)))
val state: State[S, Stream[Int]] = fib.take(15).sequence
println(state.run(S(0, 1)).value._2.toList) // List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377)

プログラミングhaskell 9章 version scala 〜後半〜

val box: List[String] =
  List(
    "+---------------+",
    "|               |",
    "+---+---+---+---+",
    "| q | c | d | = |",
    "+---+---+---+---+",
    "| 1 | 2 | 3 | + |",
    "+---+---+---+---+",
    "| 4 | 5 | 6 | - |",
    "+---+---+---+---+",
    "| 7 | 8 | 9 | * |",
    "+---+---+---+---+"
  )

val buttons: String = {
  val standard = "qcd=123+456-789*0()/"
  val extra = "QCD \033\010\014\n"
  standard + extra
}

val showbox: IO[Unit] = seqn((1 to 13).zip(box).map(t => writeat((1, t._1))(t._2)).toList)

def display(s: String): IO[Unit] =
  for {
    _ <- writeat((3, 2))("             ")
    _ <- writeat((3, 2))(s.toCharArray.takeRight(13).mkString)
  } yield ()

def calc(s: String): IO[Unit] =
  for {
    _ <- display(s)
    c <- getChar
    _ <- if (buttons.contains(c)) process(c)(s)
    else for {
      _ <- beep
      _ <- calc(s)
    } yield ()
  } yield ()

def process(c: Char)(s: String): IO[Unit] = s match {
  case _ if "qQ\033".contains(c) => quit
  case _ if "dD\010\014".contains(c) => delete(s)
  case _ if "=\n".contains(c) => eval(s)
  case _ if "cC".contains(c) => clear
  case _ => process(c)(s)
}

def quit = goto((1, 14))
def delete(s: String) = s match {
  case "" => calc("")
  case xs => calc(xs.head.toString)
}
import ParserMain._
def eval(s: String): IO[Unit] =  expr.run(s) match {
  case Some((_, n)) => calc(n.toString)
  case None =>
    for {
      _ <- beep
      _ <- calc(s)
    } yield ()
}
def clear: IO[Unit] = calc("")
def press(c: Char)(s: String): IO[Unit] = calc(s + c.toString)

val run: IO[Unit] =
  for {
    _ <- cls
    _ <- showbox
    _ <- clear
  } yield ()
run.unsafeRunSync()

プログラミングhaskell 9章 version scala 〜前半〜

def getChar: IO[Char] = IO(System.in.read().toChar)

def putChar(c: Char): IO[Unit] = IO(print(c))

def echo: IO[Unit] =
  for {
    c <- getChar
    _ <- putChar('\n')
    _ <- putChar(c)
    _ <- putChar('\n')
  } yield ()

def getLine: IO[List[Char]] =
  for {
    x <- getChar
    r <- if (x == '\n') IO(Nil)
    else
      for {
        xs <- getLine
      } yield x :: xs
  } yield r

def putStr(s: String): IO[Unit] = s.toCharArray.toList match {
  case Nil => IO(())
  case x :: xs =>
    for {
      _ <- putChar(x)
      _ <- putStr(xs.mkString)
    } yield ()
}

def putStrLn(s: String): IO[Unit] =
  for {
    _ <- putStr(s)
    _ <- putChar('\n')
  } yield ()

def strlen: IO[Unit] =
  for {
    _ <- putStr("Enter a string: ")
    x <- getLine
    _ <- putStr("The string has ")
    _ <- putStr(x.length.toString)
    _ <- putStrLn(" characters")
  } yield ()

def cls = putStr("\033[2J")

type Pos = (Int, Int)

def goto(p: Pos) =
  putStr("\033[" + p._2.toString + ";" + p._1.toString + "H")

def writeat(p: Pos)(s: String): IO[Unit] =
  for {
    _ <- goto(p)
    _ <- putStr(s)
  } yield ()

def seqn[T](seq: List[IO[T]]): IO[Unit] = seq match {
  case Nil => IO(())
  case a :: as =>
    for {
      _ <- a
      _ <- seqn(as)
    } yield ()
}

seqn((1 to 9).map(_.toString charAt 0).map(putChar).toList).unsafeRunSync()

Writerモナドの使い道 [自作モノイド]

case class Product(money: Int)

case class Coins(gohyakuen: Int, hyakuen: Int, gojuen: Int, juen: Int) {
  def +(other: Coins) = Coins(gohyakuen + other.gohyakuen, hyakuen + other.hyakuen, gojuen + other.gojuen, juen + other.juen)
  def sum(): Int = gohyakuen * 500 + hyakuen * 100 + gojuen * 50 + juen * 10
}

implicit val monoidCoins = new Monoid[Coins] {
  override def empty: Coins = Coins(0, 0, 0, 0)
  override def combine(x: Coins, y: Coins): Coins = x + y
}

def buyProduct(coins: Coins): Writer[Coins, Product] =
  for {
    _ <- Writer.tell(coins)
    r <- Writer.value[Coins, Product](Product(coins.sum()))
  } yield r

def buyProducts(coinsList: List[Coins]): Writer[Coins, List[Product]] =
  coinsList.map(buyProduct).sequence

// 500円玉3枚、100円玉3枚、50円玉5枚、10円玉6枚使用
// 230円と710円と1170円の品をかう
// (Coins(3,3,5,6),List(Product(230), Product(710), Product(1170)))
println(buyProducts(List(Coins(0, 1, 2, 3), Coins(1, 2, 0, 1), Coins(2, 0, 3, 2))).run)