├── .ackrc ├── .dockerignore ├── .gitignore ├── .nvmrc ├── .profile ├── .rspec ├── .ruby-version ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── Setup.hs ├── bin ├── cat.js ├── cat_with_lineno.js ├── cat_without_world.js ├── dentaku.normal.js ├── echo.js ├── input-capitalise-driver.js ├── input-capitalise.js ├── input-readline.js ├── io.js ├── io_with_world.js ├── io_without_world.js ├── iomonad.js ├── life.js ├── list.js ├── pair.js ├── read.js ├── string.js ├── tarai_client.js ├── tarai_server.js └── tcp_server.js ├── build.sbt ├── cabal.config ├── docs ├── .gitignore ├── _config.yml ├── _includes │ ├── footer.html │ ├── head.html │ └── header.html ├── _layouts │ ├── default.html │ ├── page.html │ └── post.html ├── _posts │ └── 2016-10-16-welcome-to-jekyll.markdown ├── _sass │ ├── _base.scss │ ├── _layout.scss │ └── _syntax-highlighting.scss ├── about.md ├── chap01.spec.html ├── chap02.spec.html ├── chap03.spec.html ├── chap04.spec.html ├── chap05.spec.html ├── chap06.spec.html ├── chap07.spec.html ├── chap08.spec.html ├── css │ ├── docco.css │ └── main.scss ├── data.html ├── data.spec.html ├── dentaku.normal.html ├── dentaku.normal.spec.html ├── docco.css ├── env.html ├── evaluator.html ├── evaluator.spec.html ├── feed.xml ├── fileio.html ├── images │ ├── add-reduction-00.png │ ├── add-reduction-01.png │ ├── add-reduction-02.png │ ├── add-reduction-03.png │ ├── add-reduction-04.png │ ├── add-reduction-05.png │ ├── add-reduction-06.png │ ├── add-reduction-07.png │ ├── add-reduction-08.png │ ├── add-reduction-09.png │ ├── add-reduction-10.png │ ├── add-reduction-11.png │ ├── add-reduction-12.png │ ├── add-reduction-13.png │ ├── add-reduction-14.png │ ├── add-reduction-15.png │ ├── add-reduction-16.png │ ├── add-reduction-17.png │ ├── add-reduction-18.png │ ├── add-reduction-19.png │ ├── add-reduction-20.png │ ├── add-reduction-21.png │ ├── add-reduction-22.png │ ├── add-reduction-23.png │ ├── add-reduction-24.png │ ├── add-reduction-25.png │ ├── add-reduction-26.png │ ├── add-reduction-27.png │ ├── add-reduction-28.png │ ├── add-reduction-29.png │ ├── add-reduction-30.png │ ├── add-reduction-31.png │ ├── add-reduction-32.png │ ├── add-reduction-33.png │ ├── add-reduction-34.png │ ├── add-reduction-35.png │ ├── add-reduction-36.png │ ├── add-reduction-37.png │ ├── add-reduction-38.png │ ├── add-reduction-39.png │ ├── add-reduction.gif │ ├── add_reduction.dia │ ├── add_reduction.gif │ ├── add_reduction.xcf │ ├── environment.gif │ ├── event-loop.png │ ├── event-loop.shape │ ├── match-reduction-00.png │ ├── match-reduction-01.png │ ├── match-reduction-02.png │ ├── match-reduction-03.png │ ├── match-reduction-04.png │ ├── match-reduction-05.png │ ├── match-reduction-06.png │ ├── match-reduction-07.png │ ├── match-reduction-08.png │ ├── match-reduction-09.png │ ├── match-reduction-10.png │ ├── match-reduction-11.png │ ├── match-reduction-12.png │ ├── match-reduction-13.png │ ├── match-reduction-14.png │ ├── match-reduction-15.png │ ├── match-reduction-16.png │ ├── match-reduction-17.png │ ├── match-reduction-18.png │ ├── match-reduction-19.png │ ├── match-reduction-20.png │ ├── match-reduction-21.png │ ├── match-reduction-22.png │ ├── match-reduction-23.png │ ├── match-reduction-24.png │ ├── match-reduction-25.png │ ├── match-reduction-26.png │ ├── match-reduction-27.png │ ├── match-reduction-28.png │ ├── match-reduction-29.png │ ├── match-reduction-30.png │ ├── match-reduction-31.png │ ├── match-reduction-32.png │ ├── match-reduction-33.png │ ├── match-reduction-34.png │ ├── match-reduction-35.png │ ├── match-reduction-36.png │ ├── match-reduction-37.png │ ├── match-reduction.dia │ ├── match-reduction.gif │ ├── match-reduction.png │ ├── match-reduction.xcf │ ├── mechanism-of-assignment.gif │ ├── mechanism-of-assignment.xcf │ ├── multiply_reduction-01.png │ ├── multiply_reduction-02.png │ ├── multiply_reduction-03.png │ ├── multiply_reduction-04.png │ ├── multiply_reduction-05.png │ ├── multiply_reduction-06.png │ ├── multiply_reduction-07.png │ ├── multiply_reduction-08.png │ ├── multiply_reduction-09.png │ ├── multiply_reduction-10.png │ ├── multiply_reduction-11.png │ ├── multiply_reduction-12.png │ ├── multiply_reduction-13.png │ ├── multiply_reduction-14.png │ ├── multiply_reduction-15.png │ ├── multiply_reduction-16.png │ ├── multiply_reduction-17.png │ ├── multiply_reduction-18.png │ ├── multiply_reduction-19.png │ ├── multiply_reduction-20.png │ ├── multiply_reduction.dia │ ├── multiply_reduction.gif │ ├── multiply_reduction.xcf │ ├── tarai-system-00.png │ ├── tarai-system-01.png │ ├── tarai-system-02.png │ ├── tarai-system-03.png │ ├── tarai-system-04.png │ ├── tarai-system-05.png │ ├── tarai-system-06.png │ ├── tarai-system-07.png │ ├── tarai-system-08.png │ ├── tarai-system-09.png │ ├── tarai-system-10.png │ ├── tarai-system-11.png │ ├── tarai-system-12.png │ ├── tarai-system-13.png │ ├── tarai-system-14.png │ ├── tarai-system-15.png │ ├── tarai-system-16.png │ ├── tarai-system-17.png │ ├── tarai-system-18.png │ ├── tarai-system-19.png │ ├── tarai-system-20.png │ ├── tarai-system-21.png │ ├── tarai-system-22.png │ ├── tarai-system-23.png │ ├── tarai-system-24.png │ ├── tarai-system-25.png │ ├── tarai-system-26.png │ ├── tarai-system-27.png │ ├── tarai-system-28.png │ ├── tarai-system-29.png │ ├── tarai-system-30.png │ ├── tarai-system-31.png │ ├── tarai-system-32.png │ ├── tarai-system.dia │ ├── tarai-system.gif │ └── turing_succ.gif ├── index.html ├── interpreter.spec.html ├── list.html ├── list.spec.html ├── monad.html ├── monad.spec.html ├── monad_transformer.html ├── monad_transformer.spec.html ├── monadic-evaluator.spec.html ├── pair.html ├── pair.spec.html ├── parser.html ├── parser.spec.html ├── pprinter.html ├── pprinter.spec.html ├── public │ ├── fonts │ │ ├── aller-bold.eot │ │ ├── aller-bold.ttf │ │ ├── aller-bold.woff │ │ ├── aller-light.eot │ │ ├── aller-light.ttf │ │ ├── aller-light.woff │ │ ├── novecento-bold.eot │ │ ├── novecento-bold.ttf │ │ └── novecento-bold.woff │ └── stylesheets │ │ └── normalize.css ├── string.html ├── string.spec.html ├── stylesheets │ ├── github-light.css │ ├── normalize.css │ └── stylesheet.css └── template │ └── docco.jst ├── failed ├── chap03 │ ├── add.spec.js │ ├── multiply.spec.js │ └── multiply_again.spec.js ├── chap04 │ ├── expect_type_error.spec.js │ └── type_error.spec.js ├── chap05 │ ├── functionalIf.spec.js │ └── statementIf.spec.js └── chap07 │ ├── compose.spec.js │ └── not.spec.js ├── functionaljs.cabal ├── gulpfile.js ├── lib ├── data.js ├── dentaku.normal.js ├── env.js ├── evaluator.js ├── fileio.js ├── list.js ├── monad.js ├── monad_transformer.js ├── pair.js ├── parser.js ├── pprinter.js ├── string.js └── turing.js ├── package-lock.json ├── package.json ├── project ├── FunctionalJs.scala └── build.properties ├── src ├── main │ └── haskell │ │ └── .gitkeep └── test │ ├── haskell │ ├── Chap06Spec.hs │ ├── HSpecTests.hs │ ├── Haq.hs │ ├── QCheckSpec.hs │ └── Spec.hs │ └── scala │ ├── chap02.check.scala │ ├── chap02.spec.scala │ └── chap05.spec.scala ├── stack.yaml └── test ├── chap01.spec.js ├── chap02.spec.js ├── chap02_spec.rb ├── chap03.spec.js ├── chap04.spec.js ├── chap05.spec.coffee ├── chap05.spec.js ├── chap05.spec.scala ├── chap06.spec.js ├── chap07.spec.js ├── chap08.spec.js ├── data.spec.js ├── dentaku.normal.spec.js ├── evaluator.spec.js ├── interpreter.spec.js ├── list.spec.js ├── monad.spec.js ├── monad_transformer.spec.js ├── not_in_use ├── chap01.spec.js ├── chap02.spec.js ├── chap03.spec.js ├── chap04.spec.js ├── chap05.spec.js ├── chap06.spec.js ├── chap07.spec.js └── chap08.spec.js ├── pair.spec.js ├── parser.spec.js ├── pprinter.spec.js ├── resources ├── dream.txt ├── file.txt ├── io.txt ├── mikan.txt └── test.txt ├── runner.html └── string.spec.js /.ackrc: -------------------------------------------------------------------------------- 1 | --type-set=coffee=.coffee,.js 2 | --type-set=src=.coffee,.js 3 | --type-set=txt:ext:se 4 | --nogroup 5 | 6 | --ignore-dir=node_modules 7 | --ignore-dir=tmp 8 | --ignore-dir=.grunt 9 | --ignore-dir=public 10 | --ignore-file=ext:log 11 | 12 | 13 | # Always color, even if piping to a another program 14 | --color 15 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .emacs.desktop* 2 | 3 | # Logs 4 | logs 5 | *.log 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 29 | node_modules 30 | 31 | _site/ 32 | .publish/ 33 | 34 | # scala 35 | target/ 36 | 37 | # haskell 38 | .stack-work 39 | dist/ 40 | 41 | # docco 42 | node_modules/ 43 | project/ 44 | target/ 45 | .publish/ 46 | 47 | # vim 48 | *.swp 49 | Session.vim 50 | 51 | draft/ 52 | 53 | 54 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.20.0 2 | -------------------------------------------------------------------------------- /.profile: -------------------------------------------------------------------------------- 1 | # ~/.profile: executed by Bourne-compatible login shells. 2 | 3 | if [ "$BASH" ]; then 4 | if [ -f ~/.bashrc ]; then 5 | . ~/.bashrc 6 | fi 7 | fi 8 | 9 | mesg n 10 | # The Following loads nvm, and install Node.js which version is assigned to $NODE_ENV 11 | source ~/.nvm/nvm.sh 12 | echo "Installing node@${NODE_VERSION}, this may take several minutes..." 13 | # nvm install ${NODE_VERSION} 14 | nvm use v${NODE_VERSION} 15 | nvm alias default v${NODE_VERSION} 16 | alias gulp='node --harmony `which gulp`' 17 | 18 | # sbt 19 | export PATH=~/scala-$SCALA_VERSION/bin:$PATH 20 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format d -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.3.0 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM phusion/baseimage:0.9.11 2 | # c.f. https://github.com/phusion/baseimage-docker 3 | MAINTAINER Akimichi Tatsukawa 4 | ENV REFRESHED_AT 2016-10-24(Mon) 5 | ## Use baseimage-docker's init system. 6 | CMD ["/sbin/my_init"] 7 | 8 | RUN /etc/my_init.d/00_regen_ssh_host_keys.sh 9 | 10 | RUN sed -i~ -e 's;http://archive.ubuntu.com/ubuntu;http://ftp.jaist.ac.jp/pub/Linux/ubuntu;' /etc/apt/sources.list 11 | RUN apt-get -yqq update 12 | 13 | ## Japanese Environment 14 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y language-pack-ja 15 | ENV LANG ja_JP.UTF-8 16 | RUN update-locale LANG=ja_JP.UTF-8 17 | RUN (mv /etc/localtime /etc/localtime.org && ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime) 18 | 19 | ## Development Environment 20 | ENV EDITOR vim 21 | RUN update-alternatives --set editor /usr/bin/vim.basic 22 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y git wget curl unzip build-essential python-dev rake 23 | 24 | COPY .profile /root 25 | RUN mkdir -p /workspace/nodejs && \ 26 | mkdir -p /workspace/scala && \ 27 | mkdir -p /workspace/haskell 28 | 29 | 30 | ######################### 31 | ## sbt インストール 32 | ######################### 33 | ENV SCALA_VERSION 2.11.7 34 | ENV SBT_VERSION 0.13.8 35 | 36 | COPY build.sbt /workspace/scala 37 | COPY project /workspace/scala/project 38 | COPY src /workspace/scala/src 39 | 40 | # INSTALL JAVA 7 add webupd8 repository 41 | RUN \ 42 | echo "===> add webupd8 repository..." && \ 43 | echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \ 44 | echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \ 45 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EEA14886 && \ 46 | apt-get update && \ 47 | \ 48 | \ 49 | echo "===> install Java" && \ 50 | echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \ 51 | echo debconf shared/accepted-oracle-license-v1-1 seen true | debconf-set-selections && \ 52 | DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes oracle-java7-installer oracle-java7-set-default && \ 53 | \ 54 | \ 55 | echo "===> clean up..." && \ 56 | rm -rf /var/cache/oracle-jdk7-installer && \ 57 | apt-get clean && \ 58 | rm -rf /var/lib/apt/lists/* 59 | 60 | # scala 61 | RUN \ 62 | cd /root && \ 63 | curl -o scala-$SCALA_VERSION.tgz http://downloads.typesafe.com/scala/$SCALA_VERSION/scala-$SCALA_VERSION.tgz && \ 64 | tar -xf scala-$SCALA_VERSION.tgz && \ 65 | rm scala-$SCALA_VERSION.tgz 66 | # sbt 67 | WORKDIR /workspace/scala 68 | RUN \ 69 | curl -L -o sbt-$SBT_VERSION.deb https://dl.bintray.com/sbt/debian/sbt-$SBT_VERSION.deb && \ 70 | dpkg -i sbt-$SBT_VERSION.deb && \ 71 | rm sbt-$SBT_VERSION.deb && \ 72 | apt-get update 73 | RUN sbt update 74 | 75 | ############################### 76 | # Install nvm with node and npm 77 | ############################### 78 | ENV NODE_VERSION 0.12.0 79 | 80 | # COPY test /workspace/nodejs/test 81 | # COPY lib /workspace/nodejs/lib 82 | # COPY .nvmrc gulpfile.js package.json /workspace/nodejs/ 83 | RUN touch $HOME/.ssh/known_hosts 84 | RUN ssh-keyscan github.com >> $HOME/.ssh/known_hosts 85 | RUN git clone https://github.com/akimichi/functionaljs.git /workspace/nodejs 86 | 87 | # install node.js 88 | WORKDIR /workspace/nodejs 89 | RUN add-apt-repository ppa:chris-lea/node.js && \ 90 | apt-get update -qq 91 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs 92 | # Replace shell with bash so we can source files 93 | RUN rm /bin/sh && ln -s /bin/bash /bin/sh 94 | 95 | WORKDIR /root 96 | # setup the nvm environment 97 | # Install nvm with node and npm 98 | RUN git clone https://github.com/creationix/nvm.git $HOME/.nvm 99 | RUN bash \ 100 | && source $HOME/.nvm/nvm.sh \ 101 | && nvm install v$NODE_VERSION \ 102 | && nvm alias default v$NODE_VERSION \ 103 | && nvm use default 104 | 105 | ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules 106 | ENV PATH $NVM_DIR/v$NODE_VERSION/bin:$PATH 107 | 108 | RUN npm install -g node-gyp && \ 109 | npm install -g mocha && \ 110 | npm install -g gulp && \ 111 | npm install -g coffee-script 112 | WORKDIR /workspace 113 | RUN cd /workspace/nodejs && npm install 114 | 115 | ################# 116 | # install haskell 117 | ################# 118 | RUN export DEBIAN_FRONTEND=noninteractive && \ 119 | apt-get update && \ 120 | apt-get dist-upgrade -qqy && \ 121 | apt-get install -qqy --no-install-recommends software-properties-common && \ 122 | add-apt-repository -y ppa:hvr/ghc && \ 123 | apt-get update && \ 124 | apt-get install -qqy cabal-install-1.22 ghc-7.10.2 happy-1.19.5 alex-3.1.4 && \ 125 | apt-get autoremove -qqy && \ 126 | apt-get clean && apt-get autoclean && \ 127 | rm -rf /usr/share/man/?? && rm -rf /usr/share/man/??_* 128 | 129 | ENV PATH="${HOME}/.cabal/bin:/opt/cabal/1.22/bin:/opt/ghc/7.10.2/bin:${PATH}" 130 | 131 | WORKDIR /workspace/haskell 132 | RUN wget https://www.stackage.org/lts/cabal.config 133 | 134 | # install stackage 135 | RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 575159689BEFB442 136 | RUN echo 'deb http://download.fpcomplete.com/ubuntu trusty main' | tee /etc/apt/sources.list.d/fpco.list 137 | RUN apt-get update && apt-get install stack -y 138 | COPY src /workspace/haskell/src/ 139 | COPY functionaljs.cabal Setup.hs LICENSE /workspace/haskell/ 140 | RUN stack init 141 | RUN stack setup 142 | 143 | # cabal 144 | RUN cabal update 145 | RUN cabal install 'cabal-install >= 0.10' 146 | RUN cabal install 147 | 148 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 149 | 150 | VOLUME /workspace 151 | 152 | CMD ["bash"] 153 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # gem 'github-pages' 3 | gem 'minima' 4 | gem 'github-pages', group: :jekyll_plugins 5 | gem 'rspec' 6 | gem 'json', github: 'flori/json', branch: 'v1.8' 7 | 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/flori/json.git 3 | revision: 7f4cfd853f2c919d854fb95548a19980feff17e8 4 | branch: v1.8 5 | specs: 6 | json (1.8.6) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | RedCloth (4.2.9) 12 | activesupport (5.2.0) 13 | concurrent-ruby (~> 1.0, >= 1.0.2) 14 | i18n (>= 0.7, < 2) 15 | minitest (~> 5.1) 16 | tzinfo (~> 1.1) 17 | addressable (2.3.8) 18 | blankslate (2.1.2.4) 19 | classifier-reborn (2.0.3) 20 | fast-stemmer (~> 1.0) 21 | coffee-script (2.4.1) 22 | coffee-script-source 23 | execjs 24 | coffee-script-source (1.9.1.1) 25 | colorator (0.1) 26 | concurrent-ruby (1.0.5) 27 | diff-lcs (1.2.5) 28 | ethon (0.8.0) 29 | ffi (>= 1.3.0) 30 | execjs (2.6.0) 31 | fast-stemmer (1.0.2) 32 | ffi (1.9.10) 33 | gemoji (2.1.0) 34 | github-pages (39) 35 | RedCloth (= 4.2.9) 36 | github-pages-health-check (~> 0.2) 37 | jekyll (= 2.4.0) 38 | jekyll-coffeescript (= 1.0.1) 39 | jekyll-feed (= 0.3.1) 40 | jekyll-mentions (= 0.2.1) 41 | jekyll-redirect-from (= 0.8.0) 42 | jekyll-sass-converter (= 1.3.0) 43 | jekyll-sitemap (= 0.8.1) 44 | jemoji (= 0.5.0) 45 | kramdown (= 1.5.0) 46 | liquid (= 2.6.2) 47 | maruku (= 0.7.0) 48 | mercenary (~> 0.3) 49 | pygments.rb (= 0.6.3) 50 | rdiscount (= 2.1.7) 51 | redcarpet (= 3.3.2) 52 | terminal-table (~> 1.4) 53 | github-pages-health-check (0.5.3) 54 | addressable (~> 2.3) 55 | net-dns (~> 0.8) 56 | public_suffix (~> 1.4) 57 | typhoeus (~> 0.7) 58 | html-pipeline (1.9.0) 59 | activesupport (>= 2) 60 | nokogiri (~> 1.4) 61 | i18n (1.0.1) 62 | concurrent-ruby (~> 1.0) 63 | jekyll (2.4.0) 64 | classifier-reborn (~> 2.0) 65 | colorator (~> 0.1) 66 | jekyll-coffeescript (~> 1.0) 67 | jekyll-gist (~> 1.0) 68 | jekyll-paginate (~> 1.0) 69 | jekyll-sass-converter (~> 1.0) 70 | jekyll-watch (~> 1.1) 71 | kramdown (~> 1.3) 72 | liquid (~> 2.6.1) 73 | mercenary (~> 0.3.3) 74 | pygments.rb (~> 0.6.0) 75 | redcarpet (~> 3.1) 76 | safe_yaml (~> 1.0) 77 | toml (~> 0.1.0) 78 | jekyll-coffeescript (1.0.1) 79 | coffee-script (~> 2.2) 80 | jekyll-feed (0.3.1) 81 | jekyll-gist (1.3.5) 82 | jekyll-mentions (0.2.1) 83 | html-pipeline (~> 1.9.0) 84 | jekyll (~> 2.0) 85 | jekyll-paginate (1.1.0) 86 | jekyll-redirect-from (0.8.0) 87 | jekyll (>= 2.0) 88 | jekyll-sass-converter (1.3.0) 89 | sass (~> 3.2) 90 | jekyll-sitemap (0.8.1) 91 | jekyll-watch (1.3.0) 92 | listen (~> 3.0) 93 | jemoji (0.5.0) 94 | gemoji (~> 2.0) 95 | html-pipeline (~> 1.9) 96 | jekyll (>= 2.0) 97 | kramdown (1.5.0) 98 | liquid (2.6.2) 99 | listen (3.0.3) 100 | rb-fsevent (>= 0.9.3) 101 | rb-inotify (>= 0.9) 102 | maruku (0.7.0) 103 | mercenary (0.3.5) 104 | mini_portile2 (2.3.0) 105 | minima (1.2.0) 106 | minitest (5.11.3) 107 | net-dns (0.8.0) 108 | nokogiri (1.8.2) 109 | mini_portile2 (~> 2.3.0) 110 | parslet (1.5.0) 111 | blankslate (~> 2.0) 112 | posix-spawn (0.3.11) 113 | public_suffix (1.5.1) 114 | pygments.rb (0.6.3) 115 | posix-spawn (~> 0.3.6) 116 | yajl-ruby (~> 1.3.1) 117 | rb-fsevent (0.9.6) 118 | rb-inotify (0.9.5) 119 | ffi (>= 0.5.0) 120 | rdiscount (2.1.7) 121 | redcarpet (3.3.2) 122 | rspec (3.3.0) 123 | rspec-core (~> 3.3.0) 124 | rspec-expectations (~> 3.3.0) 125 | rspec-mocks (~> 3.3.0) 126 | rspec-core (3.3.2) 127 | rspec-support (~> 3.3.0) 128 | rspec-expectations (3.3.1) 129 | diff-lcs (>= 1.2.0, < 2.0) 130 | rspec-support (~> 3.3.0) 131 | rspec-mocks (3.3.2) 132 | diff-lcs (>= 1.2.0, < 2.0) 133 | rspec-support (~> 3.3.0) 134 | rspec-support (3.3.0) 135 | safe_yaml (1.0.4) 136 | sass (3.4.19) 137 | terminal-table (1.5.2) 138 | thread_safe (0.3.6) 139 | toml (0.1.2) 140 | parslet (~> 1.5.0) 141 | typhoeus (0.8.0) 142 | ethon (>= 0.8.0) 143 | tzinfo (1.2.5) 144 | thread_safe (~> 0.1) 145 | yajl-ruby (1.3.1) 146 | 147 | PLATFORMS 148 | ruby 149 | 150 | DEPENDENCIES 151 | github-pages 152 | json! 153 | minima 154 | rspec 155 | 156 | BUNDLED WITH 157 | 1.16.2 158 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Akimichi Tatsukawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 「関数型プログラミングの基礎」サンプルコード 2 | 3 | このレポジトリは、リックテレコム社刊行の[「関数型プログラミングの基礎」](https://www.amazon.co.jp/%E9%96%A2%E6%95%B0%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E5%9F%BA%E7%A4%8E-JavaScript%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6-%E7%AB%8B%E5%B7%9D%E5%AF%9F%E7%90%86/dp/4865940596/ref=sr_1_1?ie=UTF8&qid=1476598423&sr=8-1&keywords=%E9%96%A2%E6%95%B0%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)のサンプルコードをおさめたものです。 4 | 5 | github pagesのサイトは、http://akimichi.github.io/functionaljs/ になります。 6 | 7 | ## 利用法 8 | 9 | サンプルコードを利用するには、まず最初に本レポジトリをクローンし、次にそのディレクトリに入ります。 10 | 11 | ~~~ 12 | $ git clone git@github.com:akimichi/functionaljs.git 13 | $ cd functionaljs 14 | ~~~ 15 | 16 | テスト環境の構築には、 1) 個別にインストールする, 2) docker を使う 、 の2つの方法があります。 17 | 18 | ### ローカル環境にテスト環境を個別にインストールする 19 | 20 | ここでは ubuntu が動作している環境にテスト環境をインストールする方法を説明します。 21 | 他のOSについては、書籍を参照ください。 22 | 23 | #### node.js のインストール 24 | 25 | node.jsのインストールは、[nvm](https://github.com/creationix/nvm)を用います。 26 | 27 | nvmをインストールするには、curlコマンドを用いて次のようにするのが簡便です。 28 | 29 | ~~~ 30 | $ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.0/install.sh | bash 31 | ~~~ 32 | 33 | あるいはwgetコマンドを用いる場合は、次のようになります。 34 | 35 | ~~~ 36 | $ wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.32.0/install.sh | bash 37 | ~~~ 38 | 39 | 上記の方法はスクリプトが移動したなどの理由で失敗することがあります。 40 | もしインストールに失敗する場合は、https://github.com/creationix/nvm を参考にして最新の方法でインストールしてください。 41 | 42 | 次に、node.js v0.12.0 をインストールします。 43 | 44 | ~~~ 45 | $ nvm install v0.12.0 46 | ~~~ 47 | 48 | ### テストの実行 49 | 50 | ローカル環境に nvm がインストールされていることが必要です。 51 | 52 | レポジトリをクローンしたディレクトリに移動します。 53 | 54 | ~~~ 55 | cd functionajs 56 | ~~~ 57 | 58 | nvm use で node.jsのバージョン v0.12.0 を使うことを指定します。 59 | npm install で必要なパッケージをインストールします。 60 | 61 | ~~~ 62 | $ nvm use 63 | $ npm install 64 | ~~~ 65 | 66 | テストを実行するには [gulp](http://gulpjs.com/) を利用します。 67 | gulpコマンドを利用するため、以下のようにgulpをグローバルにインストールします。 68 | 69 | ~~~ 70 | $ npm install -g gulp 71 | ~~~ 72 | 73 | これでJavaScriptのコードをテストする準備が整いました。 74 | コードのテストは、以下のようにします。 75 | 76 | ~~~ 77 | $ gulp js-test 78 | ~~~ 79 | 80 | なおscalaとhaskellのコードをテストするには、以下のdockerによるインストールを参照ください。 81 | 82 | ### dockerを使う 83 | 84 | [docker](https://www.docker.com/)を使って、各種のテスト環境を構築できます。 85 | あらかじめdockerをインストールしておいてください。 86 | この方法は、dockerさえインストールしておけば確実に環境を構築できるという利点があります。 87 | ただし、dockerイメージは約4GBあるのでディスク容量の少ないマシンでの利用には注意してください。 88 | 89 | なお、dockerを使ったインストールは、リックテレコム社が推奨する方法では**ありません**。 90 | インストール時の問題等のついては、 https://github.com/akimichi/functionaljs/issues に投稿してください。 91 | 92 | #### dockerイメージを準備する 93 | 94 | dockerコンテナを動かす前に、dockerイメージを準備する必要があります。 95 | dockerイメージを取得するには、2つの方法があります。 96 | ひとつは docker hub からダウンロードする方法で、もうひとつはDockerfileから自分で作成する方法です。 97 | 98 | ##### docker hubから取得する 99 | 100 | docker hubからイメージをダウンロードするには、pullコマンドを利用します。 101 | 102 | ~~~ 103 | $ docker pull emile/functionaljs:v1 104 | ~~~ 105 | 106 | ##### dockerのイメージを自分で作成する 107 | 108 | イメージを準備するもう一つの方法は、Dockerfileをもとに自分でdockerイメージを作成する方法です。 109 | イメージをローカル環境に作成するには、dockerコマンドで以下のようにします。 110 | 111 | ~~~ 112 | $ docker build -t="username/functionaljs:v1" . 113 | ~~~ 114 | 115 | なお、上記コマンドのusernameには基本的にユーザー名がはいります。 116 | 117 | #### 単体テストを実行する 118 | 119 | dockerイメージが準備できれば、そのイメージからコンテナを起動することでテストの実行が可能です。 120 | 121 | 以下のコマンドでnode.jsのコードをテストします。 122 | もし自分のユーザー名でイメージを作成した場合は、以下のemileの箇所を、そのユーザー名に置きかえてください。 123 | 124 | ~~~ 125 | $ docker run -it --rm --workdir="/workspace/nodejs" emile/functionaljs:v1 /bin/bash --login -i -c "gulp --harmony js-test" 126 | ~~~ 127 | 128 | 以下のコマンドでscala のコードをテストします。 129 | 130 | ~~~ 131 | $ docker run -it --rm --workdir="/workspace/scala" emile/functionaljs:v1 /bin/bash -c "sbt test" 132 | ~~~ 133 | 134 | 以下のコマンドでhaskell のコードをテストします。 135 | 136 | ~~~ 137 | $ docker run -it --rm --workdir="/workspace/haskell" emile/functionaljs:v1 /bin/bash -c "stack test" 138 | ~~~ 139 | 140 | #### REPLを実行する 141 | 142 | dockerコンテナにログインすることで、node.jsなどの対話的環境(REPL)を実行できます。 143 | 144 | REPL を実行するには、まずコンテナにログインします。 145 | 146 | ~~~ 147 | $ docker run -it --workdir="/workspace" emile/functionaljs:v1 bash --login -i 148 | ~~~ 149 | 150 | これでコンテナ内の /workspace ディレクトリにログインしました。 151 | 152 | node.jsのREPLを試すには、以下のように nodejsのディレクトリに移動して nodeコマンド を呼びだします。 153 | コンソールを抜けるときは Ctrl-C を2回続けて押します。 154 | 155 | ~~~ 156 | $ cd nodejs/ 157 | $ node 158 | > 1 + 2 159 | 3 160 | > 161 | (^C again to quit) 162 | ~~~ 163 | 164 | scala のREPLを試すには、 scalaのディレクトリに移動して、 sbt console を起動します。 165 | コンソールを抜けるには、:q を入力します。 166 | 167 | ~~~ 168 | $ cd scala 169 | $ sbt console 170 | 171 | [info] Loading project definition from /workspace/scala/project 172 | [info] Set current project to Functional Book Test Project (in build file:/workspace/scala/) 173 | [info] Starting scala interpreter... 174 | [info] 175 | Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_80). 176 | Type in expressions to have them evaluated. 177 | Type :help for more information. 178 | 179 | scala> 1 + 2 180 | res0: Int = 3 181 | 182 | scala> :q 183 | ~~~ 184 | 185 | haskellのREPLを試すには、 haskell のディレクトリに移動して、 ghci を起動します。 186 | コンソールを抜けるには、:q を入力します。 187 | 188 | ~~~ 189 | $ cd haskell 190 | $ ghci 191 | 192 | GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help 193 | Prelude> 1 + 2 194 | 3 195 | Prelude> :q 196 | Leaving GHCi. 197 | ~~~ 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'fileutils' 3 | require 'rake/clean' 4 | 5 | 6 | task :default => :doc 7 | 8 | task :doc do 9 | command = "npx docco ./test/*.js ./lib/*.js -c docs/css/docco.css -t docs/template/docco.jst" 10 | # command = "docker run -it --rm -v $PWD:/usr/src/app registry.homeunix.net:5000/emile/nodejs-labo-6.10:0.7" 11 | sh command 12 | end 13 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /bin/cat.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* 4 | $ node --harmony bin/cat.js test/resources/dream.txt 5 | 6 | */ 7 | 8 | var pair = require('./pair'); 9 | 10 | var IO = { 11 | /* #@range_begin(io_monad_definition_with_world) */ 12 | // unit:: T => IO[T] 13 | unit: (any) => { 14 | return (world) => { // 引数worldは現在の外界 15 | return pair.cons(any, world); 16 | }; 17 | }, 18 | // flatMap:: IO[A] => (A => IO[B]) => IO[B] 19 | flatMap: (instanceA) => { 20 | return (actionAB) => { // actionAB:: A -> IO[B] 21 | return (world) => { // 引数worldは現在の外界 22 | /* 現在の外界のなかで instanceAのIOアクションを実行する */ 23 | var newPair = instanceA(world); 24 | return pair.match(newPair,{ 25 | cons: (value, newWorld) => { 26 | /* 27 | 新しい外界のなかで、actionAB(value)で作られた 28 | IOアクションを実行する 29 | */ 30 | return actionAB(value)(newWorld); 31 | } 32 | }); 33 | }; 34 | }; 35 | }, 36 | /* #@range_end(io_monad_definition_with_world) */ 37 | /* #@range_begin(io_monad_definition_with_world_helper_function) */ 38 | /* done:: T => IO[T] 39 | done関数 */ 40 | done: (any) => { 41 | return IO.unit(); 42 | }, 43 | /* run:: IO[A] => A */ 44 | run: (instanceM) => { 45 | return (world) => { 46 | /* IOアクションを現在の外界に適用し、結果のみを返す */ 47 | return pair.left(instanceM(world)); 48 | }; 49 | }, 50 | /* #@range_end(io_monad_definition_with_world_helper_function) */ 51 | /* #@range_begin(io_actions) */ 52 | /* readFile:: STRING => IO[STRING] 53 | readFile関数は、pathで指定されたファイルを 54 | 読み込むIOアクション */ 55 | readFile: (path) => { 56 | return (world) => { // 外界を引数とする 57 | var fs = require('fs'); 58 | var content = fs.readFileSync(path, 'utf8'); 59 | return IO.unit(content)(world); // 外界を渡してIOアクションを返す 60 | }; 61 | }, 62 | /* println:: STRING => IO[] 63 | println関数は、messageで指定された文字列を 64 | コンソール画面に出力するIOアクション */ 65 | println: (message) => { 66 | return (world) => { // IOモナドを返す 67 | console.log(message); 68 | return IO.unit(null)(world); 69 | }; 70 | } 71 | /* #@range_end(io_actions) */ 72 | }; 73 | 74 | 75 | 76 | /* #@range_begin(io_monad_combined) */ 77 | var initialWorld = null; 78 | var path = process.argv[2]; 79 | 80 | IO.flatMap(IO.readFile(path))((content) => { // contentにはファイルの内容が入っている 81 | return IO.flatMap(IO.println(content))((_) => { 82 | return IO.done(_); 83 | }); 84 | })(initialWorld); 85 | /* #@range_end(io_monad_combined) */ 86 | -------------------------------------------------------------------------------- /bin/dentaku.normal.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Dentaku = require('../lib/dentaku.normal.js'); 4 | var readline = require('readline'); 5 | var prompt = "input> "; 6 | 7 | var rl = readline.createInterface({ 8 | input: process.stdin, 9 | output: process.stdout 10 | }); 11 | 12 | rl.on('line', (input) => { 13 | console.log(Dentaku.evaluate(input)); 14 | rl.setPrompt(prompt, prompt.length); 15 | rl.prompt(); 16 | }); 17 | 18 | rl.setPrompt(prompt, prompt.length); 19 | rl.prompt(); 20 | 21 | // rl.question("dentaku> ", (input) => { 22 | // // TODO: Log the answer in a database 23 | // console.log(Dentaku.evaluate(input)); 24 | // rl.close(); 25 | // }); 26 | -------------------------------------------------------------------------------- /bin/echo.js: -------------------------------------------------------------------------------- 1 | /* #@range_begin(stdin_stream) */ 2 | "use strict"; 3 | 4 | process.stdin.resume(); 5 | process.stdin.setEncoding('utf8'); 6 | 7 | var fragment = ""; 8 | 9 | var prompt = (_) => { 10 | process.stdout.write("> "); 11 | }; 12 | 13 | var mkLines = (chunk) => { 14 | var lines = chunk.split("\n"); 15 | lines[0] = fragment + lines[0]; 16 | fragment = lines.pop(); 17 | return lines; 18 | }; 19 | 20 | prompt(); 21 | 22 | process.stdin.on('data', (chunk) => { 23 | mkLines(chunk).forEach((line) => { 24 | console.log(line); 25 | }); 26 | prompt(); 27 | }); 28 | 29 | // ストリーム終了時に呼ばれる. 30 | process.stdin.on('end', function(){ 31 | console.log("EXIT"); 32 | }); 33 | /* #@range_end(stdin_stream) */ 34 | -------------------------------------------------------------------------------- /bin/input-capitalise-driver.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // ストリームでユーザー入力を制御する 4 | 5 | var expect = require('expect.js'); 6 | var readline = require('readline'); 7 | 8 | var input = require('./input-capitalise.js'); 9 | 10 | var rl = readline.createInterface({ 11 | input: process.stdin, 12 | output: process.stdout 13 | }); 14 | 15 | var question = rl.question("英単語を入力してください ", (answer) => { 16 | // TODO: Log the answer in a database 17 | var capitalise = (ch) => { 18 | return ch.toUpperCase(); 19 | }; 20 | console.log("あなたの入力: ", input.stream.toString.call(input, 21 | input.stream.map.call(input, 22 | input.stream.fromString(answer))(capitalise))); 23 | 24 | rl.close(); 25 | }); 26 | -------------------------------------------------------------------------------- /bin/input-capitalise.js: -------------------------------------------------------------------------------- 1 | (function(exports) { 2 | 3 | "use strict"; 4 | 5 | // ストリームでユーザー入力を制御する 6 | 7 | var expect = require('expect.js'); 8 | // var readline = require('readline'); 9 | // var rl = readline.createInterface({ 10 | // input: process.stdin, 11 | // output: process.stdout 12 | // }); 13 | var self = { 14 | match: (data, pattern) => { 15 | // return data(pattern); 16 | return data.call(pattern, pattern); 17 | }, 18 | string: { 19 | head: (str) => { 20 | expect(str).to.a('string'); 21 | return str[0]; 22 | }, 23 | tail: (str) => { 24 | expect(str).to.a('string'); 25 | return str.substring(1); 26 | }, 27 | isEmpty: (str) => { 28 | return str.length === 0; 29 | }, 30 | concat: (str1, str2) => { 31 | 32 | 33 | }, 34 | toArray: (str) => { 35 | expect(str).to.a('string'); 36 | var glue = (item) => { 37 | return (rest) => { 38 | return [item].concat(rest); 39 | }; 40 | }; 41 | if(self.string.isEmpty(str)) { 42 | return []; 43 | } else { 44 | return [self.string.head(str)].concat(self.string.toArray(self.string.tail(str))); 45 | } 46 | } 47 | }, 48 | stream: { 49 | empty: (_) => { 50 | return (pattern) => { 51 | expect(pattern).to.an('object'); 52 | return pattern.empty(); 53 | }; 54 | }, 55 | cons: (head,tailThunk) => { 56 | expect(tailThunk).to.a('function'); 57 | return (pattern) => { 58 | expect(pattern).to.an('object'); 59 | return pattern.cons(head,tailThunk); 60 | }; 61 | }, 62 | // head:: STREAM -> MAYBE[STREAM] 63 | head: (lazyList) => { 64 | return self.match(lazyList,{ 65 | empty: (_) => { 66 | return undefined; 67 | }, 68 | cons: (value, tailThunk) => { 69 | return value; 70 | } 71 | }); 72 | }, 73 | // tail:: STREAM -> MAYBE[STREAM] 74 | tail: (lazyList) => { 75 | return self.match(lazyList,{ 76 | empty: (_) => { 77 | return undefined; 78 | }, 79 | cons: (head, tailThunk) => { 80 | return tailThunk(); 81 | } 82 | }); 83 | }, 84 | isEmpty: (lazyList) => { 85 | return self.match(lazyList,{ 86 | empty: (_) => { 87 | return true; 88 | }, 89 | cons: (head,tailThunk) => { 90 | return false; 91 | } 92 | }); 93 | }, 94 | // ## stream#map 95 | map: (lazyList) => { 96 | return (transform) => { 97 | return self.match(lazyList,{ 98 | empty: (_) => { 99 | return self.stream.empty(); 100 | }, 101 | cons: (head,tailThunk) => { 102 | return self.stream.cons(transform(head),(_) => { 103 | return self.stream.map(tailThunk())(transform); 104 | }); 105 | } 106 | }); 107 | }; 108 | }, 109 | // ## stream#concat 110 | concat: (xs) => { 111 | return (ysThunk) => { 112 | return self.match(xs,{ 113 | empty: (_) => { 114 | return ysThunk(); 115 | }, 116 | cons: (head,tailThunk) => { 117 | return self.stream.cons(head,(_) => { 118 | return self.stream.concat(tailThunk())(ysThunk); 119 | }); 120 | } 121 | }); 122 | }; 123 | }, 124 | // ## stream#flatten 125 | // flatten :: STREAM[STREAM[T]] => STREAM[T] 126 | flatten: (lazyList) => { 127 | return self.match(lazyList,{ 128 | empty: (_) => { 129 | return self.stream.empty(); 130 | }, 131 | cons: (head,tailThunk) => { 132 | return self.stream.concat(head)((_) => { 133 | return self.stream.flatten(tailThunk()); 134 | }); 135 | } 136 | }); 137 | }, 138 | // ### stream#take 139 | // take:: STREAM -> NUMBER -> STREAM 140 | take: (lazyList) => { 141 | return (number) => { 142 | expect(number).to.a('number'); 143 | expect(number).to.be.greaterThan(-1); 144 | return self.match(lazyList,{ 145 | empty: (_) => { 146 | return self.stream.empty(); 147 | }, 148 | cons: (head,tailThunk) => { 149 | if(number === 0) { 150 | return self.stream.empty(); 151 | } else { 152 | return self.stream.cons(head,(_) => { 153 | return self.stream.take(tailThunk())(number -1); 154 | }); 155 | } 156 | } 157 | }); 158 | }; 159 | }, 160 | /* #@range_begin(stream_filter) */ 161 | filter: (lazyList) => { 162 | return (predicate) => { 163 | expect(predicate).to.a('function'); 164 | return self.match(lazyList,{ 165 | empty: (_) => { 166 | return self.stream.empty(); 167 | }, 168 | cons: (head,tailThunk) => { 169 | if(predicate(head)){ 170 | return self.stream.cons(head,(_) => { 171 | return self.stream.filter(tailThunk())(predicate); 172 | }); 173 | } else { 174 | return self.stream.filter(tailThunk())(predicate); 175 | } 176 | } 177 | }); 178 | }; 179 | }, 180 | toArray: (lazyList) => { 181 | return self.match(lazyList,{ 182 | empty: (_) => { 183 | return []; 184 | }, 185 | cons: (head,tailThunk) => { 186 | return self.match(tailThunk(),{ 187 | empty: (_) => { 188 | return [head]; 189 | }, 190 | cons: (head_,tailThunk_) => { 191 | return [head].concat(self.stream.toArray(tailThunk())); 192 | } 193 | }); 194 | } 195 | }); 196 | }, 197 | // ### stream#fromList 198 | fromArray: (array) => { 199 | return array.reduce((accumulator, item) => { 200 | return self.stream.concat(accumulator)(self.stream.cons(item, (_) => { 201 | return self.stream.empty(); 202 | })); 203 | }); 204 | }, 205 | toString: (lazyList) => { 206 | return self.match(lazyList,{ 207 | empty: (_) => { 208 | return []; 209 | }, 210 | cons: (head,tailThunk) => { 211 | return self.match(tailThunk(),{ 212 | empty: (_) => { 213 | return ""; 214 | }, 215 | cons: (head_,tailThunk_) => { 216 | return head + self.stream.toString(tailThunk()); 217 | } 218 | }); 219 | } 220 | }); 221 | }, 222 | fromString: (str) => { 223 | expect(str).to.a('string'); 224 | if(self.string.isEmpty(str)) { 225 | return self.stream.empty(); 226 | } else { 227 | return self.stream.cons(self.string.head(str), () => { 228 | self.stream.fromString(self.string.tail(str)); 229 | }); 230 | } 231 | } 232 | } // stream 233 | }; // self 234 | 235 | module.exports = self; 236 | 237 | })(module.exports); 238 | -------------------------------------------------------------------------------- /bin/input-readline.js: -------------------------------------------------------------------------------- 1 | // ストリームでユーザー入力を制御する 2 | 3 | var readline = require('readline'); 4 | var rl = readline.createInterface({ 5 | input: process.stdin, 6 | output: process.stdout 7 | }); 8 | 9 | rl.question("何か入力してください ", function(answer) { 10 | // TODO: Log the answer in a database 11 | console.log("あなたの入力: ", answer); 12 | 13 | rl.close(); 14 | }); 15 | -------------------------------------------------------------------------------- /bin/io.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // unit:: a -> IO a 4 | var unit = (any) => { 5 | return (_) => { 6 | return any; 7 | }; 8 | }; 9 | 10 | // done:: T -> IO T 11 | var done = (any) => { 12 | return unit(); 13 | }; 14 | 15 | // flatMap:: IO a -> (a -> IO b) -> IO b 16 | var flatMap = (instanceA) => { 17 | return (actionAB) => { // actionAB:: a -> IO b 18 | return unit(run(actionAB(run(instanceA)))); 19 | }; 20 | }; 21 | 22 | // run:: IO A -> A 23 | var run = (instance) => { 24 | return instance(); 25 | }; 26 | 27 | var readFile = (path) => { 28 | return (io) => { 29 | var fs = require('fs'); 30 | var content = fs.readFileSync(path, 'utf8'); 31 | return content; 32 | }; 33 | }; 34 | 35 | var writeFile = (content) => { 36 | return (io) => { 37 | console.log(content); 38 | return null; 39 | }; 40 | }; 41 | 42 | 43 | var println = (message) => { 44 | return (io) => { 45 | console.log(message); 46 | return null; 47 | }; 48 | }; 49 | 50 | // var readln = function(io) { 51 | // var fs = require('fs'); 52 | // var length = 80; 53 | // var buffer = new Buffer(length); 54 | // fs.readSync(process.stdin.fd, buffer, 0, length) 55 | // var line = buffer.split(/\r?\n/); 56 | // return line; 57 | // }; 58 | 59 | run(println("test")); 60 | run(readFile("./io.js")); 61 | 62 | flatMap(readFile("./io.js"))((content) => { 63 | return flatMap(println(content))((_) => { 64 | return done(); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /bin/io_with_world.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var pair = require('./pair'); 4 | 5 | /* #@range_begin(pair_datatype) */ 6 | // var pair = { 7 | // // pair の代数的データ構造 8 | // cons: (left, right) => { 9 | // return (pattern) => { 10 | // return pattern.cons(left, right); 11 | // }; 12 | // }, 13 | // match : (data, pattern) => { 14 | // return data.call(pair, pattern); 15 | // }, 16 | // // ペアの右側を取得する 17 | // right: (tuple) => { 18 | // return pair.match(tuple, { 19 | // cons: (left, right) => { 20 | // return right; 21 | // } 22 | // }); 23 | // }, 24 | // // ペアの左側を取得する 25 | // left: (tuple) => { 26 | // return pair.match(tuple, { 27 | // cons: (left, right) => { 28 | // return left; 29 | // } 30 | // }); 31 | // } 32 | // }; 33 | /* #@range_end(pair_datatype) */ 34 | 35 | var IO = { 36 | /* #@range_begin(io_monad_definition_with_world) */ 37 | // unit:: a -> IO a 38 | unit: (any) => { 39 | return (world) => { 40 | return any; 41 | }; 42 | }, 43 | // flatMap:: IO a -> (a -> IO b) -> IO b 44 | flatMap: (instanceA) => { 45 | return (actionAB) => { // actionAB:: a -> IO b 46 | return (world) => { 47 | var newPair = instanceA(world); // 現在の外界のなかで instanceAのIOアクションを実行する 48 | return pair.match(newPair,{ 49 | cons: (value, newWorld) => { 50 | return actionAB(value)(newWorld); // 新しい外界のなかで、actionAB(value)で作られたIOアクションを実行する 51 | } 52 | }); 53 | }; 54 | }; 55 | }, 56 | /* #@range_begin(io_monad_definition_with_world_helper_function) */ 57 | // done:: T -> IO T 58 | done: (any) => { 59 | return this.unit(); 60 | }, 61 | // run:: IO A -> A 62 | run: (instance) => { 63 | return instance(); 64 | }, 65 | /* #@range_end(io_monad_definition_with_world_helper_function) */ 66 | /* #@range_begin(io_actions) */ 67 | // readFile:: STRING => IO[STRING] 68 | readFile: (path) => { 69 | return (io) => { 70 | var fs = require('fs'); 71 | var content = fs.readFileSync(path, 'utf8'); 72 | return content; 73 | }; 74 | }, 75 | // println:: STRING => IO[null] 76 | println: (message) => { 77 | return (io) => { 78 | console.log(message); 79 | return null; 80 | }; 81 | } 82 | /* #@range_end(io_actions) */ 83 | }; 84 | /* #@range_end(io_monad_definition_with_world) */ 85 | 86 | 87 | -------------------------------------------------------------------------------- /bin/io_without_world.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* 4 | 外界を明示しないIOモナド 5 | 6 | */ 7 | 8 | 9 | var expect = require('expect.js'); 10 | var pair = require('./pair'); 11 | 12 | module.exports = { 13 | /* #@range_begin(io_monad_definition_with_world) */ 14 | // unit:: T -> IO T 15 | // ただし、IO T は Nothing => T とする。 16 | unit: (any) => { 17 | return (_) => { 18 | return any; 19 | }; 20 | }, 21 | /* #@range_begin(io_monad_definition_with_world_helper_function) */ 22 | // done:: T -> IO T 23 | done: (any) => { 24 | var self = this; 25 | return self.unit(any); 26 | }, 27 | // flatMap:: IO T -> (T -> IO S) -> IO S 28 | flatMap: (instanceA) => { 29 | var self = this; 30 | return (actionAB) => { // actionAB:: T -> IO S 31 | return self.unit(self.run(actionAB(self.run(instanceA)))); 32 | }; 33 | }, 34 | // run:: IO A -> A 35 | run: (instance) => { 36 | return instance(); 37 | }, 38 | /* #@range_end(io_monad_definition_with_world_helper_function) */ 39 | /* #@range_begin(io_actions) */ 40 | // readFile:: STRING => IO[STRING] 41 | readFile: (path) => { 42 | return () => { 43 | var fs = require('fs'); 44 | var content = fs.readFileSync(path, 'utf8'); 45 | expect(content).to.a('string'); 46 | return content; 47 | }; 48 | }, 49 | // println:: STRING => IO[null] 50 | println: (message) => { 51 | return () => { 52 | console.log(message); 53 | return null; 54 | }; 55 | } 56 | /* #@range_end(io_actions) */ 57 | }; 58 | /* #@range_end(io_monad_definition_with_world) */ 59 | 60 | -------------------------------------------------------------------------------- /bin/list.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var string = require('./string'); 5 | 6 | module.exports = { 7 | match : (data, pattern) => { 8 | var self = this; 9 | return data.call(self, pattern); 10 | }, 11 | empty: (_) => { 12 | return (pattern) => { 13 | return pattern.empty(); 14 | }; 15 | }, 16 | cons: (value, alist) => { 17 | return (pattern) => { 18 | return pattern.cons(value, alist); 19 | }; 20 | }, 21 | head: (alist) => { 22 | var self = this; 23 | return this.match(alist, { 24 | empty: (_) => { 25 | return null; 26 | }, 27 | cons: (head, tail) => { 28 | return head; 29 | } 30 | }); 31 | }, 32 | tail: (alist) => { 33 | var self = this; 34 | return this.match(alist, { 35 | empty: (_) => { 36 | return null; 37 | }, 38 | cons: (head, tail) => { 39 | return tail; 40 | } 41 | }); 42 | }, 43 | isEmpty: (alist) => { 44 | var self = this; 45 | return self.match(alist, { 46 | empty: (_) => { 47 | return true; 48 | }, 49 | cons: (head, tail) => { 50 | return false; 51 | } 52 | }); 53 | }, 54 | // append:: LIST[T] -> LIST[T] -> LIST[T] 55 | // append [] ys = ys 56 | // append (x:xs) ys = x : (xs ++ ys) 57 | append: (xs) => { 58 | return (ys) => { 59 | return this.match(xs, { 60 | empty: (_) => { 61 | return ys; 62 | }, 63 | cons: (head, tail) => { 64 | return this.cons(head, this.append(tail)(ys)); 65 | } 66 | }); 67 | }; 68 | }, 69 | // list#concat 70 | // concat:: LIST[LIST[T]] -> LIST[T] 71 | // concat [] = [] 72 | // concat (xs:xss) = append(xs, xss) 73 | // or, 74 | // concat xss = foldr xss [] append 75 | concat: (xss) => { 76 | return this.match(xss,{ 77 | empty: (_) => { 78 | return this.empty(); 79 | }, 80 | cons: (xs,xss) => { 81 | return this.append(xs,xss); 82 | } 83 | }); 84 | }, 85 | last: (alist) => { 86 | var self = this; 87 | return this.match(alist, { 88 | empty: (_) => { 89 | return null; 90 | }, 91 | cons: (head, tail) => { 92 | return this.match(tail, { 93 | empty: (_) => { 94 | return head; 95 | }, 96 | cons: (head, _) => { 97 | return this.last(tail); 98 | } 99 | }); 100 | } 101 | }); 102 | }, 103 | // join:: LIST[LIST[T]] -> LIST[T] 104 | join: (list_of_list) => { 105 | return this.concat(list_of_list); 106 | }, 107 | // foldr:: LIST[T] -> T -> FUNC[T -> LIST] -> T 108 | foldr: (alist) => { 109 | var self = this; 110 | return (accumulator) => { 111 | return (glue) => { 112 | expect(glue).to.a('function'); 113 | return self.match(alist,{ 114 | empty: (_) => { 115 | return accumulator; 116 | }, 117 | cons: (head, tail) => { 118 | return glue(head)(self.foldr(tail)(accumulator)(glue)); 119 | } 120 | }); 121 | }; 122 | }; 123 | }, 124 | // map:: LIST[T] -> FUNC[T -> T] -> LIST[T] 125 | map: (alist) => { 126 | var self = this; 127 | return (transform) => { 128 | return this.match(alist,{ 129 | empty: (_) => { 130 | return this.empty(); 131 | }, 132 | cons: (head,tail) => { 133 | return this.cons(transform(head),this.map(tail)(transform)); 134 | } 135 | }); 136 | }; 137 | }, 138 | /* #@range_begin(list_reverse) */ 139 | reverse: (alist) => { 140 | var self = this; 141 | var reverseAux = (alist, accumulator) => { 142 | return this.match(alist, { 143 | empty: (_) => { 144 | return accumulator; // 空のリストの場合は終了 145 | }, 146 | cons: (head, tail) => { 147 | return reverseAux(tail, this.cons(head, accumulator)); 148 | } 149 | }); 150 | }; 151 | return reverseAux(alist, this.empty()); 152 | }, 153 | /* #@range_end(list_reverse) */ 154 | // ## list.filter 155 | /* #@range_begin(list_filter) */ 156 | filter: (alist) => { 157 | return (predicate) => { 158 | return this.match(alist,{ 159 | empty: (_) => { 160 | return this.empty(); 161 | }, 162 | cons: (head,tail) => { 163 | if(predicate(head)){ 164 | return this.cons(head,(_) => { 165 | return this.filter(tail)(predicate); 166 | }); 167 | } else { 168 | return this.filter(tail)(predicate); 169 | } 170 | } 171 | }); 172 | }; 173 | }, 174 | // list#length 175 | length: (alist) => { 176 | return this.match(alist,{ 177 | empty: (_) => { 178 | return 0; 179 | }, 180 | cons: (head,tail) => { 181 | return this.foldr(alist)(0)((item) => { 182 | return (accumulator) => { 183 | return 1 + accumulator; 184 | }; 185 | }); 186 | } 187 | }); 188 | }, 189 | any: (alist) => { 190 | return (predicate) => { 191 | expect(predicate).to.a('function'); 192 | return this.match(alist,{ 193 | empty: (_) => { 194 | return false; 195 | }, 196 | cons: (head,tail) => { 197 | if(predicate(head)) { 198 | return true; 199 | } else { 200 | return this.any(tail)(predicate); 201 | } 202 | } 203 | }); 204 | // return compose(self.list.or.bind(self))(self.flip.bind(self)(self.list.map.bind(self))(predicate))(list); 205 | }; 206 | }, 207 | /* #@range_end(list_filter) */ 208 | toArray: (alist) => { 209 | var toArrayAux = (alist,accumulator) => { 210 | return this.match(alist, { 211 | empty: (_) => { 212 | return accumulator; // 空のリストの場合は終了 213 | }, 214 | cons: (head, tail) => { 215 | return toArrayAux(tail, accumulator.concat(head)); 216 | } 217 | }); 218 | }; 219 | return toArrayAux(alist, []); 220 | }, 221 | fromArray: (array) => { 222 | expect(array).to.an('array'); 223 | return array.reduce((accumulator, item) => { 224 | return this.append(accumulator)(this.cons(item, this.empty())); 225 | }, this.empty()); 226 | }, 227 | /* #@range_begin(list_fromString) */ 228 | fromString: (str) => { 229 | var self = this; 230 | expect(str).to.a('string'); 231 | if(this.isEmpty(str)) { 232 | return this.empty(); 233 | } else { 234 | return this.cons(string.head(str), this.fromString(this.tail(str))); 235 | } 236 | }, 237 | /* #@range_end(list_fromString) */ 238 | at: (alist) => { 239 | return (index) => { 240 | expect(index).to.a('number'); 241 | expect(index).to.be.greaterThan(-1); 242 | if (index === 0) { 243 | return this.head(alist); 244 | } else { 245 | return this.at(this.tail(alist))(index - 1); 246 | } 247 | }; 248 | }, 249 | take: (alist) => { 250 | return (n) => { 251 | expect(n).to.a('number'); 252 | expect(n).to.be.greaterThan(-1); 253 | if (n === 0) { 254 | return this.empty(); 255 | } else { 256 | return this.cons(this.head)(this.take(this.tail)(n-1)); 257 | } 258 | }; 259 | }, 260 | // ## list#drop 261 | // drop :: List => List 262 | drop: function(list){ 263 | var self = this; 264 | return (n) => { 265 | expect(n).to.be.a('number'); 266 | expect(n).to.be.greaterThan(-1); 267 | if (n === 0) 268 | return list; 269 | else { 270 | if(self.this.isEmpty.bind(self)(list)) 271 | return self.this.empty; 272 | else { 273 | var tail = this.tail; 274 | return self.this.drop.bind(self)(tail)(n-1); 275 | } 276 | } 277 | }; 278 | }, 279 | /* #@range_begin(list_generate) */ 280 | generate: (alist) => { 281 | var theList = alist; 282 | return (_) => { 283 | return this.match(theList,{ 284 | empty: (_) => { 285 | return null; 286 | }, 287 | cons: (head,tail) => { 288 | theList = tail; 289 | return head; 290 | } 291 | }); 292 | }; 293 | } 294 | /* #@range_end(list_generate) */ 295 | }; 296 | -------------------------------------------------------------------------------- /bin/pair.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | /* #@range_begin(pair_datatype) */ 5 | // pair の代数的データ構造 6 | cons: (left, right) => { 7 | return (pattern) => { 8 | return pattern.cons(left, right); 9 | }; 10 | }, 11 | match : (data, pattern) => { 12 | return data( pattern); 13 | }, 14 | // ペアの右側を取得する 15 | right: (tuple) => { 16 | return this.match(tuple, { 17 | cons: (left, right) => { 18 | return right; 19 | } 20 | }); 21 | }, 22 | // ペアの左側を取得する 23 | left: (tuple) => { 24 | return this.match(tuple, { 25 | cons: (left, right) => { 26 | return left; 27 | } 28 | }); 29 | } 30 | /* #@range_end(pair_datatype) */ 31 | }; 32 | -------------------------------------------------------------------------------- /bin/read.js: -------------------------------------------------------------------------------- 1 | /* #@range_begin(file_stream) */ 2 | var fs = require('fs'); 3 | 4 | // 変数fstreamにはファイルの内容がストリームとして格納される 5 | var fstream = fs.createReadStream('/var/log/syslog', {encoding: 'utf-8'}); 6 | 7 | // データが入ってきたときに実行される 8 | fstream.on('data', (chunk) => { // chunkには読み込まれたデータの一部が入る 9 | console.log(chunk); 10 | }); 11 | // それ以上読み込むデータがないときに実行される 12 | fstream.on('end', () => { 13 | console.log("EXIT"); 14 | }); 15 | /* #@range_end(file_stream) */ 16 | 17 | // var main = (stream) => { 18 | // stream.on('data', (data) => { 19 | // console.log(data); 20 | // }); 21 | // stream.on('end', () => { 22 | // main(stream); 23 | // }); 24 | // }; 25 | 26 | 27 | // main(fstream); 28 | -------------------------------------------------------------------------------- /bin/string.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | 5 | module.exports = { 6 | head: (str) => { 7 | expect(str).to.a('string'); 8 | return str[0]; 9 | }, 10 | tail: (str) => { 11 | expect(str).to.a('string'); 12 | return str.substring(1); 13 | }, 14 | isEmpty: (str) => { 15 | return str.length === 0; 16 | }, 17 | toArray: (str) => { 18 | expect(str).to.a('string'); 19 | var glue = (item) => { 20 | return (rest) => { 21 | return [item].concat(rest); 22 | }; 23 | }; 24 | if(this.isEmpty(str)) { 25 | return []; 26 | } else { 27 | return [this.head(str)].concat(this.toArray(this.tail(str))); 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /bin/tarai_client.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | process.stdin.setEncoding('utf8'); 4 | 5 | /* #@range_begin(tarai_client) */ 6 | var net = require('net'); 7 | var socket = net.connect({ 8 | host: '127.0.0.1', 9 | port: 3000 10 | }); 11 | 12 | /* 13 | taraiサーバと接続したときに起動されるconnectイベントハンドラ 14 | */ 15 | socket.on('connect', () => { 16 | // コンソールの標準入力を読み出すためのreadableイベントハンドラ 17 | process.stdin.on('readable', () => { 18 | var chunk = process.stdin.read(); 19 | if (chunk !== null) { 20 | /* 読み込んだ文字列を数値に変換する */ 21 | var maybeInt = parseInt(chunk,10); 22 | if(isNaN(maybeInt)){ 23 | /* 数値でない場合、大文字に変換する */ 24 | process.stdout.write(chunk.toUpperCase()); 25 | } else { 26 | /* 数値の場合、taraiサーバに計算をリクエストする */ 27 | socket.write(maybeInt + '\r\n'); 28 | }; 29 | } 30 | }); 31 | }); 32 | 33 | /* 34 | taraiサーバからの計算結果を受け取るdataイベントハンドラ 35 | */ 36 | socket.on('data', (chunk) => { 37 | process.stdout.write(chunk.toString()); 38 | }); 39 | /* #@range_end(tarai_client) */ 40 | 41 | process.stdin.on('end', () => { 42 | process.stdout.write('end'); 43 | }); 44 | -------------------------------------------------------------------------------- /bin/tarai_server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* tarai関数 */ 4 | var tarai = (x,y,z) => { 5 | if(x > y) { 6 | return tarai(tarai(x - 1, y, z), 7 | tarai(y - 1, z, x), 8 | tarai(z - 1, x, y)); 9 | } else { 10 | return y; 11 | } 12 | }; 13 | /* #@range_begin(tarai_server) */ 14 | var net = require('net'); 15 | var localhost = '127.0.0.1'; 16 | 17 | net.createServer((socket) => { 18 | /* dataイベントハンドラ */ 19 | socket.on('data', (incomingData) => { 20 | /* クライアントからデータを数値に変換する */ 21 | var number = parseInt(incomingData,10); 22 | console.log(number); 23 | /* tarai関数を計算して、クライアントに返す */ 24 | socket.write(tarai(number * 2, number, 0) + '\r\n'); 25 | }); 26 | /* closeイベントハンドラ */ 27 | socket.on('close', (error) => { 28 | console.log("connection closed"); 29 | }); 30 | }).listen(3000, localhost); 31 | /* #@range_end(tarai_server) */ 32 | 33 | -------------------------------------------------------------------------------- /bin/tcp_server.js: -------------------------------------------------------------------------------- 1 | /* #@range_begin(tcp_server) */ 2 | "use strict"; 3 | 4 | var net = require('net'); 5 | var localhost = '127.0.0.1'; 6 | 7 | // サーバインスタンスを生成 8 | net.createServer((socket) => { 9 | // 'data' イベントハンドラ 10 | socket.on('data', (incomingData) => { 11 | socket.write(incomingData); 12 | }); 13 | // 'close'イベントハンドラ 14 | socket.on('close', (error) => { 15 | console.log("connection closed"); 16 | }); 17 | }).listen(3000, localhost); 18 | /* #@range_end(tcp_server) */ 19 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | autoCompilerPlugins := true 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Site settings 2 | title: Your awesome title 3 | email: your-email@domain.com 4 | description: > # this means to ignore newlines until "baseurl:" 5 | Write an awesome description for your new site here. You can edit this 6 | line in _config.yml. It will appear in your document head meta (for 7 | Google search results) and in your feed.xml site description. 8 | baseurl: "" # the subpath of your site, e.g. /blog/ 9 | url: "http://yourdomain.com" # the base hostname & protocol for your site 10 | twitter_username: jekyllrb 11 | github_username: jekyll 12 | 13 | # Build settings 14 | markdown: kramdown 15 | -------------------------------------------------------------------------------- /docs/_includes/footer.html: -------------------------------------------------------------------------------- 1 | 56 | -------------------------------------------------------------------------------- /docs/_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/_includes/header.html: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% include head.html %} 5 | 6 | 7 | 8 | {% include header.html %} 9 | 10 |
11 |
12 | {{ content }} 13 |
14 |
15 | 16 | {% include footer.html %} 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | 6 |
7 |

