Команда Microsoft представила Bosque — нову мову програмування з відкритим вихідним кодом. Вона базується на синтаксисі TypeScript, семантиці машинного навчання і Node.js.
Автор проекту каже, що хотів створити функціональну мову, котра з часом допоможе вийти за межі парадигми структурованого програмування, популярного у 1970-х. Метою Bosque є створення простого і наочного коду, який легко прочитають і люди, і машини.
Завдяки ключовим конструктивним особливостям мови можна уникнути випадкових труднощів (Accidental Complexity) в процесі кодування. Це має підвищити продуктивність розробників, покращити якість програмного забезпечення та інструментів.
В моделі структурованого програмування керування потоком відбувається через цикли, умовні вирази й підпрограми. Натомість Bosque позбавляється від таких джерел складнощів, як цикли, змінні об'єкти та рівність посилань. Маррон описує цю нову нову парадигму розробки як «регуляризоване програмування».
Робота над Bosque все ще триває, тож Microsoft зацікавлені у відгуках і пропозиціях програмістів. Ознайомитись і долучитися можна через репозиторій Bosque на Github.
Приклад хрестиків-нуликів на Bosque:
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
//
//This is a bosque test/benchmark for a tic-tac-toe program.
//
namespace NSMain;
entity Board {
const playerX: String[PlayerMark] = 'x'#PlayerMark;
const playerO: String[PlayerMark] = 'o'#PlayerMark;
const allCellPositions: List[[Int, Int]] = List[[Int, Int]]@{
@[ 0, 0 ], @[ 1, 0 ], @[ 2, 0 ],
@[ 0, 1 ], @[ 1, 1 ], @[ 2, 1 ],
@[ 0, 2 ], @[ 1, 2 ], @[ 2, 2 ]
};
const winPositionOptions: List[List[[Int, Int]]] = List[List[[Int, Int]]]@{
List[[Int, Int]]@{ @[ 0, 0 ], @[ 0, 1 ], @[ 0, 2 ] },
List[[Int, Int]]@{ @[ 0, 1 ], @[ 1, 1 ], @[ 2, 1 ] },
List[[Int, Int]]@{ @[ 0, 2 ], @[ 1, 2 ], @[ 2, 2 ] },
List[[Int, Int]]@{ @[ 0, 0 ], @[ 1, 0 ], @[ 2, 0 ] },
List[[Int, Int]]@{ @[ 1, 0 ], @[ 1, 1 ], @[ 1, 2 ] },
List[[Int, Int]]@{ @[ 2, 0 ], @[ 2, 1 ], @[ 2, 2 ] },
List[[Int, Int]]@{ @[ 0, 0 ], @[ 1, 1 ], @[ 2, 2 ] },
List[[Int, Int]]@{ @[ 0, 2 ], @[ 1, 1 ], @[ 2, 0 ] }
};
//Board is a list of marks, indexed by x,y coords from upper left 0 based
field cells: List[String[PlayerMark]?];
factory static createInitialBoard(): { cells: List[String[PlayerMark]?] } {
return @{ cells=List[String[PlayerMark]?]::createOfSize(9, none) };
}
method getOpenCells(): List[[Int, Int]] {
return Board::allCellPositions->filter(fn(pos: [Int, Int]): Bool => {
return !this->isCellOccupied(pos[0], pos[1]);
});
}
method getCellContents(x: Int, y: Int): String[PlayerMark]?
requires 0 <= x && x < 3 && 0 <= y && y < 3;
{
return this.cells->at(x + y * 3);
}
method isCellOccupied(x: Int, y: Int): Bool {
return this->getCellContents(x, y) != none;
}
method isCellOccupiedWith(x: Int, y: Int, mark: String[PlayerMark]): Bool
requires mark == Board::playerX || mark == Board::playerO;
{
return this->getCellContents(x, y) == mark;
}
method markCellWith(x: Int, y: Int, mark: String[PlayerMark]): Board
requires mark == Board::playerX || mark == Board::playerO;
requires 0 <= x && x < 3 && 0 <= y && y < 3;
requires !this->isCellOccupied(x, y);
{
return this<~(cells=this.cells->set(x + y * 3, mark));
}
hidden method checkSingleWinOption(opt: List[[Int, Int]], mark: String[PlayerMark]): Bool {
return opt->all(fn(entry: [Int, Int]): Bool => this->isCellOccupiedWith(entry[0], entry[1], mark));
}
hidden method checkSingleWinner(mark: String[PlayerMark]): Bool {
return Board::winPositionOptions->any(fn(opt: List[[Int, Int]]): Bool => this->checkSingleWinOption(opt, mark));
}
method checkForWinner(): String[PlayerMark]? {
if(this->checkSingleWinner(Board::playerX)) {
return Board::playerX;
}
elif(this->checkSingleWinner(Board::playerO)) {
return Board::playerO;
}
else {
return none;
}
}
}
entity Game {
field winner: String[PlayerMark]? = none;
field board: Board = Board@createInitialBoard();
method hasWinner(): Bool {
return this.winner != none;
}
method getWinner(): String[PlayerMark]
requires this->hasWinner();
{
return this.winner->as[String[PlayerMark]]();
}
method makeAutoMove(mark: String[PlayerMark], rnd: Int): Game
requires !this->hasWinner();
{
var! nboard: Board;
if(!this.board->isCellOccupied(1, 1)) {
nboard = this.board->markCellWith(1, 1, mark);
}
else {
var opts = this.board->getOpenCells();
var tup = opts->uniform(rnd);
nboard = this.board->markCellWith(...tup, mark);
}
return this<~( board=nboard, winner=nboard->checkForWinner() );
}
method makeExplicitMove(x: Int, y: Int, mark: String[PlayerMark]): Game
requires !this.board->isCellOccupied(x, y);
{
var nboard = this.board->markCellWith(x, y, mark);
return this<~( board=nboard, winner=nboard->checkForWinner() );
}
}
entity PlayerMark provides Parsable {
field mark: String;
override static tryParse(str: String): PlayerMark | None {
return (str == "x" || str == "o") ? PlayerMark@{ mark=str } : none;
}
}
entrypoint function main(): Game {
var! game = Game@{};
game = game->makeAutoMove(Board::playerX, 0);
game = game->makeAutoMove(Board::playerO, 1);
game = game->makeAutoMove(Board::playerX, 2);
game = game->makeExplicitMove(2, 0, Board::playerO);
game = game->makeExplicitMove(2, 1, Board::playerX);
return game;
}
Ще немає коментарів