{{ page.title }}

8 |
9 | 10 |
11 | {{ content }} 12 |
13 | 14 |
15 | -------------------------------------------------------------------------------- /docs/_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | 6 |
7 |

{{ page.title }}

8 | 9 |
10 | 11 |
12 | {{ content }} 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /docs/_posts/2016-10-16-welcome-to-jekyll.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Welcome to Jekyll!" 4 | date: 2016-10-16 18:07:51 5 | categories: jekyll update 6 | --- 7 | You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve --watch`, which launches a web server and auto-regenerates your site when a file is updated. 8 | 9 | To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works. 10 | 11 | Jekyll also offers powerful support for code snippets: 12 | 13 | {% highlight ruby %} 14 | def print_hi(name) 15 | puts "Hi, #{name}" 16 | end 17 | print_hi('Tom') 18 | #=> prints 'Hi, Tom' to STDOUT. 19 | {% endhighlight %} 20 | 21 | Check out the [Jekyll docs][jekyll] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll’s dedicated Help repository][jekyll-help]. 22 | 23 | [jekyll]: http://jekyllrb.com 24 | [jekyll-gh]: https://github.com/jekyll/jekyll 25 | [jekyll-help]: https://github.com/jekyll/jekyll-help 26 | -------------------------------------------------------------------------------- /docs/_sass/_base.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Reset some basic elements 3 | */ 4 | body, h1, h2, h3, h4, h5, h6, 5 | p, blockquote, pre, hr, 6 | dl, dd, ol, ul, figure { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | 12 | 13 | /** 14 | * Basic styling 15 | */ 16 | body { 17 | font-family: $base-font-family; 18 | font-size: $base-font-size; 19 | line-height: $base-line-height; 20 | font-weight: 300; 21 | color: $text-color; 22 | background-color: $background-color; 23 | -webkit-text-size-adjust: 100%; 24 | } 25 | 26 | 27 | 28 | /** 29 | * Set `margin-bottom` to maintain vertical rhythm 30 | */ 31 | h1, h2, h3, h4, h5, h6, 32 | p, blockquote, pre, 33 | ul, ol, dl, figure, 34 | %vertical-rhythm { 35 | margin-bottom: $spacing-unit / 2; 36 | } 37 | 38 | 39 | 40 | /** 41 | * Images 42 | */ 43 | img { 44 | max-width: 100%; 45 | vertical-align: middle; 46 | } 47 | 48 | 49 | 50 | /** 51 | * Figures 52 | */ 53 | figure > img { 54 | display: block; 55 | } 56 | 57 | figcaption { 58 | font-size: $small-font-size; 59 | } 60 | 61 | 62 | 63 | /** 64 | * Lists 65 | */ 66 | ul, ol { 67 | margin-left: $spacing-unit; 68 | } 69 | 70 | li { 71 | > ul, 72 | > ol { 73 | margin-bottom: 0; 74 | } 75 | } 76 | 77 | 78 | 79 | /** 80 | * Headings 81 | */ 82 | h1, h2, h3, h4, h5, h6 { 83 | font-weight: 300; 84 | } 85 | 86 | 87 | 88 | /** 89 | * Links 90 | */ 91 | a { 92 | color: $brand-color; 93 | text-decoration: none; 94 | 95 | &:visited { 96 | color: darken($brand-color, 15%); 97 | } 98 | 99 | &:hover { 100 | color: $text-color; 101 | text-decoration: underline; 102 | } 103 | } 104 | 105 | 106 | 107 | /** 108 | * Blockquotes 109 | */ 110 | blockquote { 111 | color: $grey-color; 112 | border-left: 4px solid $grey-color-light; 113 | padding-left: $spacing-unit / 2; 114 | font-size: 18px; 115 | letter-spacing: -1px; 116 | font-style: italic; 117 | 118 | > :last-child { 119 | margin-bottom: 0; 120 | } 121 | } 122 | 123 | 124 | 125 | /** 126 | * Code formatting 127 | */ 128 | pre, 129 | code { 130 | font-size: 15px; 131 | border: 1px solid $grey-color-light; 132 | border-radius: 3px; 133 | background-color: #eef; 134 | } 135 | 136 | code { 137 | padding: 1px 5px; 138 | } 139 | 140 | pre { 141 | padding: 8px 12px; 142 | overflow-x: scroll; 143 | 144 | > code { 145 | border: 0; 146 | padding-right: 0; 147 | padding-left: 0; 148 | } 149 | } 150 | 151 | 152 | 153 | /** 154 | * Wrapper 155 | */ 156 | .wrapper { 157 | max-width: -webkit-calc(800px - (#{$spacing-unit} * 2)); 158 | max-width: calc(800px - (#{$spacing-unit} * 2)); 159 | margin-right: auto; 160 | margin-left: auto; 161 | padding-right: $spacing-unit; 162 | padding-left: $spacing-unit; 163 | @extend %clearfix; 164 | 165 | @include media-query($on-laptop) { 166 | max-width: -webkit-calc(800px - (#{$spacing-unit})); 167 | max-width: calc(800px - (#{$spacing-unit})); 168 | padding-right: $spacing-unit / 2; 169 | padding-left: $spacing-unit / 2; 170 | } 171 | } 172 | 173 | 174 | 175 | /** 176 | * Clearfix 177 | */ 178 | %clearfix { 179 | 180 | &:after { 181 | content: ""; 182 | display: table; 183 | clear: both; 184 | } 185 | } 186 | 187 | 188 | 189 | /** 190 | * Icons 191 | */ 192 | .icon { 193 | 194 | > svg { 195 | display: inline-block; 196 | width: 16px; 197 | height: 16px; 198 | vertical-align: middle; 199 | 200 | path { 201 | fill: $grey-color; 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /docs/_sass/_layout.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Site header 3 | */ 4 | .site-header { 5 | border-top: 5px solid $grey-color-dark; 6 | border-bottom: 1px solid $grey-color-light; 7 | min-height: 56px; 8 | 9 | // Positioning context for the mobile navigation icon 10 | position: relative; 11 | } 12 | 13 | .site-title { 14 | font-size: 26px; 15 | line-height: 56px; 16 | letter-spacing: -1px; 17 | margin-bottom: 0; 18 | float: left; 19 | 20 | &, 21 | &:visited { 22 | color: $grey-color-dark; 23 | } 24 | } 25 | 26 | .site-nav { 27 | float: right; 28 | line-height: 56px; 29 | 30 | .menu-icon { 31 | display: none; 32 | } 33 | 34 | .page-link { 35 | color: $text-color; 36 | line-height: $base-line-height; 37 | 38 | // Gaps between nav items, but not on the first one 39 | &:not(:first-child) { 40 | margin-left: 20px; 41 | } 42 | } 43 | 44 | @include media-query($on-palm) { 45 | position: absolute; 46 | top: 9px; 47 | right: 30px; 48 | background-color: $background-color; 49 | border: 1px solid $grey-color-light; 50 | border-radius: 5px; 51 | text-align: right; 52 | 53 | .menu-icon { 54 | display: block; 55 | float: right; 56 | width: 36px; 57 | height: 26px; 58 | line-height: 0; 59 | padding-top: 10px; 60 | text-align: center; 61 | 62 | > svg { 63 | width: 18px; 64 | height: 15px; 65 | 66 | path { 67 | fill: $grey-color-dark; 68 | } 69 | } 70 | } 71 | 72 | .trigger { 73 | clear: both; 74 | display: none; 75 | } 76 | 77 | &:hover .trigger { 78 | display: block; 79 | padding-bottom: 5px; 80 | } 81 | 82 | .page-link { 83 | display: block; 84 | padding: 5px 10px; 85 | } 86 | } 87 | } 88 | 89 | 90 | 91 | /** 92 | * Site footer 93 | */ 94 | .site-footer { 95 | border-top: 1px solid $grey-color-light; 96 | padding: $spacing-unit 0; 97 | } 98 | 99 | .footer-heading { 100 | font-size: 18px; 101 | margin-bottom: $spacing-unit / 2; 102 | } 103 | 104 | .contact-list, 105 | .social-media-list { 106 | list-style: none; 107 | margin-left: 0; 108 | } 109 | 110 | .footer-col-wrapper { 111 | font-size: 15px; 112 | color: $grey-color; 113 | margin-left: -$spacing-unit / 2; 114 | @extend %clearfix; 115 | } 116 | 117 | .footer-col { 118 | float: left; 119 | margin-bottom: $spacing-unit / 2; 120 | padding-left: $spacing-unit / 2; 121 | } 122 | 123 | .footer-col-1 { 124 | width: -webkit-calc(35% - (#{$spacing-unit} / 2)); 125 | width: calc(35% - (#{$spacing-unit} / 2)); 126 | } 127 | 128 | .footer-col-2 { 129 | width: -webkit-calc(20% - (#{$spacing-unit} / 2)); 130 | width: calc(20% - (#{$spacing-unit} / 2)); 131 | } 132 | 133 | .footer-col-3 { 134 | width: -webkit-calc(45% - (#{$spacing-unit} / 2)); 135 | width: calc(45% - (#{$spacing-unit} / 2)); 136 | } 137 | 138 | @include media-query($on-laptop) { 139 | .footer-col-1, 140 | .footer-col-2 { 141 | width: -webkit-calc(50% - (#{$spacing-unit} / 2)); 142 | width: calc(50% - (#{$spacing-unit} / 2)); 143 | } 144 | 145 | .footer-col-3 { 146 | width: -webkit-calc(100% - (#{$spacing-unit} / 2)); 147 | width: calc(100% - (#{$spacing-unit} / 2)); 148 | } 149 | } 150 | 151 | @include media-query($on-palm) { 152 | .footer-col { 153 | float: none; 154 | width: -webkit-calc(100% - (#{$spacing-unit} / 2)); 155 | width: calc(100% - (#{$spacing-unit} / 2)); 156 | } 157 | } 158 | 159 | 160 | 161 | /** 162 | * Page content 163 | */ 164 | .page-content { 165 | padding: $spacing-unit 0; 166 | } 167 | 168 | .page-heading { 169 | font-size: 20px; 170 | } 171 | 172 | .post-list { 173 | margin-left: 0; 174 | list-style: none; 175 | 176 | > li { 177 | margin-bottom: $spacing-unit; 178 | } 179 | } 180 | 181 | .post-meta { 182 | font-size: $small-font-size; 183 | color: $grey-color; 184 | } 185 | 186 | .post-link { 187 | display: block; 188 | font-size: 24px; 189 | } 190 | 191 | 192 | 193 | /** 194 | * Posts 195 | */ 196 | .post-header { 197 | margin-bottom: $spacing-unit; 198 | } 199 | 200 | .post-title { 201 | font-size: 42px; 202 | letter-spacing: -1px; 203 | line-height: 1; 204 | 205 | @include media-query($on-laptop) { 206 | font-size: 36px; 207 | } 208 | } 209 | 210 | .post-content { 211 | margin-bottom: $spacing-unit; 212 | 213 | h2 { 214 | font-size: 32px; 215 | 216 | @include media-query($on-laptop) { 217 | font-size: 28px; 218 | } 219 | } 220 | 221 | h3 { 222 | font-size: 26px; 223 | 224 | @include media-query($on-laptop) { 225 | font-size: 22px; 226 | } 227 | } 228 | 229 | h4 { 230 | font-size: 20px; 231 | 232 | @include media-query($on-laptop) { 233 | font-size: 18px; 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /docs/_sass/_syntax-highlighting.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Syntax highlighting styles 3 | */ 4 | .highlight { 5 | background: #fff; 6 | @extend %vertical-rhythm; 7 | 8 | .c { color: #998; font-style: italic } // Comment 9 | .err { color: #a61717; background-color: #e3d2d2 } // Error 10 | .k { font-weight: bold } // Keyword 11 | .o { font-weight: bold } // Operator 12 | .cm { color: #998; font-style: italic } // Comment.Multiline 13 | .cp { color: #999; font-weight: bold } // Comment.Preproc 14 | .c1 { color: #998; font-style: italic } // Comment.Single 15 | .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special 16 | .gd { color: #000; background-color: #fdd } // Generic.Deleted 17 | .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific 18 | .ge { font-style: italic } // Generic.Emph 19 | .gr { color: #a00 } // Generic.Error 20 | .gh { color: #999 } // Generic.Heading 21 | .gi { color: #000; background-color: #dfd } // Generic.Inserted 22 | .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific 23 | .go { color: #888 } // Generic.Output 24 | .gp { color: #555 } // Generic.Prompt 25 | .gs { font-weight: bold } // Generic.Strong 26 | .gu { color: #aaa } // Generic.Subheading 27 | .gt { color: #a00 } // Generic.Traceback 28 | .kc { font-weight: bold } // Keyword.Constant 29 | .kd { font-weight: bold } // Keyword.Declaration 30 | .kp { font-weight: bold } // Keyword.Pseudo 31 | .kr { font-weight: bold } // Keyword.Reserved 32 | .kt { color: #458; font-weight: bold } // Keyword.Type 33 | .m { color: #099 } // Literal.Number 34 | .s { color: #d14 } // Literal.String 35 | .na { color: #008080 } // Name.Attribute 36 | .nb { color: #0086B3 } // Name.Builtin 37 | .nc { color: #458; font-weight: bold } // Name.Class 38 | .no { color: #008080 } // Name.Constant 39 | .ni { color: #800080 } // Name.Entity 40 | .ne { color: #900; font-weight: bold } // Name.Exception 41 | .nf { color: #900; font-weight: bold } // Name.Function 42 | .nn { color: #555 } // Name.Namespace 43 | .nt { color: #000080 } // Name.Tag 44 | .nv { color: #008080 } // Name.Variable 45 | .ow { font-weight: bold } // Operator.Word 46 | .w { color: #bbb } // Text.Whitespace 47 | .mf { color: #099 } // Literal.Number.Float 48 | .mh { color: #099 } // Literal.Number.Hex 49 | .mi { color: #099 } // Literal.Number.Integer 50 | .mo { color: #099 } // Literal.Number.Oct 51 | .sb { color: #d14 } // Literal.String.Backtick 52 | .sc { color: #d14 } // Literal.String.Char 53 | .sd { color: #d14 } // Literal.String.Doc 54 | .s2 { color: #d14 } // Literal.String.Double 55 | .se { color: #d14 } // Literal.String.Escape 56 | .sh { color: #d14 } // Literal.String.Heredoc 57 | .si { color: #d14 } // Literal.String.Interpol 58 | .sx { color: #d14 } // Literal.String.Other 59 | .sr { color: #009926 } // Literal.String.Regex 60 | .s1 { color: #d14 } // Literal.String.Single 61 | .ss { color: #990073 } // Literal.String.Symbol 62 | .bp { color: #999 } // Name.Builtin.Pseudo 63 | .vc { color: #008080 } // Name.Variable.Class 64 | .vg { color: #008080 } // Name.Variable.Global 65 | .vi { color: #008080 } // Name.Variable.Instance 66 | .il { color: #099 } // Literal.Number.Integer.Long 67 | } 68 | -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: About 4 | permalink: /about/ 5 | --- 6 | 7 | This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](http://jekyllrb.com/) 8 | 9 | You can find the source code for the Jekyll new theme at: [github.com/jglovier/jekyll-new](https://github.com/jglovier/jekyll-new) 10 | 11 | You can find the source code for Jekyll at [github.com/jekyll/jekyll](https://github.com/jekyll/jekyll) 12 | -------------------------------------------------------------------------------- /docs/css/main.scss: -------------------------------------------------------------------------------- 1 | --- 2 | # Only the main Sass file needs front matter (the dashes are enough) 3 | --- 4 | @charset "utf-8"; 5 | 6 | 7 | 8 | // Our variables 9 | $base-font-family: Helvetica, Arial, sans-serif; 10 | $base-font-size: 16px; 11 | $small-font-size: $base-font-size * 0.875; 12 | $base-line-height: 1.5; 13 | 14 | $spacing-unit: 30px; 15 | 16 | $text-color: #111; 17 | $background-color: #fdfdfd; 18 | $brand-color: #2a7ae2; 19 | 20 | $grey-color: #828282; 21 | $grey-color-light: lighten($grey-color, 40%); 22 | $grey-color-dark: darken($grey-color, 25%); 23 | 24 | $on-palm: 600px; 25 | $on-laptop: 800px; 26 | 27 | 28 | 29 | // Using media queries with like this: 30 | // @include media-query($palm) { 31 | // .wrapper { 32 | // padding-right: $spacing-unit / 2; 33 | // padding-left: $spacing-unit / 2; 34 | // } 35 | // } 36 | @mixin media-query($device) { 37 | @media screen and (max-width: $device) { 38 | @content; 39 | } 40 | } 41 | 42 | 43 | 44 | // Import partials from `sass_dir` (defaults to `_sass`) 45 | @import 46 | "base", 47 | "layout", 48 | "syntax-highlighting" 49 | ; 50 | -------------------------------------------------------------------------------- /docs/feed.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: null 3 | --- 4 | 5 | 6 | 7 | {{ site.title | xml_escape }} 8 | {{ site.description | xml_escape }} 9 | {{ site.url }}{{ site.baseurl }}/ 10 | 11 | {{ site.time | date_to_rfc822 }} 12 | {{ site.time | date_to_rfc822 }} 13 | Jekyll v{{ jekyll.version }} 14 | {% for post in site.posts limit:10 %} 15 | 16 | {{ post.title | xml_escape }} 17 | {{ post.content | xml_escape }} 18 | {{ post.date | date_to_rfc822 }} 19 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 20 | {{ post.url | prepend: site.baseurl | prepend: site.url }} 21 | {% for tag in post.tags %} 22 | {{ tag | xml_escape }} 23 | {% endfor %} 24 | {% for cat in post.categories %} 25 | {{ cat | xml_escape }} 26 | {% endfor %} 27 | 28 | {% endfor %} 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/fileio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileio.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 | 198 | 199 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /docs/images/add-reduction-00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-00.png -------------------------------------------------------------------------------- /docs/images/add-reduction-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-01.png -------------------------------------------------------------------------------- /docs/images/add-reduction-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-02.png -------------------------------------------------------------------------------- /docs/images/add-reduction-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-03.png -------------------------------------------------------------------------------- /docs/images/add-reduction-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-04.png -------------------------------------------------------------------------------- /docs/images/add-reduction-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-05.png -------------------------------------------------------------------------------- /docs/images/add-reduction-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-06.png -------------------------------------------------------------------------------- /docs/images/add-reduction-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-07.png -------------------------------------------------------------------------------- /docs/images/add-reduction-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-08.png -------------------------------------------------------------------------------- /docs/images/add-reduction-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-09.png -------------------------------------------------------------------------------- /docs/images/add-reduction-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-10.png -------------------------------------------------------------------------------- /docs/images/add-reduction-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-11.png -------------------------------------------------------------------------------- /docs/images/add-reduction-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-12.png -------------------------------------------------------------------------------- /docs/images/add-reduction-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-13.png -------------------------------------------------------------------------------- /docs/images/add-reduction-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-14.png -------------------------------------------------------------------------------- /docs/images/add-reduction-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-15.png -------------------------------------------------------------------------------- /docs/images/add-reduction-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-16.png -------------------------------------------------------------------------------- /docs/images/add-reduction-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-17.png -------------------------------------------------------------------------------- /docs/images/add-reduction-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-18.png -------------------------------------------------------------------------------- /docs/images/add-reduction-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-19.png -------------------------------------------------------------------------------- /docs/images/add-reduction-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-20.png -------------------------------------------------------------------------------- /docs/images/add-reduction-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-21.png -------------------------------------------------------------------------------- /docs/images/add-reduction-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-22.png -------------------------------------------------------------------------------- /docs/images/add-reduction-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-23.png -------------------------------------------------------------------------------- /docs/images/add-reduction-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-24.png -------------------------------------------------------------------------------- /docs/images/add-reduction-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-25.png -------------------------------------------------------------------------------- /docs/images/add-reduction-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-26.png -------------------------------------------------------------------------------- /docs/images/add-reduction-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-27.png -------------------------------------------------------------------------------- /docs/images/add-reduction-28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-28.png -------------------------------------------------------------------------------- /docs/images/add-reduction-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-29.png -------------------------------------------------------------------------------- /docs/images/add-reduction-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-30.png -------------------------------------------------------------------------------- /docs/images/add-reduction-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-31.png -------------------------------------------------------------------------------- /docs/images/add-reduction-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-32.png -------------------------------------------------------------------------------- /docs/images/add-reduction-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-33.png -------------------------------------------------------------------------------- /docs/images/add-reduction-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-34.png -------------------------------------------------------------------------------- /docs/images/add-reduction-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-35.png -------------------------------------------------------------------------------- /docs/images/add-reduction-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-36.png -------------------------------------------------------------------------------- /docs/images/add-reduction-37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-37.png -------------------------------------------------------------------------------- /docs/images/add-reduction-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-38.png -------------------------------------------------------------------------------- /docs/images/add-reduction-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction-39.png -------------------------------------------------------------------------------- /docs/images/add-reduction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add-reduction.gif -------------------------------------------------------------------------------- /docs/images/add_reduction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add_reduction.gif -------------------------------------------------------------------------------- /docs/images/add_reduction.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/add_reduction.xcf -------------------------------------------------------------------------------- /docs/images/environment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/environment.gif -------------------------------------------------------------------------------- /docs/images/event-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/event-loop.png -------------------------------------------------------------------------------- /docs/images/event-loop.shape: -------------------------------------------------------------------------------- 1 | 2 | 3 | images - event-loop 4 | event-loop.png 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/images/match-reduction-00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-00.png -------------------------------------------------------------------------------- /docs/images/match-reduction-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-01.png -------------------------------------------------------------------------------- /docs/images/match-reduction-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-02.png -------------------------------------------------------------------------------- /docs/images/match-reduction-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-03.png -------------------------------------------------------------------------------- /docs/images/match-reduction-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-04.png -------------------------------------------------------------------------------- /docs/images/match-reduction-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-05.png -------------------------------------------------------------------------------- /docs/images/match-reduction-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-06.png -------------------------------------------------------------------------------- /docs/images/match-reduction-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-07.png -------------------------------------------------------------------------------- /docs/images/match-reduction-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-08.png -------------------------------------------------------------------------------- /docs/images/match-reduction-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-09.png -------------------------------------------------------------------------------- /docs/images/match-reduction-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-10.png -------------------------------------------------------------------------------- /docs/images/match-reduction-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-11.png -------------------------------------------------------------------------------- /docs/images/match-reduction-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-12.png -------------------------------------------------------------------------------- /docs/images/match-reduction-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-13.png -------------------------------------------------------------------------------- /docs/images/match-reduction-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-14.png -------------------------------------------------------------------------------- /docs/images/match-reduction-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-15.png -------------------------------------------------------------------------------- /docs/images/match-reduction-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-16.png -------------------------------------------------------------------------------- /docs/images/match-reduction-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-17.png -------------------------------------------------------------------------------- /docs/images/match-reduction-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-18.png -------------------------------------------------------------------------------- /docs/images/match-reduction-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-19.png -------------------------------------------------------------------------------- /docs/images/match-reduction-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-20.png -------------------------------------------------------------------------------- /docs/images/match-reduction-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-21.png -------------------------------------------------------------------------------- /docs/images/match-reduction-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-22.png -------------------------------------------------------------------------------- /docs/images/match-reduction-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-23.png -------------------------------------------------------------------------------- /docs/images/match-reduction-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-24.png -------------------------------------------------------------------------------- /docs/images/match-reduction-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-25.png -------------------------------------------------------------------------------- /docs/images/match-reduction-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-26.png -------------------------------------------------------------------------------- /docs/images/match-reduction-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-27.png -------------------------------------------------------------------------------- /docs/images/match-reduction-28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-28.png -------------------------------------------------------------------------------- /docs/images/match-reduction-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-29.png -------------------------------------------------------------------------------- /docs/images/match-reduction-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-30.png -------------------------------------------------------------------------------- /docs/images/match-reduction-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-31.png -------------------------------------------------------------------------------- /docs/images/match-reduction-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-32.png -------------------------------------------------------------------------------- /docs/images/match-reduction-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-33.png -------------------------------------------------------------------------------- /docs/images/match-reduction-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-34.png -------------------------------------------------------------------------------- /docs/images/match-reduction-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-35.png -------------------------------------------------------------------------------- /docs/images/match-reduction-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-36.png -------------------------------------------------------------------------------- /docs/images/match-reduction-37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction-37.png -------------------------------------------------------------------------------- /docs/images/match-reduction.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction.dia -------------------------------------------------------------------------------- /docs/images/match-reduction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction.gif -------------------------------------------------------------------------------- /docs/images/match-reduction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction.png -------------------------------------------------------------------------------- /docs/images/match-reduction.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/match-reduction.xcf -------------------------------------------------------------------------------- /docs/images/mechanism-of-assignment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/mechanism-of-assignment.gif -------------------------------------------------------------------------------- /docs/images/mechanism-of-assignment.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/mechanism-of-assignment.xcf -------------------------------------------------------------------------------- /docs/images/multiply_reduction-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-01.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-02.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-03.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-04.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-05.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-06.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-07.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-08.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-09.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-10.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-11.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-12.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-13.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-14.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-15.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-16.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-17.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-18.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-19.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction-20.png -------------------------------------------------------------------------------- /docs/images/multiply_reduction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction.gif -------------------------------------------------------------------------------- /docs/images/multiply_reduction.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/multiply_reduction.xcf -------------------------------------------------------------------------------- /docs/images/tarai-system-00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-00.png -------------------------------------------------------------------------------- /docs/images/tarai-system-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-01.png -------------------------------------------------------------------------------- /docs/images/tarai-system-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-02.png -------------------------------------------------------------------------------- /docs/images/tarai-system-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-03.png -------------------------------------------------------------------------------- /docs/images/tarai-system-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-04.png -------------------------------------------------------------------------------- /docs/images/tarai-system-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-05.png -------------------------------------------------------------------------------- /docs/images/tarai-system-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-06.png -------------------------------------------------------------------------------- /docs/images/tarai-system-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-07.png -------------------------------------------------------------------------------- /docs/images/tarai-system-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-08.png -------------------------------------------------------------------------------- /docs/images/tarai-system-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-09.png -------------------------------------------------------------------------------- /docs/images/tarai-system-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-10.png -------------------------------------------------------------------------------- /docs/images/tarai-system-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-11.png -------------------------------------------------------------------------------- /docs/images/tarai-system-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-12.png -------------------------------------------------------------------------------- /docs/images/tarai-system-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-13.png -------------------------------------------------------------------------------- /docs/images/tarai-system-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-14.png -------------------------------------------------------------------------------- /docs/images/tarai-system-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-15.png -------------------------------------------------------------------------------- /docs/images/tarai-system-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-16.png -------------------------------------------------------------------------------- /docs/images/tarai-system-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-17.png -------------------------------------------------------------------------------- /docs/images/tarai-system-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-18.png -------------------------------------------------------------------------------- /docs/images/tarai-system-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-19.png -------------------------------------------------------------------------------- /docs/images/tarai-system-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-20.png -------------------------------------------------------------------------------- /docs/images/tarai-system-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-21.png -------------------------------------------------------------------------------- /docs/images/tarai-system-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-22.png -------------------------------------------------------------------------------- /docs/images/tarai-system-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-23.png -------------------------------------------------------------------------------- /docs/images/tarai-system-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-24.png -------------------------------------------------------------------------------- /docs/images/tarai-system-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-25.png -------------------------------------------------------------------------------- /docs/images/tarai-system-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-26.png -------------------------------------------------------------------------------- /docs/images/tarai-system-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-27.png -------------------------------------------------------------------------------- /docs/images/tarai-system-28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-28.png -------------------------------------------------------------------------------- /docs/images/tarai-system-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-29.png -------------------------------------------------------------------------------- /docs/images/tarai-system-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-30.png -------------------------------------------------------------------------------- /docs/images/tarai-system-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-31.png -------------------------------------------------------------------------------- /docs/images/tarai-system-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system-32.png -------------------------------------------------------------------------------- /docs/images/tarai-system.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/tarai-system.gif -------------------------------------------------------------------------------- /docs/images/turing_succ.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/images/turing_succ.gif -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Functionaljs 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | View on GitHub 19 | 20 | 21 |
22 | 表紙 23 |
24 | 25 | 26 | 27 |
28 | Download this project as a .zip file 29 | Download this project as a tar.gz file 30 |
31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 |

39 | 40 |

41 | 書籍「関数型プログラミングの基礎」(リックテレコム社)のテストコードを掲載しています。 42 |

43 | 44 |

54 | 55 |

56 | 57 |

58 | 書籍で取りあげることのできなかった発展的なコードを紹介します。 59 |

60 |

65 |
66 |
67 | 68 | 69 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/aller-bold.eot -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/aller-bold.ttf -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/aller-bold.woff -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/aller-light.eot -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/aller-light.ttf -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/aller-light.woff -------------------------------------------------------------------------------- /docs/public/fonts/novecento-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/novecento-bold.eot -------------------------------------------------------------------------------- /docs/public/fonts/novecento-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/novecento-bold.ttf -------------------------------------------------------------------------------- /docs/public/fonts/novecento-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/docs/public/fonts/novecento-bold.woff -------------------------------------------------------------------------------- /docs/stylesheets/github-light.css: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 GitHub, Inc. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | .pl-c /* comment */ { 27 | color: #969896; 28 | } 29 | 30 | .pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */, 31 | .pl-s .pl-v /* string variable */ { 32 | color: #0086b3; 33 | } 34 | 35 | .pl-e /* entity */, 36 | .pl-en /* entity.name */ { 37 | color: #795da3; 38 | } 39 | 40 | .pl-s .pl-s1 /* string source */, 41 | .pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ { 42 | color: #333; 43 | } 44 | 45 | .pl-ent /* entity.name.tag */ { 46 | color: #63a35c; 47 | } 48 | 49 | .pl-k /* keyword, storage, storage.type */ { 50 | color: #a71d5d; 51 | } 52 | 53 | .pl-pds /* punctuation.definition.string, string.regexp.character-class */, 54 | .pl-s /* string */, 55 | .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */, 56 | .pl-sr /* string.regexp */, 57 | .pl-sr .pl-cce /* string.regexp constant.character.escape */, 58 | .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */, 59 | .pl-sr .pl-sre /* string.regexp source.ruby.embedded */ { 60 | color: #183691; 61 | } 62 | 63 | .pl-v /* variable */ { 64 | color: #ed6a43; 65 | } 66 | 67 | .pl-id /* invalid.deprecated */ { 68 | color: #b52a1d; 69 | } 70 | 71 | .pl-ii /* invalid.illegal */ { 72 | background-color: #b52a1d; 73 | color: #f8f8f8; 74 | } 75 | 76 | .pl-sr .pl-cce /* string.regexp constant.character.escape */ { 77 | color: #63a35c; 78 | font-weight: bold; 79 | } 80 | 81 | .pl-ml /* markup.list */ { 82 | color: #693a17; 83 | } 84 | 85 | .pl-mh /* markup.heading */, 86 | .pl-mh .pl-en /* markup.heading entity.name */, 87 | .pl-ms /* meta.separator */ { 88 | color: #1d3e81; 89 | font-weight: bold; 90 | } 91 | 92 | .pl-mq /* markup.quote */ { 93 | color: #008080; 94 | } 95 | 96 | .pl-mi /* markup.italic */ { 97 | color: #333; 98 | font-style: italic; 99 | } 100 | 101 | .pl-mb /* markup.bold */ { 102 | color: #333; 103 | font-weight: bold; 104 | } 105 | 106 | .pl-md /* markup.deleted, meta.diff.header.from-file */ { 107 | background-color: #ffecec; 108 | color: #bd2c00; 109 | } 110 | 111 | .pl-mi1 /* markup.inserted, meta.diff.header.to-file */ { 112 | background-color: #eaffea; 113 | color: #55a532; 114 | } 115 | 116 | .pl-mdr /* meta.diff.range */ { 117 | color: #795da3; 118 | font-weight: bold; 119 | } 120 | 121 | .pl-mo /* meta.output */ { 122 | color: #1d3e81; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /docs/template/docco.jst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= title %> 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | <% if (sources.length > 1) { %> 26 | 43 | <% } %> 44 |
    45 | <% if (!hasTitle) { %> 46 |
  • 47 |
    48 |

    <%= title %>

    49 |
    50 |
  • 51 | <% } %> 52 | <% for (var i=0, l=sections.length; i 53 | <% var section = sections[i]; %> 54 |
  • 55 |
    56 | <% heading = section.docsHtml.match(/^\s*<(h\d)>/) %> 57 |
    58 | 59 |
    60 | <%= section.docsHtml %> 61 |
    62 | <% if (section.codeText.replace(/\s/gm, '') != '') { %> 63 |
    <%= section.codeHtml %>
    64 | <% } %> 65 |
  • 66 | <% } %> 67 |
68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /failed/chap03/add.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('負の足し算で失敗する', (next) => { 7 | var succ = (n) => { 8 | return n + 1; 9 | }; 10 | var prev = (n) => { 11 | return n - 1; 12 | }; 13 | var add = (x,y) => { // add関数の定義 14 | if(y < 1){ 15 | return x; 16 | } else { 17 | return add(succ(x), prev(y)); // add関数の再帰呼び出し 18 | } 19 | }; 20 | /* #@range_begin(add_failed_test) */ 21 | expect( 22 | add(1,-2) 23 | ).to.eql( 24 | -1 // -1 になるべきが、-1ではない 25 | ); 26 | /* #@range_end(add_failed_test) */ 27 | next(); 28 | }); 29 | -------------------------------------------------------------------------------- /failed/chap03/multiply.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('負のかけ算で失敗する', (next) => { 7 | var succ = (n) => { 8 | return n + 1; 9 | }; 10 | var prev = (n) => { 11 | return n - 1; 12 | }; 13 | var add = (x, y) => { 14 | if(y < 1){ 15 | return x; 16 | } else { 17 | return add(succ(x),prev(y)); 18 | } 19 | }; 20 | var times = (count,fun,arg, memo) => { 21 | if(count > 1) { 22 | return times(count-1,fun,arg, fun(memo,arg)); 23 | } else { 24 | return fun(memo,arg); 25 | } 26 | }; 27 | var multiply = (n,m) => { 28 | return times(m, add, n, 0); 29 | }; 30 | var exponential = (n,m) => { 31 | return times(m, multiply, n, 1); 32 | }; 33 | /* #@range_begin(multiply_failed_test) */ 34 | expect( 35 | multiply(-2,3) 36 | ).to.eql( 37 | -6 // -2 * 3 = 6 のはず 38 | ); 39 | /* #@range_end(multiply_failed_test) */ 40 | next(); 41 | }); 42 | -------------------------------------------------------------------------------- /failed/chap03/multiply_again.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('依然、かけ算は失敗する', (next) => { 7 | var succ = (n) => { 8 | return n + 1; 9 | }; 10 | var prev = (n) => { 11 | return n - 1; 12 | }; 13 | var add = (x,y) => { 14 | if(y === 0){ 15 | return x; 16 | } else { 17 | if(y < 0){ 18 | return add(prev(x), succ(y)); // yが負の場合 19 | } else { 20 | return add(succ(x), prev(y)); // yが正の場合 21 | } 22 | } 23 | }; 24 | var times = (count,fun,arg, memo) => { 25 | if(count > 1) { 26 | return times(count-1,fun,arg, fun(memo,arg)); 27 | } else { 28 | return fun(memo,arg); 29 | } 30 | }; 31 | var exponential = (n,m) => { 32 | return times(m, multiply, n, 1); 33 | }; 34 | /* #@range_begin(multiply_failed_again_test) */ 35 | var multiply = (n,m) => { 36 | return times(m, add, n, 0); 37 | }; 38 | expect( 39 | multiply(-2,3) 40 | ).to.eql( 41 | -6 42 | ); 43 | expect( 44 | multiply(2,-3) 45 | ).to.eql( 46 | -6 47 | ); 48 | /* #@range_end(multiply_failed_again_test) */ 49 | next(); 50 | }); 51 | -------------------------------------------------------------------------------- /failed/chap04/expect_type_error.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | 5 | it('expectで型エラーを検出する', (next) => { 6 | /* #@range_begin(expect_type_error) */ 7 | var one = 1; 8 | var two = 2; 9 | var three = "three"; 10 | var four = 4; 11 | var add = (n,m) => { 12 | expect(n).to.be.a('number'); 13 | expect(m).to.be.a('number'); 14 | return n + m; 15 | }; 16 | var multiply = (n,m) => { 17 | expect(n).to.be.a('number'); 18 | expect(m).to.be.a('number'); 19 | return n * m; 20 | }; 21 | expect( 22 | multiply(add(one,two),add(three,four)) 23 | ).to.eql( 24 | 10 /* 1 * 2 + (3 + 4) = 10 を期待するが、NaNが返る */ 25 | ); 26 | /* #@range_end(expect_type_error) */ 27 | next(); 28 | }); 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /failed/chap04/type_error.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('型の違いで失敗する', (next) => { 7 | // var number = "three" 8 | // expect( 9 | // 4 * 2 + Math.abs(number) 10 | // ).to.eql( 11 | // 11 /* 4 * 2 + Math.abs(3) = 11 を期待する */ 12 | // ); 13 | /* #@range_begin(type_error) */ 14 | var one = 1; 15 | var two = 2; 16 | var three = "three"; 17 | var four = 4; 18 | expect( 19 | one * two * (three + four) 20 | ).to.eql( 21 | 11 /* 1 * 2 + (3 + 4) = 10 を期待する */ 22 | ); 23 | /* #@range_end(type_error) */ 24 | next(); 25 | }); 26 | 27 | 28 | -------------------------------------------------------------------------------- /failed/chap05/functionalIf.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('条件式の実装(不完全)', (next) => { 7 | setTimeout(next, 300); 8 | var functionalIf = (predicate, thenClause, elseClause) => { 9 | if(predicate){ 10 | return thenClause; 11 | } else { 12 | return elseClause; 13 | } 14 | }; 15 | var infiniteLoop = (_) => { 16 | return infiniteLoop(_); 17 | }; 18 | expect( 19 | functionalIf((2 < 3), 2, infiniteLoop()) 20 | ).to.eql( 21 | 2 22 | ); 23 | }); 24 | 25 | 26 | -------------------------------------------------------------------------------- /failed/chap05/statementIf.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('ifは文である', (next) => { 7 | /* ##@range_begin(if_isnot_first_class_object) */ 8 | var result = if(true) { 9 | true; 10 | } else { 11 | false; 12 | } 13 | /* ##@range_end(if_isnot_first_class_object) */ 14 | next(); 15 | }); 16 | 17 | 18 | -------------------------------------------------------------------------------- /failed/chap07/compose.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('加算と反数の合成は失敗する', (next) => { 7 | var compose = (f,g) => { 8 | return (arg) => { 9 | return f(g(arg)); 10 | }; 11 | }; 12 | /* #@range_begin(compose_opposite_add) */ 13 | var opposite = (x) => { 14 | return - x; 15 | }; 16 | var add = (x, y) => { 17 | return x + y; 18 | }; 19 | expect( 20 | compose(opposite,add)(2,3) 21 | ).to.eql( 22 | -5 // -(2 + 3) = -5 23 | ); 24 | /* #@range_end(compose_opposite_add) */ 25 | next(); 26 | }); 27 | -------------------------------------------------------------------------------- /failed/chap07/not.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var util = require('util'); 5 | 6 | it('!演算子はコンビネータではない', (next) => { 7 | var multiplyOf = (n) => { 8 | return (m) => { 9 | if(m % n === 0) { 10 | return true; 11 | } else { 12 | return false; 13 | } 14 | }; 15 | }; 16 | var even = multiplyOf(2); 17 | /* #@range_begin(not_operator_is_not_combinator) */ 18 | var not = (predicate) => { 19 | return ! predicate; // !演算子で論理を反転させる 20 | }; 21 | var odd = not(even); 22 | /* #@range_end(not_operator_is_not_combinator) */ 23 | /* #@range_begin(not_operator_is_not_combinator_test) */ 24 | expect( 25 | odd(3) 26 | ).to.eql( 27 | true 28 | ); 29 | /* #@range_end(not_operator_is_not_combinator_test) */ 30 | next(); 31 | }); 32 | -------------------------------------------------------------------------------- /functionaljs.cabal: -------------------------------------------------------------------------------- 1 | -- Initial functionaljs.cabal generated by cabal init. For further 2 | -- documentation, see http://haskell.org/cabal/users-guide/ 3 | 4 | name: functionaljs 5 | version: 0.1.0.0 6 | -- synopsis: 7 | -- description: 8 | -- license: 9 | license-file: LICENSE 10 | author: Akimichi Tatsukawa 11 | maintainer: akimichi.tatsukawa@gmail.com 12 | -- copyright: 13 | category: Testing 14 | build-type: Simple 15 | extra-source-files: README.md 16 | cabal-version: >=1.10 17 | 18 | library 19 | -- exposed-modules: 20 | -- other-modules: 21 | -- other-extensions: 22 | build-depends: base >=4.8 && <4.9 23 | hs-source-dirs: src/main/haskell 24 | default-language: Haskell2010 25 | 26 | test-suite tests 27 | ghc-options: -Wall 28 | default-extensions: OverloadedStrings 29 | type: exitcode-stdio-1.0 30 | main-is: Spec.hs 31 | -- main-is: Chap06Spec.hs 32 | -- main-is: HSpecTests.hs 33 | -- Other-Modules: HSpecTests 34 | hs-source-dirs: src/test/haskell 35 | build-depends: base, 36 | hspec >= 1.8, 37 | QuickCheck 38 | default-language: Haskell2010 -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gutil = require('gulp-util'); 3 | var mocha = require('gulp-mocha'); 4 | var coffee = require('gulp-coffee'); 5 | var foreach = require('gulp-foreach'); 6 | var tap = require('gulp-tap'); 7 | var docco = require("gulp-docco"); 8 | var ghPages = require('gulp-gh-pages'); 9 | var exec = require('child_process').exec; 10 | 11 | gulp.task('js-test', function () { 12 | gulp.src('test/*.js') 13 | .pipe(mocha({ 14 | reporter: 'spec', 15 | //reporter: 'nyan', 16 | clearRequireCache: true, 17 | ignoreLeaks: true 18 | })); 19 | }); 20 | 21 | gulp.task('ruby-test', function (cb) { 22 | exec('rspec test/', function (err, stdout, stderr) { 23 | console.log(stdout); 24 | console.log(stderr); 25 | cb(err); 26 | }); 27 | }); 28 | 29 | gulp.task('scala-test', function (cb) { 30 | exec('sbt test', function (err, stdout, stderr) { 31 | console.log(stdout); 32 | console.log(stderr); 33 | cb(err); 34 | }); 35 | }); 36 | 37 | gulp.task('haskell-test', function (cb) { 38 | exec('stack test', function (err, stdout, stderr) { 39 | console.log(stdout); 40 | exec('stack test', function (err, stdout, stderr) { 41 | cb(err); 42 | }); 43 | }); 44 | }); 45 | // Watch Files For Changes 46 | gulp.task('watch', function() { 47 | gulp.watch(['test/*.js']); 48 | }); 49 | 50 | 51 | gulp.task('doc', function() { 52 | var options = { 53 | layout: 'parallel', 54 | output: 'docs', 55 | template: 'docs/template/docco.jst', 56 | css: 'docs/css/docco.css', 57 | extension: null, 58 | languages: {}, 59 | marked: null 60 | }; 61 | return gulp.src(["./test/*.js","./lib/*.js"]) 62 | .pipe(docco(options)) 63 | .pipe(gulp.dest('./docs')); 64 | }); 65 | 66 | gulp.task('deploy', function() { 67 | return gulp.src('./docs/**/*') 68 | .pipe(ghPages()); 69 | }); 70 | 71 | gulp.task('default', ['test','doc', 'deploy']); 72 | gulp.task('test', ['js-test','scala-test', 'haskell-test','ruby-test']); 73 | -------------------------------------------------------------------------------- /lib/data.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | 5 | module.exports = { 6 | type: (data,pattern) => { 7 | if(data.type === undefined) { 8 | var typeOf = String(typeof data); 9 | return pattern[typeOf](data); 10 | // return pattern.default(data); 11 | } else { 12 | return data.type(pattern); 13 | } 14 | }, 15 | match: (data,pattern) => { 16 | return data.match(pattern); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /lib/dentaku.normal.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var Pair = require('../lib/pair.js'); 5 | var List = require('../lib/list.js'); 6 | var Parser = require('../lib/parser.js'); 7 | var I = require('../lib/evaluator.js').ID; 8 | var Env = require('../lib/env.js'); 9 | var PP = require('../lib/pprinter.js'); 10 | 11 | const Dentaku = { 12 | // expr ::= term (+ expr | e) 13 | expr: (_) => { 14 | var add = List.fromString("+"); 15 | var subtract = List.fromString("-"); 16 | var add_or_subtract_parser = Parser.alt(Parser.symbol(add))(Parser.symbol(subtract)); 17 | return Parser.flatMap(Dentaku.term())((t) => { 18 | return Parser.alt(Parser.flatMap(add_or_subtract_parser)((operator) => { 19 | if(List.isEqual(operator,add)) { 20 | return Parser.flatMap(Dentaku.expr())((e) => { 21 | return Parser.pure(I.Exp.add(t, e)); 22 | }); 23 | } else if(List.isEqual(operator, subtract)) { 24 | return Parser.flatMap(Dentaku.expr())((e) => { 25 | return Parser.pure(I.Exp.subtract(t, e)); 26 | }); 27 | } 28 | }))( 29 | Parser.pure(t) 30 | ); 31 | }); 32 | }, 33 | // term ::= factor (* term | e) 34 | term: (_) => { 35 | var multiply = List.fromString("*"); 36 | var divide = List.fromString("/"); 37 | var multiply_or_divide_parser = Parser.alt(Parser.symbol(multiply))(Parser.symbol(divide)); 38 | return Parser.flatMap(Dentaku.factor())((f) => { 39 | return Parser.alt(Parser.flatMap(multiply_or_divide_parser)((operator) => { 40 | if(List.isEqual(operator,multiply)) { 41 | return Parser.flatMap(Dentaku.expr())((e) => { 42 | return Parser.pure(I.Exp.multiply(f, e)); 43 | }); 44 | } else if(List.isEqual(operator, divide)) { 45 | return Parser.flatMap(Dentaku.expr())((e) => { 46 | return Parser.pure(I.Exp.divide(f, e)); 47 | }); 48 | } 49 | }))( 50 | Parser.pure(f) 51 | ); 52 | }); 53 | }, 54 | // factor ::= (expr) | nat 55 | factor: (_) => { 56 | var self = this; 57 | var openParen = Parser.symbol(List.fromString("(")); 58 | var closeParen = Parser.symbol(List.fromString(")")); 59 | return Parser.alt(Parser.flatMap(openParen)((_) => { 60 | return Parser.flatMap(self.expr())((e) => { 61 | return Parser.flatMap(closeParen)((_) => { 62 | return Parser.pure(e); 63 | }) 64 | }); 65 | }))( 66 | Parser.flatMap(Parser.numeric())((numeric) => { 67 | return Parser.pure(I.Exp.num(numeric)); 68 | }) 69 | ) 70 | }, 71 | evaluate: (inputString) => { 72 | var parseResult = Parser.parse(Dentaku.expr())(List.fromString(inputString)); 73 | var env = Env.empty; 74 | 75 | return parseResult.match({ 76 | empty: (_) => { 77 | return "Invalid input"; 78 | }, 79 | cons: (head, tail) => { 80 | return head.match({ 81 | cons: (ast, remainingInput) => { 82 | return remainingInput.match({ 83 | empty: (_) => { 84 | return I.evaluate(ast,env); 85 | }, 86 | cons: (head, tail) => { 87 | return PP.print(tail); 88 | // throw("Unused input " + PP.print(tail)); 89 | } 90 | }); 91 | } 92 | }) 93 | } 94 | }); 95 | 96 | } 97 | }; 98 | 99 | module.exports = Dentaku 100 | -------------------------------------------------------------------------------- /lib/env.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | // var fs = require('fs'); 5 | // var List = require('./list.js'); 6 | // var Pair = require('../lib/pair.js'); 7 | // var String = require('../lib/string.js'); 8 | // var PP = require('../lib/pprinter.js'); 9 | // var IO = require('../lib/monad.js').IO; 10 | 11 | const Env = { 12 | // ## 環境モジュール 13 | // 空の環境 14 | empty: (variable) => { 15 | return undefined; 16 | }, 17 | /* 変数名に対応する値を環境から取りだす */ 18 | // lookupEnv:: (STRING, ENV) => M[VALUE] 19 | lookup: (identifier, environment) => { 20 | return environment(identifier); 21 | }, 22 | /* 環境を拡張する */ 23 | // extendEnv:: (STRING, VALUE, ENV) => ENV 24 | extend: (identifier, value, environment) => { 25 | expect(identifier).to.a('string'); 26 | return (queryIdentifier) => { 27 | expect(queryIdentifier).to.a('string'); 28 | if(identifier === queryIdentifier) { 29 | return value; 30 | } else { 31 | return Env.lookup(queryIdentifier, environment); 32 | } 33 | }; 34 | } 35 | }; 36 | module.exports = Env 37 | -------------------------------------------------------------------------------- /lib/evaluator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var fs = require('fs'); 5 | var List = require('./list.js'); 6 | var Pair = require('../lib/pair.js'); 7 | var String = require('../lib/string.js'); 8 | var PP = require('../lib/pprinter.js'); 9 | var Env = require('../lib/env.js'); 10 | var IO = require('../lib/monad.js').IO; 11 | var ID = require('../lib/monad.js').ID; 12 | var Cont = require('../lib/monad.js').Cont; 13 | 14 | const Evaluator = { 15 | ID: { 16 | Exp: { 17 | /* 式のパターンマッチ関数 */ 18 | match : (data, pattern) => { 19 | return data(pattern); 20 | }, 21 | /* 数値の式 */ 22 | num: (value) => { 23 | return (pattern) => { 24 | return pattern.num(value); 25 | }; 26 | }, 27 | /* 変数の式 */ 28 | variable : (name) => { 29 | return (pattern) => { 30 | return pattern.variable(name); 31 | }; 32 | }, 33 | /* 関数定義の式(λ式) */ 34 | lambda: (variable, body) => { 35 | return (pattern) => { 36 | return pattern.lambda(variable, body); 37 | }; 38 | }, 39 | /* 関数適用の式 */ 40 | app: (lambda, arg) => { 41 | return (pattern) => { 42 | return pattern.app(lambda, arg); 43 | }; 44 | }, 45 | /* 足し算の式 */ 46 | add : (expL,expR) => { 47 | return (pattern) => { 48 | return pattern.add(expL, expR); 49 | }; 50 | }, 51 | /* 足し算の式 */ 52 | subtract : (expL,expR) => { 53 | return (pattern) => { 54 | return pattern.subtract(expL, expR); 55 | }; 56 | }, 57 | /* 足し算の式 */ 58 | divide : (expL,expR) => { 59 | return (pattern) => { 60 | return pattern.divide(expL, expR); 61 | }; 62 | }, 63 | /* かけ算の式 */ 64 | multiply : (expL,expR) => { 65 | return (pattern) => { 66 | return pattern.multiply(expL, expR); 67 | }; 68 | } 69 | }, 70 | evaluate: (anExp, environment) => { 71 | return Evaluator.ID.Exp.match(anExp,{ 72 | // 数値の評価 73 | num: (numericValue) => { 74 | return ID.unit(numericValue); 75 | }, 76 | // 変数の評価 77 | variable: (name) => { 78 | return ID.unit(Env.lookup(name, environment)); 79 | }, 80 | /* 関数定義(λ式)の評価 */ 81 | lambda: (variable, body) => { 82 | return Evaluator.ID.Exp.match(variable,{ 83 | variable: (name) => { 84 | return ID.unit((actualArg) => { 85 | return Evaluator.ID.evaluate(body, 86 | Env.extend(name, actualArg, environment)); 87 | }); 88 | } 89 | }); 90 | }, 91 | /* 関数適用の評価 */ 92 | app: (lambda, arg) => { 93 | return ID.flatMap(Evaluator.ID.evaluate(lambda, environment))((closure) => { 94 | return ID.flatMap(Evaluator.ID.evaluate(arg, environment))((actualArg) => { 95 | return closure(actualArg); 96 | }); 97 | }); 98 | }, 99 | // 足し算の評価 100 | add: (expL, expR) => { 101 | return ID.flatMap(Evaluator.ID.evaluate(expL, environment))((valueL) => { 102 | return ID.flatMap(Evaluator.ID.evaluate(expR, environment))((valueR) => { 103 | return ID.unit(valueL + valueR); 104 | }); 105 | }); 106 | }, 107 | // 足し算の評価 108 | subtract: (expL, expR) => { 109 | return ID.flatMap(self.evaluate(expL, environment))((valueL) => { 110 | return ID.flatMap(self.evaluate(expR, environment))((valueR) => { 111 | return ID.unit(valueL - valueR); 112 | }); 113 | }); 114 | }, 115 | // 足し算の評価 116 | multiply: (expL, expR) => { 117 | return ID.flatMap(self.evaluate(expL, environment))((valueL) => { 118 | return ID.flatMap(self.evaluate(expR, environment))((valueR) => { 119 | return ID.unit(valueL * valueR); 120 | }); 121 | }); 122 | }, 123 | // 足し算の評価 124 | divide: (expL, expR) => { 125 | return ID.flatMap(self.evaluate(expL, environment))((valueL) => { 126 | return ID.flatMap(self.evaluate(expR, environment))((valueR) => { 127 | return ID.unit(valueL / valueR); 128 | }); 129 | }); 130 | } 131 | }); 132 | } 133 | }, 134 | Cont: { 135 | Exp: { 136 | /* 式のパターンマッチ関数 */ 137 | match : (data, pattern) => { 138 | return data(pattern); 139 | }, 140 | /* 数値の式 */ 141 | num: (value) => { 142 | return (pattern) => { 143 | return pattern.num(value); 144 | }; 145 | }, 146 | /* 変数の式 */ 147 | variable : (name) => { 148 | return (pattern) => { 149 | return pattern.variable(name); 150 | }; 151 | }, 152 | /* 関数定義の式(λ式) */ 153 | lambda: (variable, body) => { 154 | return (pattern) => { 155 | return pattern.lambda(variable, body); 156 | }; 157 | }, 158 | /* 関数適用の式 */ 159 | app: (lambda, arg) => { 160 | return (pattern) => { 161 | return pattern.app(lambda, arg); 162 | }; 163 | }, 164 | /* 足し算の式 */ 165 | add : (expL,expR) => { 166 | return (pattern) => { 167 | return pattern.add(expL, expR); 168 | }; 169 | }, 170 | /* callccの式 */ 171 | callcc: (name, exp) => { 172 | return (pattern) => { 173 | return pattern.callcc(name, exp); 174 | }; 175 | } 176 | }, 177 | evaluate: (anExp, environment) => { 178 | return Evaluator.Cont.Exp.match(anExp,{ 179 | // 数値の評価 180 | num: (numericValue) => { 181 | return Cont.unit(numericValue); 182 | }, 183 | // 変数の評価 184 | variable: (name) => { 185 | return Cont.unit(Env.lookup(name, environment)); 186 | }, 187 | // 足し算の評価 188 | add: (expL, expR) => { 189 | return Cont.flatMap(Evaluator.Cont.evaluate(expL, environment))((valueL) => { 190 | return Cont.flatMap(Evaluator.Cont.evaluate(expR, environment))((valueR) => { 191 | return Cont.unit(valueL + valueR); 192 | }); 193 | }); 194 | }, 195 | /* 関数定義(λ式)の評価 */ 196 | lambda: (variable, body) => { 197 | return Evaluator.Cont.Exp.match(variable,{ 198 | variable: (name) => { 199 | return Cont.unit((actualArg) => { 200 | return Evaluator.Cont.evaluate(body, 201 | Env.extend(name, actualArg, environment)); 202 | }); 203 | } 204 | }); 205 | }, 206 | /* 関数適用の評価 */ 207 | app: (lambda, arg) => { 208 | return Cont.flatMap(Evaluator.Cont.evaluate(lambda, environment))((closure) => { 209 | return Cont.flatMap(Evaluator.Cont.evaluate(arg, environment))((actualArg) => { 210 | return closure(actualArg); 211 | }); 212 | }); 213 | }, 214 | // callcc: (name, exp) => { 215 | // return Cont.flatMap()((_) => { 216 | 217 | // }; 218 | // } 219 | }); 220 | } 221 | } 222 | }; 223 | 224 | module.exports = Evaluator 225 | -------------------------------------------------------------------------------- /lib/fileio.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var read = (path) => { 4 | return fs.readFileSync(path, 'utf8'); 5 | }; 6 | var write = (path, content) => { 7 | return fs.writeFileSync(path, content); 8 | }; 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/monad_transformer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var fs = require('fs'); 5 | var List = require('./list.js'); 6 | var ID = require('./monad.js').ID; 7 | var Maybe = require('./monad.js').Maybe; 8 | var Either = require('./monad.js').Either; 9 | 10 | module.exports = { 11 | // ## MaybeT 12 | // Maybeモナド変換子 13 | // ~~~haskell 14 | // newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) } 15 | // instance Monad m => Monad (MaybeT m) where 16 | // return = MaybeT . return . Just 17 | // x >>= f = MaybeT $ do maybe_value <- runMaybeT x 18 | // case maybe_value of 19 | // Nothing -> return Nothing 20 | // Just value -> runMaybeT $ f value 21 | // 22 | // instance Monad m => Monad (MaybeT m) where 23 | // return x = MaybeT $ return (Just x) 24 | // m >>= k = MaybeT $ do a <- runMaybeT m 25 | // case a of 26 | // Nothing -> return Nothing 27 | // Just v -> runMaybeT (k v) 28 | // fail _ = MaybeT $ return Nothing 29 | // 30 | // instance MonadTrans MaybeT where 31 | // lift m = MaybeT $ m >>= (\x -> return (Just x)) 32 | // ~~~ 33 | MaybeT: { 34 | // run : (m) => { 35 | // var self = this; 36 | // return (a) => { 37 | // return m(Maybe.unit(a)); 38 | // }; 39 | // }, 40 | fail : (_) => { 41 | return (Monad) => { 42 | return Monad.unit(Maybe.nothing()); 43 | }; 44 | }, 45 | unit : (x) => { 46 | return (Monad) => { 47 | return Monad.unit(Maybe.unit(x)); 48 | // return Maybe.unit(Monad.unit(x)); 49 | }; 50 | }, 51 | // ~~~haskell 52 | // (>>=) :: MaybeT m a -> (a -> MaybeT m b) -> MaybeT m b 53 | // ~~~ 54 | flatMap: (maybeT) => { // MaybeT m a 55 | var self = this; 56 | return (f) => { // f:: a -> MaybeT m b 57 | return (Monad) => { 58 | return Monad.flatMap(maybeT)((maybeInstance) => { 59 | return Maybe.match(maybeInstance,{ 60 | nothing: (_) => { 61 | return self.unit(Maybe.nothing())(Monad); 62 | }, 63 | just: (v) => { 64 | return f(v); 65 | // return self.unit(Maybe.unit(f(v)))(Monad); 66 | } 67 | }); 68 | }); 69 | }; 70 | }; 71 | }, 72 | // instance MonadTrans MaybeT where 73 | // lift m = MaybeT $ m >>= (\x -> return (Just x)) 74 | lift: (m) => { 75 | var self = this; 76 | return m.self().flatMap(m)((x) => { 77 | return self.unit(Maybe.unit(x)); 78 | }); 79 | } 80 | }, 81 | ErrorT: { 82 | unit: (x) => { 83 | return (Monad) => { 84 | return Monad.unit(Either.unit(x)); 85 | }; 86 | }, 87 | // ~~~haskell 88 | // (>>=) :: ErrorT m a -> (a -> ErrorT m b) -> ErrorT m b 89 | // ~~~ 90 | flatMap: (errorT) => { 91 | var self = this; 92 | return (f) => { // f:: a -> MaybeT m b 93 | return (Monad) => { 94 | return Monad.flatMap(errorT)((eitherInstance) => { 95 | return Either.match(eitherInstance,{ 96 | left: (l) => { 97 | return self.unit(Either.left(l))(Monad); 98 | }, 99 | right: (r) => { 100 | return f(r); 101 | } 102 | }); 103 | }); 104 | }; 105 | }; 106 | }, 107 | throwError: (x) => { 108 | var self = this; 109 | return self.unit(Either.left(x)); 110 | }, 111 | catchError: (m) => { 112 | var self = this; 113 | return (f) => { 114 | return self.flatMap(m)((eitherInstance) => { 115 | return Either.match(eitherInstance,{ 116 | left: (l) => { 117 | return f(l); 118 | }, 119 | right: (r) => { 120 | return self.unit(Either.right(r)); 121 | } 122 | }); 123 | }); 124 | }; 125 | } 126 | } 127 | }; 128 | -------------------------------------------------------------------------------- /lib/pair.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | type : (pattern) => { 5 | return pattern.pair(); 6 | }, 7 | // match : (data, pattern) => { 8 | // return data( pattern); 9 | // }, 10 | empty: (_) => { 11 | return { 12 | type: (pattern) => { 13 | return pattern.pair(); 14 | }, 15 | match: (pattern) => { 16 | return pattern.empty(); 17 | } 18 | }; 19 | }, 20 | // pair の代数的データ構造 21 | cons: (left, right) => { 22 | return { 23 | type: (pattern) => { 24 | return pattern.pair(); 25 | }, 26 | match: (pattern) => { 27 | return pattern.cons(left, right); 28 | } 29 | }; 30 | }, 31 | // ペアの右側を取得する 32 | right: (data) => { 33 | return data.match({ 34 | cons: (left, right) => { 35 | return right; 36 | } 37 | }); 38 | }, 39 | // ペアの左側を取得する 40 | left: (data) => { 41 | return data.match({ 42 | cons: (left, right) => { 43 | return left; 44 | } 45 | }); 46 | }, 47 | // isEqual: (pairA) => { 48 | // return (pairB) => { 49 | // }; 50 | // } 51 | }; 52 | -------------------------------------------------------------------------------- /lib/pprinter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var Data = require('./data.js'); 5 | var List = require('./list.js'); 6 | // var Pair = require('./pair.js'); 7 | 8 | const Pprinter = { 9 | print: (data) => { 10 | return Data.type(data,{ 11 | pair: () => { 12 | return data.match({ 13 | empty: () => { 14 | return "()"; 15 | }, 16 | cons: (l, r) => { 17 | var left = Pprinter.print(l); 18 | var right = Pprinter.print(r); 19 | return "(" + left + "," + right + ")"; 20 | } 21 | }); 22 | }, 23 | list: () => { 24 | return data.match({ 25 | empty: () => { 26 | return "[]"; 27 | }, 28 | cons: (head, tail) => { 29 | return "[" + List.foldr(data)("nil")((item) => { 30 | return (accumulator) => { 31 | return Pprinter.print(item) + "," + accumulator; 32 | }; 33 | }) + "]"; 34 | } 35 | }); 36 | }, 37 | number: (data) => { 38 | return data; 39 | }, 40 | string: (data) => { 41 | return data; 42 | } 43 | }); 44 | } 45 | }; 46 | module.exports = Pprinter 47 | -------------------------------------------------------------------------------- /lib/string.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var Data = require('./data.js'); 5 | var List = require('./list.js'); 6 | 7 | const Text = { 8 | head: (str) => { 9 | expect(str).to.a('string'); 10 | return str[0]; 11 | }, 12 | tail: (str) => { 13 | expect(str).to.a('string'); 14 | return str.substring(1); 15 | }, 16 | isEmpty: (str) => { 17 | return str.length === 0; 18 | }, 19 | isChar: (str) => { 20 | return str.length === 1; 21 | }, 22 | /* 文字列を文字のリストに変換する */ 23 | toList: (str) => { 24 | expect(str).to.a('string'); 25 | if(Text.isChar(str) === true) { 26 | return List.cons(str, 27 | List.empty()); 28 | } else { 29 | return List.cons(Text.head(str), 30 | Text.toList(Text.tail(str))); 31 | } 32 | } 33 | }; 34 | module.exports = Text 35 | -------------------------------------------------------------------------------- /lib/turing.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var machine = (program,tape,initState, endState) => { 4 | /* ヘッドの位置 */ 5 | var position = 0; 6 | /* 機械の状態 */ 7 | var state = initState; 8 | /* 実行する命令 */ 9 | var currentInstruction = undefined; 10 | /* 11 | 以下のwhileループにて、 12 | 現在の状態が最終状態に到達するまで命令を繰り返す 13 | */ 14 | while(state != endState) { 15 | var cell = tape[String(position)]; 16 | if (cell) 17 | currentInstruction = program[state][cell]; 18 | else 19 | currentInstruction = program[state].B; 20 | if (!currentInstruction) { 21 | return false; 22 | } else { 23 | /* テープに印字する */ 24 | tape[String(position)] = currentInstruction.write; 25 | /* ヘッドを動かす */ 26 | position += currentInstruction.move; 27 | /* 次の状態に移る */ 28 | state = currentInstruction.next; 29 | } 30 | } 31 | return tape; 32 | }; 33 | 34 | module.exports = machine; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Akimichi Tatsukawa", 3 | "name": "functionaljs", 4 | "version": "0.0.1", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/akimichi/functionaljs.git" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/akimichi/functionaljs/issues" 11 | }, 12 | "homepage": "https://github.com/akimichi/functionaljs", 13 | "license": "MIT", 14 | "scripts": { 15 | "test": "mocha --harmony -R spec" 16 | }, 17 | "dependencies": { 18 | "expect.js": "^0.3.1", 19 | "gulp": "3.9.1", 20 | "mocha": "1.21.5" 21 | }, 22 | "engines": { 23 | "node": "0.12.x" 24 | }, 25 | "devDependencies": { 26 | "docco": "^0.7.0", 27 | "gulp-coffee": "^2.3.1", 28 | "gulp-docco": "0.0.4", 29 | "gulp-foreach": "^0.1.0", 30 | "gulp-gh-pages": "^0.5.4", 31 | "gulp-jasmine": "^2.0.0", 32 | "gulp-mocha": "^2.0.0", 33 | "gulp-run": "^1.6.6", 34 | "gulp-tap": "^0.1.3", 35 | "gulp-util": "^3.0.4", 36 | "kansuu.js": "^0.3", 37 | "npm": "^2.7.3", 38 | "random-js": "^1.0.4", 39 | "run-sequence": "^1.1.5", 40 | "seedrandom": "^2.3.11", 41 | "sinon": "1.17.3", 42 | "sleep-async": "^1.0.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /project/FunctionalJs.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | import sbt.Keys._ 3 | 4 | import java.io.{PrintWriter} 5 | 6 | object FunctionalJs extends Build { 7 | lazy val functionalJsProject = Project( 8 | id = "functional-js", 9 | base = file("."), 10 | settings = Project.defaultSettings ++ Seq( 11 | name := "Functional Book Test Project", 12 | organization := "akimichi.tatsukawa", 13 | version := "0.1-SNAPSHOT", 14 | // scalaVersion := "2.12", 15 | // scalaVersion := "2.10", 16 | scalaVersion := "2.11.1", 17 | // scalaVersion := "2.11.7", 18 | // scalaVersion := "2.9.1", 19 | 20 | // add other settings here 21 | /** scalacOptions 22 | * -unchecked 23 | * -deprecation 24 | * -Xprint:typer 暗黙変換の情報を表示する 25 | * -Xcheckinit 継承関係における予測しがたいスーパークラスの初期化をチェックする 26 | */ 27 | // scalacOptions ++= Seq("-unchecked", "-deprecation","-Xcheckinit", "-P:continuations:enable"), 28 | scalacOptions ++= Seq("-unchecked", "-deprecation","-Xcheckinit"), 29 | scalacOptions in Test ++= Seq("-Yrangepos"), 30 | // scalacOptions ++= Seq("-unchecked", "-deprecation","-Xcheckinit"), 31 | resolvers ++= Seq("Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases", 32 | "snapshots" at "http://oss.sonatype.org/content/repositories/snapshots", 33 | "releases" at "http://oss.sonatype.org/content/repositories/releases", 34 | "Maven Repository" at "http://repo1.maven.org/maven2/", 35 | // "Artima Maven Repository" at "http://repo.artima.com/releases", 36 | "repo.novus rels" at "http://repo.novus.com/releases/", 37 | "repo.novus snaps" at "http://repo.novus.com/snapshots/"), 38 | libraryDependencies ++= Seq ( 39 | "junit" % "junit" % "4.10" % "test", 40 | "com.novocode" % "junit-interface" % "0.10-M2" % "test", 41 | "org.scalactic" %% "scalactic" % "2.2.6", 42 | "org.scalatest" %% "scalatest" % "2.2.6" % "test", 43 | // "org.scalatest" %% "scalatest" % "2.0" % "test", 44 | // "org.scalatest" %% "scalatest" % "1.7.1" % "test", 45 | "org.scalacheck" %% "scalacheck" % "1.12.5" % "test", 46 | "org.specs2" %% "specs2-core" % "3.7.2" % "test" 47 | // "org.specs2" %% "specs2" % "1.12.1" % "test" 48 | ) 49 | ) 50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.11 2 | // sbt.version=0.11.3 3 | -------------------------------------------------------------------------------- /src/main/haskell/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akimichi/functionaljs/ac0d6eb9f368f884b22b681182883957e56fce60/src/main/haskell/.gitkeep -------------------------------------------------------------------------------- /src/test/haskell/Chap06Spec.hs: -------------------------------------------------------------------------------- 1 | module Chap06Spec where 2 | 3 | import Test.Hspec 4 | 5 | -- #@range_begin(left_and_infiniteLoop_in_haskell) 6 | left x y = x 7 | infiniteLoop () = infiniteLoop () 8 | -- #@range_end(left_and_infiniteLoop_in_haskell) 9 | 10 | -- main :: IO () 11 | -- main = hspec $ do 12 | main :: IO () 13 | main = hspec spec 14 | 15 | spec :: Spec 16 | spec = do 17 | -- #@range_begin(lazy_evaluation_in_haskell) 18 | describe "chap06" $ do 19 | it "遅延評価では無限ループに陥いらずに答えを返す" $ do 20 | left 1 (infiniteLoop()) `shouldBe` 1 21 | -- #@range_end(lazy_evaluation_in_haskell) 22 | -------------------------------------------------------------------------------- /src/test/haskell/HSpecTests.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | -- import Haq 4 | import Test.Hspec 5 | 6 | main :: IO () 7 | main = hspec $ do 8 | 9 | describe "Validate haqify function" $ do 10 | it "haqify is supposed to prefix Haq! to things" $ do 11 | True `shouldBe` True 12 | 13 | -------------------------------------------------------------------------------- /src/test/haskell/Haq.hs: -------------------------------------------------------------------------------- 1 | import System.Environment 2 | 3 | -- | 'main' runs the main program 4 | main :: IO () 5 | main = getArgs >>= print . haqify . head 6 | 7 | haqify s = "Haq! " ++ s 8 | -------------------------------------------------------------------------------- /src/test/haskell/QCheckSpec.hs: -------------------------------------------------------------------------------- 1 | module QCheckSpec where 2 | 3 | import Test.Hspec 4 | import Test.QuickCheck 5 | 6 | -- `main` is here so that this module can be run from GHCi on its own. It is 7 | -- not needed for automatic spec discovery. 8 | main :: IO () 9 | main = hspec spec 10 | 11 | spec :: Spec 12 | spec = do 13 | describe "read" $ do 14 | it "is inverse to show" $ property $ 15 | \x -> (read . show) x == (x :: Int) 16 | -------------------------------------------------------------------------------- /src/test/haskell/Spec.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -F -pgmF hspec-discover #-} 2 | -------------------------------------------------------------------------------- /src/test/scala/chap02.check.scala: -------------------------------------------------------------------------------- 1 | import org.scalacheck.Properties 2 | import org.scalacheck.Prop.forAll 3 | import org.scalacheck.Prop.{forAll, BooleanOperators} 4 | import scala.annotation.tailrec 5 | import org.scalacheck.Gen 6 | 7 | object MathSpecification extends Properties("Math") { 8 | def factorial(n: Int): Long = { 9 | @tailrec 10 | def fact(n: Int, accumulator: Int): Long = { 11 | if (n <= 1) accumulator 12 | else fact(n - 1, n * accumulator) 13 | } 14 | fact(n, 1) 15 | } 16 | // def factorial(n: Int): Int = { 17 | // @tailrec def factorialAcc(acc: Int, n: Int): Int = { 18 | // if (n <= 1) acc 19 | // else factorialAcc(n * acc, n - 1) 20 | // } 21 | // factorialAcc(1, n) 22 | // } 23 | // property("factorial") = forAll( { (n: Int) => 24 | // (n > 0 && n < 10000) ==> (factorial(n) == n * factorial(n-1)) 25 | // }) 26 | def perm(n:Int, r:Int) = { 27 | factorial(n) / factorial(n-r) 28 | } 29 | def comb(n:Int, r:Int) = { 30 | perm(n,r) / factorial(r) 31 | } 32 | // property("comb") = forAll( { (n: Int, r: Int) => 33 | // (n > 1 && r > 1 && n > r) ==> (comb(n,r) == comb(n, n-r)) 34 | // }) 35 | // property("comb") = forAll((Gen.choose(1, 10000),Gen.choose(1, 10000)) { (n: Int, r: Int) => 36 | // comb(n,r) == comb(n, n-r) 37 | // // (n > 1 && r > 1 && n > r) ==> (comb(n,r) == comb(n, n-r)) 38 | // }) 39 | def succ(n:Int) = { 40 | n + 1 41 | } 42 | /* #@range_begin(check_succ) */ 43 | property("succ") = forAll( (x:Int) => // 変数xは整数である 44 | (x >= 0) ==> // xは0以上であるとする事前条件を設定する 45 | (succ(0) + succ(x) == succ(succ(x))) 46 | ) 47 | /* #@range_end(check_succ) */ 48 | /* #@range_begin(check_multiplication) */ 49 | property("multiply") = forAll( (x:Int) => 50 | x+x == 2*x 51 | ) 52 | /* #@range_end(check_multiplication) */ 53 | } 54 | 55 | object StringSpecification extends Properties("String") { 56 | 57 | property("startsWith") = forAll { (a: String, b: String) => 58 | (a+b).startsWith(a) 59 | } 60 | 61 | property("concatenate") = forAll { (a: String, b: String) => 62 | (a+b).length >= a.length && (a+b).length >= b.length 63 | } 64 | 65 | property("substring") = forAll { (a: String, b: String, c: String) => 66 | (a+b+c).substring(a.length, a.length+b.length) == b 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/scala/chap02.spec.scala: -------------------------------------------------------------------------------- 1 | import org.junit.runner.RunWith 2 | import org.scalatest.junit.JUnitRunner 3 | import org.scalatest.FunSuite 4 | import org.scalatest.matchers.ShouldMatchers 5 | import org.scalatest.{ FunSpec, BeforeAndAfterAll, BeforeAndAfterEach, BeforeAndAfter } 6 | 7 | 8 | class Chap02Spec extends FunSpec with ShouldMatchers { 9 | describe("テストが容易である"){ 10 | describe("銀行口座の例"){ 11 | // ##@range_begin(account_class) 12 | // 銀行口座のクラス 13 | class Account(amount: Int) { 14 | // 口座の残高を可変な状態として作る 15 | var balance = amount 16 | // 口座にお金を預ける関数 17 | def deposit(amount: Int):Int = { 18 | // 残高を更新する 19 | balance = balance + amount 20 | return balance 21 | } 22 | // 口座からお金を引き出す関数 23 | def withdraw(amount: Int):Int = { 24 | // 残高を更新する 25 | balance = balance - amount 26 | return balance 27 | } 28 | } 29 | // ##@range_end(account_class) 30 | it("取り引きの例"){ 31 | /************* テスト *************/ 32 | // ##@range_begin(account_with_state_test) 33 | // 口座を1000円で開設する 34 | val theAccount = new Account(1000) 35 | theAccount.balance should equal(1000) 36 | // 口座から200円を引き出す 37 | theAccount.withdraw(200) 38 | // 残高は800円となる 39 | theAccount.balance should equal(800) 40 | // ##@range_end(account_with_state_test) 41 | } 42 | it("貧乏人の例"){ 43 | /************* テスト *************/ 44 | // ##@range_begin(poormansAccount_test) 45 | val poormansAccount = new Account(1000) // 口座を1000円で開設する 46 | poormansAccount.balance should equal(1000) 47 | poormansAccount.withdraw(200) // 口座から200円を引き出す 48 | poormansAccount.balance should equal(800) // 残高は800円となる 49 | // ##@range_end(poormansAccount_test) 50 | } 51 | it("金持ちの例"){ 52 | /************* テスト *************/ 53 | // ##@range_begin(richmansAccount_test) 54 | val richmansAccount = new Account(100000) // 口座を100万円で開設する 55 | richmansAccount.balance should equal(100000) 56 | richmansAccount.withdraw(20000) // 口座から20万円を引き出す 57 | richmansAccount.balance should equal(80000) // 残高は80円となる 58 | // ##@range_end(richmansAccount_test) 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/scala/chap05.spec.scala: -------------------------------------------------------------------------------- 1 | import org.junit.runner.RunWith 2 | import org.scalatest.junit.JUnitRunner 3 | import org.scalatest.FunSuite 4 | import org.scalatest.matchers.ShouldMatchers 5 | import org.scalatest.{ FunSpec, BeforeAndAfterAll, BeforeAndAfterEach, BeforeAndAfter } 6 | 7 | 8 | class Chap05Spec extends FunSpec with ShouldMatchers { 9 | describe("ifについて"){ 10 | it("even"){ 11 | // ##@range_begin(if_as_expression_in_scala) 12 | def even(number:Int): Boolean = { 13 | return if(number % 2 == 0) // ifは式なのでその結果を返す 14 | true 15 | else 16 | false 17 | } 18 | /************* テスト *************/ 19 | even(2) should equal(true) 20 | even(3) should equal(false) 21 | // ##@range_end(if_as_expression_in_scala) 22 | } 23 | } 24 | describe("switch文"){ 25 | it("通貨の例"){ 26 | // ##@range_begin(pattern_match_in_scala) 27 | trait Currency 28 | case class Yen(amount: Int) extends Currency 29 | case class Dollar(amount: Int) extends Currency 30 | 31 | def toS(currency:Currency):String = 32 | // 通貨の型でマッチさせる 33 | currency match { 34 | // Yenにマッチする場合 35 | case Yen(amount) => { // 変数amountには日本円の値が入る 36 | "%s yen".format(amount) 37 | } 38 | // Dollarにマッチする場合 39 | case Dollar(amount) => { // 変数amountにはドルの値が入る 40 | "%s dollar".format(amount) 41 | } 42 | } 43 | /************* テスト *************/ 44 | val yen = Yen(1000) 45 | toS(yen) should equal("1000 yen") 46 | // ##@range_end(pattern_match_in_scala) 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | # For more information, see: https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md 2 | 3 | # Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2) 4 | resolver: lts-4.1 5 | 6 | # Local packages, usually specified by relative directory name 7 | packages: 8 | - '.' 9 | 10 | # Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3) 11 | extra-deps: [] 12 | 13 | # Override default flag values for local packages and extra-deps 14 | flags: {} 15 | 16 | # Extra package databases containing global packages 17 | extra-package-dbs: [] 18 | 19 | # Control whether we use the GHC we find on the path 20 | # system-ghc: true 21 | 22 | # Require a specific version of stack, using version ranges 23 | # require-stack-version: -any # Default 24 | # require-stack-version: >= 1.0.0 25 | 26 | # Override the architecture used by stack, especially useful on Windows 27 | # arch: i386 28 | # arch: x86_64 29 | 30 | # Extra directories used by stack for building 31 | # extra-include-dirs: [/path/to/dir] 32 | # extra-lib-dirs: [/path/to/dir] 33 | -------------------------------------------------------------------------------- /test/chap02_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | describe '四則演算' do 4 | it '1 + 2 = 3' do 5 | expect(1 + 2).to eq 3 6 | end 7 | end 8 | 9 | describe '第2章' do 10 | it '関数のテスト' do 11 | adder = lambda do |n| 12 | lambda do |m| 13 | n + m 14 | end 15 | end 16 | expect( 17 | adder[1][2] 18 | ).to eq 3 19 | end 20 | it 'オブジェクト指向プログラミングのテスト' do 21 | class User 22 | @@count = 0 23 | def initialize(name) 24 | @name = name 25 | @@count = @@count + 1 26 | end 27 | attr_accessor :name 28 | def self.count 29 | @@count 30 | end 31 | end 32 | expect(User.count).to eq 0 33 | user_a = User.new("a") 34 | expect(User.count).to eq 1 35 | user_b = User.new("b") 36 | expect(User.count).to eq 2 37 | 38 | class Player < User 39 | @score = 0 40 | def win 41 | @score = @score + 1 42 | end 43 | attr_accessor :score 44 | end 45 | end 46 | describe '銀行口座の例' do 47 | #@range_begin(account_with_implicit_state) 48 | class Account # 銀行口座のクラス 49 | def initialize(balance) # 銀行口座のインスタンスを作る 50 | @balance = balance 51 | end 52 | attr_accessor :balance 53 | def deposit(amount) # 口座にお金を預ける 54 | @balance = @balance + amount 55 | end 56 | def withdraw(amount) # 口座からお金を引き出す 57 | @balance = @balance - amount 58 | end 59 | end 60 | #@range_end(account_with_implicit_state) 61 | it '浪費家の例' do 62 | #@range_begin(account_waster_test) 63 | account = Account.new(100) 64 | expect(account.balance).to eq 100 65 | account.withdraw(60) 66 | expect(account.balance).to eq 40 67 | account.withdraw(60) 68 | expect(account.balance).to eq -20 69 | #@range_end(account_waster_test) 70 | end 71 | it '吝嗇家の例' do 72 | account = Account.new(100) 73 | expect(account.balance).to eq 100 74 | account.deposit(20) 75 | expect(account.balance).to eq 120 76 | account.withdraw(40) 77 | expect(account.balance).to eq 80 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /test/chap03.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | // 第3章 心の準備 5 | // ======== 6 | 7 | // ## 小目次 8 | // 16 | 17 | 18 | var expect = require('expect.js'); 19 | 20 | // ## 3.1
DRY原則
21 | // 22 | // > 参考資料: [DRY原則の利用: コードの重複と密結合の間](https://www.infoq.com/jp/news/2012/05/DRY-code-duplication-coupling) 23 | describe('DRY原則', () => { 24 | var add = (x, y) => { 25 | return x + y; 26 | }; 27 | // **リスト3.1** 冗長なコード 28 | it('冗長なコード', (next) => { 29 | /* #@range_begin(redundant_code) */ 30 | var timesForMultiply = (count, arg, memo) => { 31 | if(count > 1) { 32 | return timesForMultiply(count-1, arg, arg + memo); 33 | } else { 34 | return arg + memo; 35 | } 36 | }; 37 | var multiply = (n, m) => { 38 | return timesForMultiply(n, m, 0); 39 | }; 40 | var timesForExponential = (count, arg, memo) => { 41 | if(count > 1) { 42 | return timesForExponential(count-1, arg, arg * memo); 43 | } else { 44 | return arg * memo; 45 | } 46 | }; 47 | var exponential = (n, m) => { 48 | return timesForExponential(m, n, 1); 49 | }; 50 | /* #@range_end(redundant_code) */ 51 | expect( 52 | multiply(2, 3) 53 | ).to.eql( 54 | 6 55 | ); 56 | expect( 57 | exponential(2, 3) 58 | ).to.eql( 59 | 8 60 | ); 61 | next(); 62 | }); 63 | it('DRYを適用する', (next) => { 64 | // **リスト3.3** DRYなtimes関数 65 | /* #@range_begin(dry_times) */ 66 | var times = (count, arg, memo, fun) => { // 引数funを追加 67 | if(count > 1) { 68 | return times(count-1, arg, fun(arg,memo), fun); 69 | } else { 70 | return fun(arg,memo); 71 | } 72 | }; 73 | /* #@range_end(dry_times) */ 74 | 75 | // **リスト3.4** DRYなかけ算とべき乗 76 | /* #@range_begin(dry_functions) */ 77 | var add = (n, m) => { 78 | return n + m; 79 | }; 80 | /* times関数を利用してmultiply関数を定義する */ 81 | var multiply = (n, m) => { 82 | return times(m, n, 0, add); 83 | }; 84 | /* times関数を利用してexponential関数を定義する */ 85 | var exponential = (n, m) => { 86 | return times(m, n, 1, multiply); 87 | }; 88 | /* #@range_end(dry_functions) */ 89 | expect( 90 | multiply(2, 3) 91 | ).to.eql( 92 | 6 93 | ); 94 | expect( 95 | exponential(2, 3) 96 | ).to.eql( 97 | 8 98 | ); 99 | expect( 100 | multiply(-2, 3) 101 | ).to.eql( 102 | -6 103 | ); 104 | next(); 105 | }); 106 | }); 107 | 108 | // ## 3.2
抽象化への指向
109 | describe('抽象化への指向', () => { 110 | // **リスト3.5** 関数という抽象化 111 | it('関数という抽象化', (next) => { 112 | /* #@range_begin(function_abstraction_example) */ 113 | var succ = (n) => { 114 | return n + 1; 115 | }; 116 | /* #@range_end(function_abstraction_example) */ 117 | next(); 118 | }); 119 | describe('高階関数による抽象化', () => { 120 | var anArray = [2,3,5,7,11,13]; 121 | 122 | // **リスト3.6** for文によるsum関数 123 | it('for文によるsum関数', (next) => { 124 | /* #@range_begin(sum_for) */ 125 | var anArray = [2,3,5,7]; 126 | var sum = (array) => { 127 | var result = 0; 128 | for(var index = 0; index < array.length; index++){ 129 | result = result + array[index]; 130 | } 131 | return result; 132 | }; 133 | sum(anArray); 134 | /* #@range_end(sum_for) */ 135 | expect( 136 | sum(anArray) 137 | ).to.eql( 138 | 17 139 | ); 140 | next(); 141 | }); 142 | // **リスト3.7** forEachによるsum関数 143 | it('forEachによるsum関数', (next) => { 144 | /* #@range_begin(sum_forEach) */ 145 | var sum = (array) => { 146 | /* 結果を格納する変数result */ 147 | var result = 0; 148 | array.forEach((item) => { 149 | result = result + item; 150 | }); 151 | return result; 152 | }; 153 | /* #@range_end(sum_forEach) */ 154 | expect( 155 | sum(anArray) 156 | ).to.eql( 157 | 41 158 | ); 159 | next(); 160 | }); 161 | // **リスト3.8** reduceによるsum関数 162 | it('reduceによるsum関数', (next) => { 163 | /* #@range_begin(sum_reduce) */ 164 | var sum = (array) => { 165 | return array.reduce((x, y) => { 166 | return x + y; 167 | }); 168 | }; 169 | /* #@range_end(sum_reduce) */ 170 | expect( 171 | sum(anArray) 172 | ).to.eql( 173 | 41 174 | ); 175 | next(); 176 | }); 177 | }); 178 | }); 179 | 180 | // ## 3.3
セマンティクスを意識する
181 | describe('セマンティクスを意識する', () => { 182 | // **リスト3.9** 環境という仕組み 183 | it('環境という仕組み', (next) => { 184 | /* merge関数は、引数にわたされた2つのオブジェクトを併合する */ 185 | var merge = (obj1, obj2) => { 186 | var mergedObject = {}; 187 | for (var attrname in obj1) { mergedObject[attrname] = obj1[attrname]; } 188 | for (var attrname in obj2) { mergedObject[attrname] = obj2[attrname]; } 189 | return mergedObject; 190 | }; 191 | //
192 | //
empty
193 | //
空の環境
194 | //
extendEnv
195 | //
環境に変数と値の対応を与えて、辞書を拡張する
196 | //
lookupEnv
197 | //
変数を指定して、環境に記憶されている値を取り出す
198 | //
199 | /* #@range_begin(environment_example) */ 200 | /* 空の環境 */ 201 | var emptyEnv = {}; 202 | /* 環境を拡張する */ 203 | var extendEnv = (binding, oldEnv) => { 204 | /* merge(obj1, obj2) は 205 | obj1とobj2のオブジェクトをマージする関数のこと */ 206 | return merge(binding, oldEnv); 207 | }; 208 | /* 変数名に対応する値を環境から取り出す */ 209 | var lookupEnv = (name, env) => { 210 | return env[name]; 211 | }; 212 | /* #@range_end(environment_example) */ 213 | // ~~~ 214 | // var a = 1; 215 | // var b = 3; 216 | // b 217 | // ~~~ 218 | expect(((_) => { 219 | // **リスト3.11** リスト 3.10のセマンティクス 220 | /* #@range_begin(environment_example_usage) */ 221 | /* 空の辞書を作成する */ 222 | var initEnv = emptyEnv; 223 | /* var a = 1 を実行して、辞書を拡張する */ 224 | var firstEnv = extendEnv({"a": 1}, initEnv); 225 | /* var b = 3 を実行して、辞書を拡張する */ 226 | var secondEnv = extendEnv({"b": 3}, firstEnv); 227 | /* 辞書から b の値を参照する */ 228 | lookupEnv("b", secondEnv); 229 | /* #@range_end(environment_example_usage) */ 230 | return lookupEnv("b", secondEnv); 231 | })()).to.eql( 232 | 3 233 | ); 234 | next(); 235 | }); 236 | }); 237 | 238 | // ## 3.4
テストに親しむ
239 | describe('テストに親しむ', () => { 240 | // ### 単体テストの仕組み 241 | // > 参考資料: [単体テスト](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%93%E3%83%86%E3%82%B9%E3%83%88) 242 | describe('単体テストの仕組み', () => { 243 | // **リスト3.12** アサート関数の例 244 | // 245 | // assertライブラリを使う場合 246 | it('assertによる表明', (next) => { 247 | /* #@range_begin(assert_assertion) */ 248 | var assert = require("assert"); 249 | assert.equal(1 + 2, 3); 250 | /* #@range_end(assert_assertion) */ 251 | next(); 252 | }); 253 | // expectライブラリを使う場合 254 | // > 参考資料: https://github.com/Automattic/expect.js 255 | it('expectによる表明', (next) => { 256 | /* #@range_begin(expect_assertion) */ 257 | var expect = require('expect.js'); 258 | expect( 259 | 1 + 2 260 | ).to.eql( 261 | 3 262 | ); 263 | /* #@range_end(expect_assertion) */ 264 | next(); 265 | }); 266 | }); 267 | }); 268 | 269 | // [目次に戻る](index.html) [次章に移る](chap04.spec.html) 270 | -------------------------------------------------------------------------------- /test/chap05.spec.coffee: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | expect = require('expect.js') 4 | util = require('util') 5 | 6 | describe '制御構造', -> 7 | it 'even', (next) -> 8 | ##@range_begin(if_as_expression) 9 | even = (n) -> 10 | if (n % 2) is 0 11 | true 12 | else 13 | false 14 | ##@range_end(if_as_expression) 15 | expect(even(2)).to.be true 16 | expect(even(3)).to.be false 17 | next() 18 | -------------------------------------------------------------------------------- /test/chap05.spec.scala: -------------------------------------------------------------------------------- 1 | trait Currency 2 | case class Yen(amount: Int) extends Currency 3 | case class Dollar(amount: Int) extends Currency 4 | 5 | def toS(currency:Currency):String = currency match { // 通貨の型でマッチさせる 6 | case Yen(amount) => { 7 | "%s yen".format(amount) // 変数amountには日本円の値が入る 8 | } 9 | case Dollar(amount) => { 10 | "%s dollar".format(amount) // 変数amountにはドルの値が入る 11 | } 12 | } 13 | val yen = Yen(1000) 14 | toS(yen) should equal("1000 yen") 15 | -------------------------------------------------------------------------------- /test/data.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var Pair = require('../lib/pair.js'); 5 | var List = require('../lib/list.js'); 6 | var Data = require('../lib/data.js'); 7 | 8 | 9 | describe('Data', () => { 10 | var tuple = Pair.cons(1,2); 11 | it("Data#type", (next) => { 12 | Data.type(tuple,{ 13 | pair: (_) => { 14 | expect(true).to.eql(true); 15 | } 16 | }); 17 | Data.type(1,{ 18 | pair: (_) => { 19 | expect().fail(); 20 | }, 21 | number: (value) => { 22 | expect(value).to.eql(1); 23 | } 24 | }); 25 | next(); 26 | }); 27 | describe('Data#match', () => { 28 | it("Data#match(pair)", (next) => { 29 | Data.match(tuple,{ 30 | cons: (x,y) => { 31 | expect(x).to.eql(1); 32 | } 33 | }); 34 | next(); 35 | }); 36 | it("Data#match(list)", (next) => { 37 | var list = List.cons(1,List.empty()); 38 | Data.match(list,{ 39 | cons: (x,y) => { 40 | expect(x).to.eql(1); 41 | } 42 | }); 43 | next(); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/dentaku.normal.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var List = require('../lib/list.js'); 5 | var Pair = require('../lib/pair.js'); 6 | var Data = require('../lib/data.js'); 7 | var PP = require('../lib/pprinter.js'); 8 | var Parser = require('../lib/parser.js'); 9 | var Dentaku = require('../lib/dentaku.normal.js'); 10 | 11 | describe('dentaku.normal', () => { 12 | it("evaluate", (next) => { 13 | expect( 14 | Dentaku.evaluate("123") 15 | ).to.eql( 16 | 123 17 | ); 18 | expect( 19 | Dentaku.evaluate("1 + 2") 20 | ).to.eql( 21 | 3 22 | ); 23 | expect( 24 | Dentaku.evaluate("2 - 1") 25 | ).to.eql( 26 | 1 27 | ); 28 | expect( 29 | Dentaku.evaluate("1.2 * 2") 30 | ).to.eql( 31 | 2.4 32 | ); 33 | expect( 34 | Dentaku.evaluate("3.9 / 3") 35 | ).to.eql( 36 | 1.3 37 | ); 38 | next(); 39 | }); 40 | // describe('parser', () => { 41 | // it("expr", (next) => { 42 | // expect( 43 | // PP.print(Parser.parse(Dentaku.expr())(List.fromString("123"))) 44 | // // PP.print(Parser.parse(Dentaku.expr())(List.fromString("123"))) 45 | // ).to.eql( 46 | // '[(123,[]),nil]' 47 | // ); 48 | // next(); 49 | // }); 50 | // it("factor", (next) => { 51 | // expect( 52 | // PP.print(Parser.parse(Dentaku.factor())(List.fromString("123"))) 53 | // ).to.eql( 54 | // '[(123,[]),nil]' 55 | // ); 56 | // next(); 57 | // }); 58 | // it("term", (next) => { 59 | // expect( 60 | // PP.print(Parser.parse(Dentaku.term())(List.fromString("1 * 2"))) 61 | // ).to.eql( 62 | // '[(2,[]),nil]' 63 | // ); 64 | // next(); 65 | // }); 66 | // }); 67 | }); 68 | 69 | -------------------------------------------------------------------------------- /test/evaluator.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var Env = require('../lib/env.js'); 5 | var emptyEnv = Env.empty; 6 | 7 | // ## IDモナドによる評価器のテスト 8 | describe('IDモナドによる評価器のテスト', () => { 9 | // 恒等モナドをIとして読み込む 10 | var I = require('../lib/evaluator.js').ID; 11 | 12 | it('数値を評価する', (next) => { 13 | expect( 14 | I.evaluate(I.Exp.num(2), emptyEnv) 15 | ).to.eql( 16 | 2 17 | ); 18 | next(); 19 | }); 20 | it('変数の評価のテスト', (next) => { 21 | /* 変数xを1に対応させた環境を作る */ 22 | var newEnv = Env.extend("x", 1, emptyEnv); 23 | expect( 24 | I.evaluate(I.Exp.variable("x"), newEnv) 25 | ).to.eql( 26 | 1 27 | ); 28 | expect( 29 | I.evaluate(I.Exp.variable("y"), newEnv) 30 | ).to.be( 31 | undefined 32 | ); 33 | next(); 34 | }); 35 | describe('演算のテスト', () => { 36 | it('足し算の評価のテスト', (next) => { 37 | /* add(1,2) */ 38 | var addition = I.Exp.add(I.Exp.num(1),I.Exp.num(2)); 39 | expect( 40 | I.evaluate(addition, emptyEnv) 41 | ).to.eql( 42 | 3 43 | ); 44 | next(); 45 | }); 46 | it('かけ算の評価のテスト', (next) => { 47 | /* multiply(1,2) */ 48 | var multiplication = I.Exp.add(I.Exp.num(2),I.Exp.num(3)); 49 | expect( 50 | I.evaluate(multiplication, emptyEnv) 51 | ).to.eql( 52 | 5 53 | ); 54 | next(); 55 | }); 56 | }); 57 | describe('関数を評価する', () => { 58 | it('identity関数を評価する', (next) => { 59 | var identity = I.Exp.app(I.Exp.lambda(I.Exp.variable("x"), 60 | I.Exp.variable("x")), 61 | I.Exp.num(2)); 62 | expect( 63 | I.evaluate(identity, emptyEnv) 64 | ).to.eql( 65 | 2 66 | ); 67 | next(); 68 | }); 69 | it('カリー化関数の評価', (next) => { 70 | // ~~~js 71 | // ((n) => { 72 | // return (m) => { 73 | // return n + m; 74 | // }; 75 | // })(2)(3) 76 | // ~~~ 77 | var expression = I.Exp.app( 78 | I.Exp.app( 79 | I.Exp.lambda(I.Exp.variable("n"), 80 | I.Exp.lambda(I.Exp.variable("m"), 81 | I.Exp.add( 82 | I.Exp.variable("n"),I.Exp.variable("m")))), 83 | I.Exp.num(2)), 84 | I.Exp.num(3)); 85 | expect( 86 | I.evaluate(expression, emptyEnv) 87 | ).to.eql( 88 | 5 89 | ); 90 | next(); 91 | }); 92 | }); 93 | }); 94 | 95 | // ## Contモナドによる継続渡し評価器のテスト 96 | describe('Contモナドによる評価器', () => { 97 | var K = require('../lib/evaluator.js').Cont; 98 | var identity = (any) => { 99 | return any; 100 | }; 101 | it('数値を評価する', (next) => { 102 | expect( 103 | K.evaluate(K.Exp.num(2), emptyEnv)(identity) 104 | ).to.eql( 105 | 2 106 | ); 107 | next(); 108 | }); 109 | it('変数を評価する', (next) => { 110 | /* 変数xを1に対応させた環境を作る */ 111 | var newEnv = Env.extend("x", 1, emptyEnv); 112 | expect( 113 | K.evaluate(K.Exp.variable("x"), newEnv)(identity) 114 | ).to.eql( 115 | 1 116 | ); 117 | expect( 118 | K.evaluate(K.Exp.variable("y"), newEnv)(identity) 119 | ).to.be( 120 | undefined 121 | ); 122 | next(); 123 | }); 124 | it('足し算の評価のテスト', (next) => { 125 | /* add(1,2) */ 126 | var addition = K.Exp.add(K.Exp.num(1),K.Exp.num(2)); 127 | expect( 128 | K.evaluate(addition, emptyEnv)(identity) 129 | ).to.eql( 130 | 3 131 | ); 132 | next(); 133 | }); 134 | describe('関数を評価する', () => { 135 | it('identity関数を評価する', (next) => { 136 | var id = K.Exp.lambda(K.Exp.variable("x"), 137 | K.Exp.variable("x")); 138 | expect( 139 | K.evaluate(K.Exp.app(id,K.Exp.num(1)), emptyEnv)(identity) 140 | ).to.eql( 141 | 1 142 | ); 143 | next(); 144 | }); 145 | it('カリー化関数の評価', (next) => { 146 | var expression = K.Exp.app( 147 | K.Exp.app( 148 | K.Exp.lambda(K.Exp.variable("n"), 149 | K.Exp.lambda(K.Exp.variable("m"), 150 | K.Exp.add( 151 | K.Exp.variable("n"),K.Exp.variable("m")))), 152 | K.Exp.num(2)), 153 | K.Exp.num(3)); 154 | expect( 155 | K.evaluate(expression, emptyEnv)(identity) 156 | ).to.eql( 157 | 5 158 | ); 159 | next(); 160 | }); 161 | }); 162 | }); 163 | -------------------------------------------------------------------------------- /test/monad_transformer.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | var fs = require('fs'); 5 | var expect = require('expect.js'); 6 | // Pair型の読込 7 | var Pair = require('../lib/pair.js'); 8 | // String型の読込 9 | var String = require('../lib/string.js'); 10 | 11 | var Maybe = require('../lib/monad.js').Maybe; 12 | var ID = require('../lib/monad.js').ID; 13 | var MaybeT = require('../lib/monad_transformer.js').MaybeT; 14 | 15 | // ### MaybeTモナドのテスト 16 | describe("MaybeTモナドをテストする",() => { 17 | it("MaybeT#unitをテストする", (next) => { 18 | Maybe.match(MaybeT.unit(1)(ID),{ 19 | nothing: (_) => { 20 | return expect.fail(); 21 | }, 22 | just: (v) => { 23 | expect( 24 | v 25 | ).to.eql( 26 | 1 27 | ); 28 | } 29 | }); 30 | next(); 31 | }); 32 | it("MaybeT#flatMapをテストする", (next) => { 33 | var instanceM = MaybeT.unit(1)(ID); 34 | var identity = (x) => { 35 | return x; 36 | }; 37 | var double = (x) => { 38 | return 2 * x; 39 | }; 40 | expect( 41 | MaybeT.flatMap(instanceM)(double)(ID) 42 | ).to.eql( 43 | 2 44 | ); 45 | next(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/not_in_use/chap01.spec.js: -------------------------------------------------------------------------------- 1 | 2 | it('チューリング機械で入力を複製する', (next) => { 3 | /* #@range_begin(turing_example) */ 4 | var program = { 5 | 'q0': {"1": {"write": "B", "move": 1, "next": 'q1'}}, 6 | 'q1': {"1": {"write": "1", "move": 1, "next": 'q1'}, 7 | "0": {"write": "0", "move": 1, "next": 'q2'}, 8 | "B": {"write": "0", "move": 1, "next": 'q2'}}, 9 | 'q2': {"1": {"write": "1", "move": 1, "next": 'q2'}, 10 | "B": {"write": "1", "move": -1, "next": 'q3'}}, 11 | 'q3': {"1": {"write": "1", "move": -1, "next": 'q3'}, 12 | "0": {"write": "0", "move": -1, "next": 'q3'}, 13 | "B": {"write": "1", "move": 1, "next": 'q4'}}, 14 | 'q4': {"1": {"write": "B", "move": 1, "next": 'q1'}, 15 | "0": {"write": "0", "move": 1, "next": 'q5'}} 16 | }; 17 | var tape = { 18 | '0': '1', 19 | '1':'1', 20 | '2':'1' 21 | }; 22 | var result = machine(program, // プログラム 23 | tape, // テープ 24 | 'q0', // 初期状態 25 | 'q5'); // 終了状態 26 | expect( 27 | result 28 | ).to.eql( 29 | ['1','1','1','0','1','1','1' ] 30 | ); 31 | /* #@range_end(turing_example) */ 32 | next(); 33 | }); 34 | 35 | it('sumsquaresとsquareの簡約', (next) => { 36 | /* #@range_begin(sumsquares) */ 37 | var sumsquares = (x,y) => { 38 | return square(x) + square(y); 39 | }; 40 | var square = (x) => { 41 | return x * x; 42 | }; 43 | /* #@range_end(sumsquares) */ 44 | expect( 45 | sumsquares(3,4) 46 | ).to.eql( 47 | 25 48 | ); 49 | next(); 50 | }); 51 | 52 | // #### 変数の置換ルール 53 | it('変数の置換ルール', (next) => { 54 | /* #@range_begin(variable_and_function) */ 55 | var foo = () => { 56 | return 3; 57 | }; 58 | expect( 59 | foo() 60 | ).to.eql( 61 | 3 62 | ); 63 | /* #@range_end(variable_and_function) */ 64 | /* #@range_begin(local_variable_usage_example) */ 65 | var bar = () => { 66 | var foo = 3; // 変数fooに値3をバインドする 67 | return foo * 10; // 変数fooの値を10倍にする 68 | }; 69 | /* #@range_end(local_variable_usage_example) */ 70 | expect( 71 | bar() 72 | ).to.eql( 73 | 30 74 | ); 75 | /* #@range_begin(variable_and_closure) */ 76 | var bar = () => { 77 | var foo = 3; 78 | return foo * 10; 79 | }; 80 | var baz = ((foo) => { 81 | return foo * 10; 82 | }); 83 | /* #@range_end(variable_and_closure) */ 84 | expect( 85 | bar() 86 | ).to.eql( 87 | baz(3) // 仮引数fooに値3をバインドする 88 | ); 89 | next(); 90 | }); 91 | 92 | it('adderからsucc関数を作る', (next) => { 93 | /* #@range_begin(succ_from_adder) */ 94 | var adder = (m) => { 95 | return (n) => { 96 | return m + n; 97 | }; 98 | }; 99 | var succ = adder(1); 100 | /* #@range_end(succ_from_adder) */ 101 | expect( 102 | succ(1) 103 | ).to.eql( 104 | 2 105 | ); 106 | next(); 107 | }); 108 | -------------------------------------------------------------------------------- /test/pair.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var Pair = require('../lib/pair.js'); 5 | var List = require('../lib/list.js'); 6 | var Data = require('../lib/data.js'); 7 | 8 | 9 | describe('Pair', () => { 10 | var data = Pair.cons(1,2); 11 | it("match", (next) => { 12 | data.match({ 13 | cons: (left, right) => { 14 | expect( 15 | left 16 | ).to.eql( 17 | 1 18 | ); 19 | } 20 | }); 21 | next(); 22 | }); 23 | it("left", (next) => { 24 | expect( 25 | Pair.left(data) 26 | ).to.eql( 27 | 1 28 | ); 29 | next(); 30 | }); 31 | it("right", (next) => { 32 | expect( 33 | Pair.right(data) 34 | ).to.eql( 35 | 2 36 | ); 37 | next(); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/pprinter.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var Data = require('../lib/data.js'); 5 | var Pair = require('../lib/pair.js'); 6 | var List = require('../lib/list.js'); 7 | var PP = require('../lib/pprinter.js'); 8 | 9 | describe('PrettyPrinter', () => { 10 | it("print", (next) => { 11 | var pair = Pair.cons(1,2); 12 | expect( 13 | PP.print(pair) 14 | ).to.eql( 15 | "(1,2)" 16 | ); 17 | expect( 18 | PP.print(List.cons(1, List.cons(2,List.empty()))) 19 | ).to.eql( 20 | "[1,2,nil]" 21 | ); 22 | expect( 23 | PP.print(List.cons("a", List.cons("b",List.empty()))) 24 | ).to.eql( 25 | "[a,b,nil]" 26 | ); 27 | expect( 28 | PP.print(List.empty()) 29 | ).to.eql( 30 | "[]" 31 | ); 32 | expect( 33 | PP.print(List.cons(Pair.cons(1,2), List.empty())) 34 | ).to.eql( 35 | "[(1,2),nil]" 36 | ); 37 | next(); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/resources/dream.txt: -------------------------------------------------------------------------------- 1 | こんな夢を見た。 2 | 六つになる子供を負ってる。たしかに自分の子である。ただ不思議な事にはいつの間にか眼が潰れて、青坊主になっている。 3 | 自分が御前の眼はいつ潰れたのかいと聞くと、なに昔からさと答えた。 4 | 声は子供の声に相違ないが、言葉つきはまるで大人である。しかも対等だ。 -------------------------------------------------------------------------------- /test/resources/file.txt: -------------------------------------------------------------------------------- 1 | This is another test. -------------------------------------------------------------------------------- /test/resources/io.txt: -------------------------------------------------------------------------------- 1 | 2 -------------------------------------------------------------------------------- /test/resources/mikan.txt: -------------------------------------------------------------------------------- 1 | 或ある曇った冬の日暮である。私わたくしは横須賀よこすか発上り二等客車の隅すみに腰を下して、ぼんやり発車の笛を待っていた。とうに電燈のついた客車の中には、珍らしく私の外に一人も乗客はいなかった。外を覗のぞくと、うす暗いプラットフォオムにも、今日は珍しく見送りの人影さえ跡を絶って、唯ただ、檻おりに入れられた小犬が一匹、時々悲しそうに、吠ほえ立てていた。これらはその時の私の心もちと、不思議な位似つかわしい景色だった。私の頭の中には云いようのない疲労と倦怠けんたいとが、まるで雪曇りの空のようなどんよりした影を落していた。私は外套がいとうのポッケットへじっと両手をつっこんだまま、そこにはいっている夕刊を出して見ようと云う元気さえ起らなかった。 2 | -------------------------------------------------------------------------------- /test/resources/test.txt: -------------------------------------------------------------------------------- 1 | 2 -------------------------------------------------------------------------------- /test/runner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Mocha Tests 7 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 20 | 21 | 33 | 34 | 39 | 40 | -------------------------------------------------------------------------------- /test/string.spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var expect = require('expect.js'); 4 | var List = require('../lib/list'); 5 | var String = require('../lib/string'); 6 | var PP = require('../lib/pprinter'); 7 | 8 | describe("Stringのテスト", () => { 9 | it("'head'", (next) => { 10 | expect( 11 | String.head("abc") 12 | ).to.eql( 13 | "a" 14 | ); 15 | next(); 16 | }); 17 | it("'tail'", (next) => { 18 | expect( 19 | String.tail("abc") 20 | ).to.eql( 21 | "bc" 22 | ); 23 | next(); 24 | }); 25 | it("toList", (next) => { 26 | expect( 27 | PP.print(String.toList.call(String,"abc")) 28 | ).to.eql( 29 | "[a,b,c,nil]" 30 | ); 31 | next(); 32 | }); 33 | }); 34 | --------------------------------------------------------------------------------