Repository: adambard/learnxinyminutes-docs Branch: master Commit: 1c6ba6f68851 Files: 886 Total size: 9.6 MB Directory structure: gitextract_7ub_b4qw/ ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── build.yml │ └── lint.yml ├── .gitignore ├── .mailmap ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── ada.md ├── agda.md ├── amd.md ├── angularjs.md ├── ansible.md ├── apl.md ├── ar/ │ ├── html.md │ ├── python.md │ └── sql.md ├── arturo.md ├── asciidoc.md ├── assemblyscript.md ├── asymptotic-notation.md ├── ats.md ├── awk.md ├── ballerina.md ├── bash.md ├── bc.md ├── be/ │ ├── python.md │ └── r.md ├── bf.md ├── bg/ │ ├── logtalk.md │ └── perl.md ├── bqn.md ├── c++.md ├── c.md ├── ca/ │ ├── asciidoc.md │ ├── go.md │ ├── groovy.md │ ├── html.md │ └── kotlin.md ├── chapel.md ├── chicken.md ├── citron.md ├── clojure-macros.md ├── clojure.md ├── cmake.md ├── cobol.md ├── coffeescript.md ├── coldfusion.md ├── common-lisp.md ├── compojure.md ├── coq.md ├── crystal.md ├── cs/ │ ├── bf.md │ ├── css.md │ ├── elm.md │ ├── go.md │ ├── hack.md │ ├── javascript.md │ ├── json.md │ ├── markdown.md │ ├── python.md │ └── sass.md ├── csharp.md ├── css.md ├── csv.md ├── cue.md ├── cypher.md ├── d.md ├── da/ │ └── javascript.md ├── dart.md ├── de/ │ ├── apl.md │ ├── asciidoc.md │ ├── bash.md │ ├── bc.md │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── clojure-macros.md │ ├── clojure.md │ ├── coffeescript.md │ ├── crystal.md │ ├── csharp.md │ ├── css.md │ ├── d.md │ ├── dhall.md │ ├── dynamic-programming.md │ ├── edn.md │ ├── elixir.md │ ├── elm.md │ ├── git.md │ ├── go.md │ ├── hack.md │ ├── haml.md │ ├── haskell.md │ ├── hq9+.md │ ├── html.md │ ├── java.md │ ├── javascript.md │ ├── json.md │ ├── latex.md │ ├── lolcode.md │ ├── lua.md │ ├── make.md │ ├── markdown.md │ ├── nix.md │ ├── opencv.md │ ├── paren.md │ ├── perl.md │ ├── processing.md │ ├── pug.md │ ├── pyqt.md │ ├── python.md │ ├── pythonlegacy.md │ ├── qt.md │ ├── rst.md │ ├── ruby-ecosystem.md │ ├── ruby.md │ ├── rust.md │ ├── sass.md │ ├── scala.md │ ├── shutit.md │ ├── sql.md │ ├── swift.md │ ├── tcl.md │ ├── vim.md │ ├── visualbasic.md │ └── yaml.md ├── dhall.md ├── directx9.md ├── djot.md ├── docker.md ├── dynamic-programming.md ├── easylang.md ├── edn.md ├── el/ │ ├── bash.md │ ├── css.md │ ├── haskell.md │ ├── html.md │ ├── java.md │ ├── json.md │ ├── ocaml.md │ ├── python.md │ ├── racket.md │ ├── rust.md │ ├── scala.md │ └── vim.md ├── elisp.md ├── elixir.md ├── elm.md ├── emacs.md ├── erlang.md ├── es/ │ ├── amd.md │ ├── asciidoc.md │ ├── asymptotic-notation.md │ ├── awk.md │ ├── bash.md │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── chapel.md │ ├── clojure.md │ ├── coffeescript.md │ ├── coldfusion.md │ ├── common-lisp.md │ ├── csharp.md │ ├── css.md │ ├── csv.md │ ├── curto.md │ ├── dart.md │ ├── docker.md │ ├── dynamic-programming.md │ ├── edn.md │ ├── elisp.md │ ├── elixir.md │ ├── factor.md │ ├── forth.md │ ├── fsharp.md │ ├── git.md │ ├── go.md │ ├── groovy.md │ ├── hack.md │ ├── haml.md │ ├── haskell.md │ ├── hq9+.md │ ├── html.md │ ├── hy.md │ ├── java.md │ ├── javascript.md │ ├── jquery.md │ ├── json.md │ ├── julia.md │ ├── kotlin.md │ ├── lambda-calculus.md │ ├── latex.md │ ├── less.md │ ├── livescript.md │ ├── logtalk.md │ ├── lua.md │ ├── make.md │ ├── markdown.md │ ├── matlab.md │ ├── objective-c.md │ ├── pascal.md │ ├── pcre.md │ ├── perl.md │ ├── php-composer.md │ ├── php.md │ ├── powershell.md │ ├── pyqt.md │ ├── python.md │ ├── pythonlegacy.md │ ├── pythonstatcomp.md │ ├── r.md │ ├── racket.md │ ├── raku.md │ ├── rst.md │ ├── ruby-ecosystem.md │ ├── ruby.md │ ├── rust.md │ ├── sass.md │ ├── scala.md │ ├── self.md │ ├── smallbasic.md │ ├── sql.md │ ├── swift.md │ ├── tcl.md │ ├── tmux.md │ ├── typescript.md │ ├── vim.md │ ├── visualbasic.md │ ├── wolfram.md │ ├── xml.md │ └── yaml.md ├── fa/ │ ├── bf.md │ ├── css.md │ ├── html.md │ ├── javascript.md │ └── vim.md ├── factor.md ├── fi/ │ ├── go.md │ ├── markdown.md │ └── ruby.md ├── fish.md ├── forth.md ├── fortran.md ├── fr/ │ ├── asymptotic-notation.md │ ├── awk.md │ ├── bash.md │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── clojure.md │ ├── coffeescript.md │ ├── crystal.md │ ├── csharp.md │ ├── css.md │ ├── d.md │ ├── dynamic-programming.md │ ├── elisp.md │ ├── elixir.md │ ├── erlang.md │ ├── fsharp.md │ ├── git.md │ ├── go.md │ ├── haml.md │ ├── haskell.md │ ├── html.md │ ├── hy.md │ ├── java.md │ ├── javascript.md │ ├── jquery.md │ ├── json.md │ ├── kotlin.md │ ├── lambda-calculus.md │ ├── livescript.md │ ├── lua.md │ ├── make.md │ ├── markdown.md │ ├── nix.md │ ├── objective-c.md │ ├── pcre.md │ ├── perl.md │ ├── php.md │ ├── pyqt.md │ ├── python.md │ ├── pythonlegacy.md │ ├── r.md │ ├── racket.md │ ├── ruby-ecosystem.md │ ├── ruby.md │ ├── rust.md │ ├── scala.md │ ├── set-theory.md │ ├── sql.md │ ├── tmux.md │ ├── typescript.md │ ├── vim.md │ ├── wolfram.md │ ├── xml.md │ └── yaml.md ├── fsharp.md ├── gdscript.md ├── git.md ├── gleam.md ├── go.md ├── golfscript.md ├── groovy.md ├── hack.md ├── haml.md ├── haskell.md ├── haxe.md ├── hcl.md ├── hdl.md ├── he/ │ ├── html.md │ └── uxntal.md ├── hi/ │ ├── amd.md │ ├── c++.md │ ├── d.md │ └── json.md ├── hjson.md ├── hocon.md ├── hq9+.md ├── hre.csv ├── html.md ├── httpie.md ├── hu/ │ ├── coffeescript.md │ ├── go.md │ ├── pythonlegacy.md │ ├── ruby.md │ ├── typescript.md │ └── yaml.md ├── hy.md ├── id/ │ ├── asciidoc.md │ ├── bf.md │ ├── coffeescript.md │ ├── css.md │ ├── hq9+.md │ ├── java.md │ ├── json.md │ ├── markdown.md │ ├── php.md │ ├── pyqt.md │ ├── rst.md │ ├── ruby.md │ ├── smallbasic.md │ └── xml.md ├── inform7.md ├── it/ │ ├── asciidoc.md │ ├── bash.md │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── cmake.md │ ├── coffeescript.md │ ├── dynamic-programming.md │ ├── elixir.md │ ├── fish.md │ ├── gdscript.md │ ├── git.md │ ├── go.md │ ├── html.md │ ├── java.md │ ├── javascript.md │ ├── jquery.md │ ├── json.md │ ├── logtalk.md │ ├── lua.md │ ├── markdown.md │ ├── matlab.md │ ├── pcre.md │ ├── php-composer.md │ ├── pyqt.md │ ├── python.md │ ├── pythonlegacy.md │ ├── qt.md │ ├── rst.md │ ├── ruby-ecosystem.md │ ├── ruby.md │ ├── rust.md │ ├── solidity.md │ ├── sql.md │ ├── toml.md │ ├── typescript.md │ ├── vim.md │ └── zfs.md ├── ja/ │ ├── asciidoc.md │ ├── bash.md │ ├── c.md │ ├── css.md │ ├── elixir.md │ ├── julia.md │ ├── markdown.md │ ├── nim.md │ ├── php.md │ ├── python.md │ ├── r.md │ ├── rust.md │ ├── vim.md │ └── yaml.md ├── janet.md ├── java.md ├── javascript.md ├── jinja.md ├── jq.md ├── jquery.md ├── json.md ├── jsonnet.md ├── julia.md ├── kdb+.md ├── ko/ │ ├── bash.md │ ├── bf.md │ ├── clojure-macros.md │ ├── clojure.md │ ├── coffeescript.md │ ├── common-lisp.md │ ├── erlang.md │ ├── go.md │ ├── java.md │ ├── javascript.md │ ├── json.md │ ├── kotlin.md │ ├── lua.md │ ├── markdown.md │ ├── php.md │ ├── pythonlegacy.md │ ├── racket.md │ ├── vim.md │ ├── xml.md │ └── yaml.md ├── kotlin.md ├── lambda-calculus.md ├── latex.md ├── lbstanza.md ├── ldpl.md ├── lean4.md ├── less.md ├── lfe.md ├── linker.md ├── lint/ │ ├── encoding.sh │ ├── frontmatter.py │ └── requirements.txt ├── livescript.md ├── logtalk.md ├── lolcode.md ├── lt/ │ ├── json.md │ └── tmux.md ├── lua.md ├── m.md ├── make.md ├── markdown.md ├── matlab.md ├── mercurial.md ├── mercury.md ├── messagepack.md ├── miniscript.md ├── mips.md ├── mongodb.md ├── moonscript.md ├── ms/ │ ├── bash.md │ ├── clojure-macros.md │ ├── clojure.md │ ├── coffeescript.md │ ├── common-lisp.md │ ├── elisp.md │ ├── javascript.md │ ├── json.md │ ├── sass.md │ └── xml.md ├── nim.md ├── niva.md ├── nix.md ├── nl/ │ ├── amd.md │ ├── bash.md │ ├── bf.md │ ├── coffeescript.md │ ├── dynamic-programming.md │ ├── html.md │ ├── json.md │ ├── markdown.md │ ├── typescript.md │ ├── vim.md │ ├── xml.md │ └── yaml.md ├── nmap.md ├── no/ │ ├── bash.md │ └── json.md ├── objective-c.md ├── ocaml.md ├── odin.md ├── opencv.md ├── opengl.md ├── openmp.md ├── openscad.md ├── osl.md ├── p5.md ├── paren.md ├── pascal.md ├── pcre.md ├── perl.md ├── pets.csv ├── phel.md ├── phix.md ├── php-composer.md ├── php.md ├── pl/ │ ├── bf.md │ ├── haskell.md │ ├── java.md │ ├── json.md │ ├── perl.md │ ├── pythonlegacy.md │ ├── ruby.md │ ├── vim.md │ └── xml.md ├── powershell.md ├── processing.md ├── prolog.md ├── protocol-buffer-3.md ├── pt-br/ │ ├── amd.md │ ├── asciidoc.md │ ├── asymptotic-notation.md │ ├── awk.md │ ├── bash.md │ ├── bc.md │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── clojure-macros.md │ ├── clojure.md │ ├── cmake.md │ ├── coffeescript.md │ ├── common-lisp.md │ ├── csharp.md │ ├── css.md │ ├── cypher.md │ ├── d.md │ ├── dart.md │ ├── dynamic-programming.md │ ├── elisp.md │ ├── elixir.md │ ├── elm.md │ ├── emacs.md │ ├── erlang.md │ ├── factor.md │ ├── fsharp.md │ ├── git.md │ ├── go.md │ ├── groovy.md │ ├── hack.md │ ├── haskell.md │ ├── haxe.md │ ├── html.md │ ├── httpie.md │ ├── hy.md │ ├── java.md │ ├── javascript.md │ ├── jquery.md │ ├── json.md │ ├── julia.md │ ├── kotlin.md │ ├── lambda-calculus.md │ ├── latex.md │ ├── less.md │ ├── lua.md │ ├── make.md │ ├── markdown.md │ ├── matlab.md │ ├── p5.md │ ├── paren.md │ ├── pascal.md │ ├── perl.md │ ├── php-composer.md │ ├── php.md │ ├── processing.md │ ├── pug.md │ ├── pyqt.md │ ├── python.md │ ├── pythonlegacy.md │ ├── pythonstatcomp.md │ ├── qt.md │ ├── r.md │ ├── ruby-ecosystem.md │ ├── ruby.md │ ├── rust.md │ ├── sass.md │ ├── scala.md │ ├── self.md │ ├── set-theory.md │ ├── solidity.md │ ├── sql.md │ ├── stylus.md │ ├── swift.md │ ├── tmux.md │ ├── toml.md │ ├── typescript.md │ ├── vim.md │ ├── visualbasic.md │ ├── xml.md │ └── yaml.md ├── pt-pt/ │ ├── bf.md │ ├── git.md │ ├── kotlin.md │ ├── scala.md │ └── swift.md ├── pug.md ├── purescript.md ├── pyqt.md ├── python.md ├── pythonlegacy.md ├── pythonstatcomp.md ├── qml.md ├── qsharp.md ├── qt.md ├── r.md ├── racket.md ├── raku-pod.md ├── raku.md ├── raylib.md ├── rdf.md ├── reason.md ├── red.md ├── rescript.md ├── rink.md ├── ro/ │ ├── bash.md │ ├── bf.md │ ├── clojure.md │ ├── coffeescript.md │ ├── elixir.md │ ├── haskell.md │ ├── json.md │ ├── latex.md │ ├── pythonlegacy.md │ ├── ruby.md │ └── xml.md ├── rst.md ├── ru/ │ ├── asymptotic-notation.md │ ├── bash.md │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── clojure.md │ ├── coffeescript.md │ ├── common-lisp.md │ ├── crystal.md │ ├── css.md │ ├── d.md │ ├── dynamic-programming.md │ ├── elixir.md │ ├── erlang.md │ ├── forth.md │ ├── go.md │ ├── haml.md │ ├── haskell.md │ ├── html.md │ ├── java.md │ ├── javascript.md │ ├── jquery.md │ ├── json.md │ ├── julia.md │ ├── kotlin.md │ ├── linker.md │ ├── lua.md │ ├── markdown.md │ ├── nim.md │ ├── objective-c.md │ ├── paren.md │ ├── pascal.md │ ├── perl.md │ ├── php-composer.md │ ├── php.md │ ├── pyqt.md │ ├── python.md │ ├── pythonlegacy.md │ ├── qt.md │ ├── ruby.md │ ├── rust.md │ ├── sql.md │ ├── swift.md │ ├── tcl.md │ ├── tmux.md │ ├── typescript.md │ ├── vim.md │ ├── visualbasic.md │ ├── xml.md │ ├── yaml.md │ └── zfs.md ├── ruby-ecosystem.md ├── ruby.md ├── rust.md ├── sass.md ├── scala.md ├── sed.md ├── self.md ├── set-theory.md ├── shutit.md ├── sing.md ├── sk/ │ ├── bash.md │ ├── coffeescript.md │ ├── elixir.md │ ├── git.md │ ├── json.md │ ├── latex.md │ └── ruby.md ├── sl/ │ └── asciidoc.md ├── smallbasic.md ├── smalltalk.md ├── snobol.md ├── solidity.md ├── sorbet.md ├── sql.md ├── standard-ml.md ├── stylus.md ├── sv/ │ ├── bf.md │ ├── haskell.md │ ├── json.md │ └── nix.md ├── swift.md ├── ta/ │ ├── css.md │ ├── javascript.md │ ├── json.md │ └── xml.md ├── tailspin.md ├── tcl.md ├── tcsh.md ├── texinfo.md ├── textile.md ├── th/ │ ├── pascal.md │ └── typescript.md ├── tmux.md ├── toml.md ├── tr/ │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── clojure.md │ ├── csharp.md │ ├── css.md │ ├── dynamic-programming.md │ ├── edn.md │ ├── fsharp.md │ ├── gdscript.md │ ├── git.md │ ├── html.md │ ├── javascript.md │ ├── jquery.md │ ├── kotlin.md │ ├── markdown.md │ ├── objective-c.md │ ├── php.md │ ├── python.md │ ├── pythonlegacy.md │ ├── ruby.md │ ├── sql.md │ ├── swift.md │ └── typescript.md ├── typescript.md ├── uk/ │ ├── awk.md │ ├── bash.md │ ├── c.md │ ├── cypher.md │ ├── go.md │ ├── java.md │ ├── javascript.md │ ├── json.md │ ├── kotlin.md │ ├── mips.md │ ├── python.md │ ├── pythonlegacy.md │ ├── ruby.md │ ├── rust.md │ ├── sql.md │ ├── typescript.md │ └── wasm.md ├── uxntal.md ├── v.md ├── vala.md ├── vi/ │ ├── git.md │ ├── html.md │ ├── json.md │ ├── less.md │ ├── markdown.md │ ├── objective-c.md │ ├── python.md │ ├── ruby-ecosystem.md │ ├── ruby.md │ ├── sass.md │ ├── typescript.md │ └── xml.md ├── vim.md ├── vim9script.md ├── vimscript.md ├── visualbasic.md ├── wasm.md ├── wikitext.md ├── wolfram.md ├── xml.md ├── yaml.md ├── zfs.md ├── zh-cn/ │ ├── angularjs.md │ ├── asciidoc.md │ ├── awk.md │ ├── bash.md │ ├── bc.md │ ├── bf.md │ ├── c++.md │ ├── c.md │ ├── clojure-macros.md │ ├── clojure.md │ ├── cmake.md │ ├── cobol.md │ ├── coffeescript.md │ ├── common-lisp.md │ ├── crystal.md │ ├── csharp.md │ ├── css.md │ ├── dart.md │ ├── docker.md │ ├── dynamic-programming.md │ ├── elisp.md │ ├── elixir.md │ ├── erlang.md │ ├── fortran.md │ ├── fsharp.md │ ├── gdscript.md │ ├── git.md │ ├── go.md │ ├── groovy.md │ ├── haskell.md │ ├── html.md │ ├── java.md │ ├── javascript.md │ ├── jquery.md │ ├── json.md │ ├── julia.md │ ├── kotlin.md │ ├── lambda-calculus.md │ ├── latex.md │ ├── less.md │ ├── livescript.md │ ├── lua.md │ ├── make.md │ ├── markdown.md │ ├── matlab.md │ ├── mips.md │ ├── nim.md │ ├── nix.md │ ├── objective-c.md │ ├── opencv.md │ ├── perl.md │ ├── php.md │ ├── powershell.md │ ├── pyqt.md │ ├── python.md │ ├── pythonlegacy.md │ ├── qt.md │ ├── r.md │ ├── racket.md │ ├── raylib.md │ ├── red.md │ ├── ruby.md │ ├── rust.md │ ├── sass.md │ ├── scala.md │ ├── set-theory.md │ ├── solidity.md │ ├── sql.md │ ├── standard-ml.md │ ├── swift.md │ ├── tmux.md │ ├── typescript.md │ ├── vim.md │ ├── visualbasic.md │ ├── wolfram.md │ ├── xml.md │ ├── yaml.md │ └── zfs.md ├── zh-tw/ │ ├── bash.md │ ├── dart.md │ ├── elixir.md │ ├── javascript.md │ ├── pcre.md │ ├── perl.md │ ├── pythonlegacy.md │ └── typescript.md └── zig.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ *.md linguist-language=Markdown linguist-detectable ================================================ FILE: .github/CODEOWNERS ================================================ /fr-fr/ @vendethiel /ru-ru/ @Menelion /uk-ua/ @Menelion /zh-cn/ @geoffliu @imba-tjd /zh-tw/ @geoffliu @imba-tjd /ko-kr/ @justin-themedium /pt-pt/ @mribeirodantas /pt-br/ @mribeirodantas ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ ## Is this a major issue that you cannot fix? **Being a community driven documents of languages and tools,"YOUR" contributions are also important. If the issue you're reporting is trivial to report to maintainers why not contribute to fix it. In that way, you will have contributed to an awesome open-source project. The changes can be typo fix, fixing of data in examples or grammar fix. If you found it, why not do it and take full credit for it?** Make sure the issue title is prepended with '[language/lang-code]' if the language is already on the site. If it's a request for a new language, use: '[Request] [language/lang-code]' Issues are always welcome. If you are able and willing, we welcome any pull requests as this is a community powered project. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ - [ ] I solemnly swear that this is all original content of which I am the original author - [ ] Pull request title is prepended with `[language/lang-code]` (example `[python/fr]` for Python in French or `[java]` for multiple Java translations) - [ ] Pull request touches only one file (or a set of logically related files with similar changes made) - [ ] Content changes are aimed at *intermediate to experienced programmers* (this is a poor format for explaining fundamental programming concepts) - [ ] If you've changed any part of the YAML Frontmatter, make sure it is formatted according to [CONTRIBUTING.md](https://github.com/adambard/learnxinyminutes-docs/blob/master/CONTRIBUTING.md) ================================================ FILE: .github/workflows/build.yml ================================================ name: Trigger site build on: push: branches: [main, master] jobs: deploy: runs-on: ubuntu-latest if: github.event_name == 'push' && github.repository_owner == 'adambard' steps: - name: Trigger site build uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.PAT_LEARNXINYMINUTES_SITE }} repository: adambard/learnxinyminutes-site event-type: doc-update ================================================ FILE: .github/workflows/lint.yml ================================================ name: CI on: push: branches: [master] pull_request: branches: [master] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.13' - run: pip install -r lint/requirements.txt - uses: ruby/setup-ruby@v1 with: ruby-version: '3.2' - run: gem install mdl - name: Files are UTF-8 run: ./lint/encoding.sh . - name: "No non-breaking spaces" run: | if grep -rI --include='*.md' $'\u00A0' .; then exit 1 fi - name: "No zero-width spaces" run: | if grep -rI --include='*.md' $'\u200B' .; then exit 1 fi - name: "No carriage return" run: | if grep -rI --include='*.md' $'\u000D' .; then exit 1 fi - name: "GitHub/JavaScript/TypeScript capitalized properly" run: | if grep -rI --include='*.md' -E "Github|Javascript|Typescript" .; then exit 1 fi - name: Lint Markdown run: mdl . --ignore-front-matter -r MD003,MD005,MD011,MD018,MD019,MD023,MD025,MD027,MD028,MD030,MD035,MD037,MD038,MD039,MD046,MD047 - name: Lint frontmatter run: ./lint/frontmatter.py . ================================================ FILE: .gitignore ================================================ **/*~ **/*# **/#*# **/*.swp **/*.swo **/*.bak **/*.log* **/*.sublime-workspace **/.DS_Store **/.DS_Store? **/._* **/.Spotlight-V100 **/.Trashes **/ehthumbs.db **/Thumbs.db **/desktop.ini ================================================ FILE: .mailmap ================================================ Leigh Brenecki Adam Bard Adam Adam Bard Adam Bard ven Nami-Doc Andre Polykanine Andre Polykanine Divay Prakash Divay Prakash Levi Bostian Pratik Karki Marcel Ribeiro-Dantas Marcel Ribeiro-Dantas Marcel Ribeiro-Dantas Marcel Ribeiro-Dantas Marcel Ribeiro-Dantas Geoff Liu Geoff Liu sirkubax caminsha <31421093+caminsha@users.noreply.github.com> Samantha McVey Ian Bertolacci ian.bertolacci Boris Verkhovskiy Louie Dinh lodin Milo Gilad Milo Gilad Yannick Loriot Yannick ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing All contributions are welcome, from the tiniest typo to a brand new article. Translations in all languages are welcome (or, for that matter, original articles in any language). Send a pull request or open an issue any time of day or night. **Please prepend the tag `[language/lang-code]` to your issues and pull requests.** For example, `[python/en]` for English Python. This will help everyone pick out things they care about. We're happy for any contribution in any form, but if you're making more than one major change (i.e. translations for two different languages) it would be super cool of you to make a separate pull request for each one so that someone can review them more effectively and/or individually. ## Style Guidelines * **Keep lines under 80 chars** * Try to keep line length in code blocks to 80 characters or fewer. * Otherwise, the text will overflow and look odd. * This and other potential pitfalls to format the content consistently are identified by [markdownlint](https://github.com/markdownlint/markdownlint). * **Prefer example to exposition** * Try to use as few words as possible. * Code examples are preferred over exposition in all cases. * **Eschew surplusage** * We welcome newcomers, but the target audience for this site is programmers with some experience. * Try to avoid explaining basic concepts except for those specific to the language in question. * Keep articles succinct and scannable. We all know how to use Google here. * **Use UTF-8** ### Header configuration The actual site generates HTML files from these Markdown ones. The markdown files can contain extra metadata before the actual markdown, called frontmatter. The following fields are necessary for English articles about programming languages: * `name`: The human-readable name of the programming language * `contributors`: A list of [*author*, *URL*] lists to credit, *URL* is optional Other fields: * `category`: The category of the article. So far, can be one of *language*, *tool* or *Algorithms & Data Structures*. Defaults to *language* if omitted. * `filename`: The filename for this article's code. It will be fetched, mashed together, and made downloadable. Translations should also include: * `translators`: A list of [*translator*, *URL*] lists to credit, *URL* is optional Non-English articles inherit frontmatter values from the English article (if it exists) but you can overwrite them. Here's an example header for Ruby: ```yaml --- name: Ruby filename: learnruby.rb contributors: - ["Doktor Esperanto", "http://example.com/"] - ["Someone else", "http://someoneelseswebsite.com/"] --- ``` ### Syntax highlighter [Pygments](https://pygments.org/languages/) is used for syntax highlighting. ### Should I add myself as a contributor? If you want to add yourself to contributors, keep in mind that contributors get equal billing, and the first contributor usually wrote the whole article. Please use your judgment when deciding if your contribution constitutes a substantial addition or not. ## Building the site locally Install Python. On macOS this can be done with [Homebrew](https://brew.sh/). ```sh brew install python ``` Then clone two repos, install dependencies and run. ```sh # Clone website git clone https://github.com/adambard/learnxinyminutes-site # Clone docs (this repo) nested in website git clone https://github.com//learnxinyminutes-docs ./learnxinyminutes-site/source/docs/ # Install dependencies cd learnxinyminutes-site pip install -r requirements.txt # Run python build.py cd build python -m http.server # open http://localhost:8000/ in your browser of choice ``` ================================================ FILE: LICENSE.txt ================================================ Creative Commons Legal Code Attribution-ShareAlike 3.0 Unported CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. License THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. c. "Creative Commons Compatible License" means a license that is listed at https://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. d. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. e. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. f. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. g. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. h. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. i. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. j. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. k. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, d. to Distribute and Publicly Perform Adaptations. e. For the avoidance of doubt: i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. b. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. c. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Ssection 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. d. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License. Creative Commons may be contacted at https://creativecommons.org/. ================================================ FILE: README.md ================================================ # [Learn X in Y minutes][1] Whirlwind tours of (several, hopefully many someday) popular and ought-to-be-more-popular programming languages, presented as valid, commented code and explained as they go. ## We need YOU!... ... to write more inline code tutorials. Just grab an existing file from this repo and copy the formatting (don't worry, it's all very simple). Make a new file, send a pull request, and if it passes muster I'll get it up pronto. Remember to fill in the "contributors" fields so you get credited properly! ## Contributing All contributions are welcome, from the tiniest typo to a brand new article. Translations in all languages are welcome (or, for that matter, original articles in any language). Send a pull request or open an issue any time of day or night. **Please prepend the tag `[language/lang-code]` to your issues and pull requests.** For example, `[python/en]` for English Python. This will help everyone pick out things they care about. We're happy for any contribution in any form, but if you're making more than one major change (i.e. translations for two different languages) it would be super cool of you to make a separate pull request for each one so that someone can review them more effectively and/or individually. For a detailed style guide, please review the full [CONTRIBUTING][2] guidelines. ## License Contributors retain copyright to their work, and can request removal at any time. By uploading a doc here, you agree to publish your work under the default [Creative Commons Attribution-ShareAlike 3.0 Unported][3] licensing included on each doc page. Anything not covered by the above -- basically, this README -- you can use as you wish, I guess. [1]: https://learnxinyminutes.com [2]: /CONTRIBUTING.md [3]: http://creativecommons.org/licenses/by-sa/3.0/deed.en_US ================================================ FILE: ada.md ================================================ --- name: Ada filename: learn.ada contributors: - ["Luke A. Guest", "https://github.com/Lucretia"] - ["Fernando Oleo Blanco", "https://github.com/Irvise"] - ["Fabien Chouteau", "https://github.com/Fabien-Chouteau"] - ["Manuel", "https://github.com/mgrojo"] --- Ada is a strong statically typed imperative, [object-oriented](https://ada-lang.io/docs/arm/AA-3/AA-3.9), [real-time](https://ada-lang.io/docs/arm/AA-D), [parallel](https://ada-lang.io/docs/arm/AA-9) and [distributed](https://ada-lang.io/docs/arm/AA-9) programming language from the Pascal/Algol family of languages, but nowadays, it only has a passing resemblance to Pascal, with the only remnants left being the ```begin/end``` keyword pair, the ```:=``` assignment symbol, records and ```if/case``` control statement structures. Ada was originally designed to be an [object-based](https://ada-lang.io/docs/arm/AA-3/AA-3.3) language and to replace 100's of languages in use by the US government. This means that all entities are objects, not in the object-oriented sense. The language became [Object-Oriented](https://ada-lang.io/docs/arm/AA-3/AA-3.9) in 1995, and added [interfaces](https://ada-lang.io/docs/arm/AA-3/AA-3.9#Subclause_3.9.4) derived from Java in 2005. [Contract based](https://ada-lang.io/docs/arm/AA-13/AA-13.1#Subclause_13.1.1) programming was introduced with Ada 2012. Ada was designed to be easy to read and learn, even for non-programmers, e.g. management within an organisation, therefore programs written in the language tend to be a bit more verbose. Ada is a modern programming language, and now has a package manager like other modern languages, Alire, see below. ```ada -- Comments are written with a double hyphen and exist until the end of -- the line. -- You do not need to call the entry point "Main" or "main," you should -- name it based on what the program does. procedure Empty is -- This is a declarative part. begin -- Statements go here. null; -- Do nothing here. end Empty; -- Ada compilers accept compilation units which can be library packages, -- tasks, sub-programs, generics, etc. -- This is where "context clauses" go, these can be pragmas or "with" -- statements. "with" is equivalent to "include" or "import" in other -- languages. with Ada.Text_IO; -- Get access to a library package. procedure Hello is begin Ada.Text_IO.Put_Line ("Hello, world"); Ada.Text_IO.Put ("Hello again, world"); Ada.Text_IO.New_Line; end Hello; -- Ada has a real module system. Modules are called packages and are split into -- two component parts, the specification and a body. -- It is important to introduce packages early, as you will be using them from -- the start. package Stuff is -- We could add the following line in order to tell the compiler that this -- package does not have to run any code before the "main" procedure starts. -- pragma Preelaborate; -- Packages can be nested within the same file or externally. -- Nested packages are accessed via dot notation, e.g. Stuff.Things.My. package Things is My : constant Integer := 100; end Things; -- If there are sub-programs declared within the specification, the body -- of the sub-program must be declared within the package body. procedure Do_Something; -- If a subprogram takes no parameters, empty -- parentheses are not required, unlike other -- languages. -- We can also make generic sub-programs. generic type Element is (<>); -- The "(<>)" notation specifies that only -- discrete types can be passed into the generic. procedure Swap (Left, Right : in out Element); -- Sometimes we want to hide how a type is defined from the outside world -- so that nobody can mess with it directly. The full type must be defined -- within the private section below. type Blobs is private; -- We can also make types "limited" by putting this keyword after the "is" -- keyword, this means that the user cannot copy objects of that type -- around, like they normally could. private type Blobs is new Integer range -25 .. 25; end Stuff; package body Stuff is -- Sub-program body. procedure Do_Something is -- We can nest sub-programs too. -- Parameters are defined with the direction of travel, in, in out, out. -- If the direction of travel is not specified, they are in by default. function Times_4 (Value : in Integer) return Integer is begin return Value * 4; end Times_4; I : Integer := 4; begin I := Times_4 (I); end Do_Something; -- Generic procedure body. procedure Swap (Left, Right : in out Element) is Temp : Element := Left; begin Left := Right; Right := Temp; end Swap; begin -- If we need to initialise something within the package, we can do it -- here. Do_Something; end Stuff; with Ada.Unchecked_Conversion; with Ada.Text_IO; with Stuff; procedure LearnAdaInY is -- Indentation is 3 spaces. -- The most important feature in Ada is the type. Objects have types and an -- object of one type cannot be assigned to an object of another type. -- You can, and should, define your own types for the domain you are -- modelling. But you can use the standard types to start with and then -- replace them later with your own types, this could be called a form of -- gradual typing. -- The standard types would only really be a good starting point for binding -- to other languages, like C. Ada is the only language with a standardised -- way to bind with C, Fortran and COBOL! See the links in the References -- section with more information on binding to these languages. type Degrees is range 0 .. 360; -- This is a type. Its underlying -- representation is an Integer. type Hues is (Red, Green, Blue, Purple, Yellow); -- So is this. Here, we -- are declaring an -- Enumeration. -- This is a modular type. They behave like Integers that automatically -- wrap around. In this specific case, the range would be 0 .. 359. -- If we added 1 to a variable containing the value 359, we would receive -- back 0. They are very useful for arrays. type Degrees_Wrap is mod 360; -- You can restrict a type's range using a subtype, this makes them -- compatible with each other, i.e. the subtype can be assigned to an -- object of the type, as can be seen below. subtype Primaries is Hues range Red .. Blue; -- This is a range. -- You can define variables or constants like this: -- Var_Name : Type := Value; -- 10 is a universal integer. These universal numerics can be used with -- any type which matches the base type. Angle : Degrees := 10; Value : Integer := 20; -- New_Angle : Degrees := Value; -- Incompatible types won't compile. -- New_Value : Integer := Angle; Blue_Hue : Primaries := Blue; -- A variable. Red_Hue : constant Primaries := Red; -- A constant. Yellow_Hue : constant Hues := Yellow; Colour_1 : constant Hues := Red_Hue; -- Colour_2 : constant Primaries := Yellow_Hue; -- uncomment to compile. -- You can force conversions, but then you are warned by the name of the -- package that you may be doing something unsafe. function Degrees_To_Int is new Ada.Unchecked_Conversion (Source => Degrees, -- Line continuations are indented by 2 spaces. Target => Integer); New_Value_2 : Integer := Degrees_To_Int (Angle); -- Note, space before (. -- GNAT is the GNU Ada Translator (compiler). -- Ada has a style guide and GNAT will warn you to adhere to it, and has -- option to check your style so that you can correct it so that all Ada -- source looks consistent. However, the style can be customized. -- Yes, you can even define your own floating and fixed point types, this -- is a very rare and unique ability. "digits" refers to the minimum -- digit precision that the type should support. "delta" is for fixed -- point types and refers to the smallest change that the type will support. type Real_Angles is digits 3 range 0.0 .. 360.0; type Fixed_Angles is delta 0.01 digits 5 range 0.0 .. 360.0; RA : constant Real_Angles := 36.45; FA : constant Fixed_Angles := 360.0; -- ".0" in order to make it a Float. -- You can have normal Latin 1 based strings by default. Str : constant String := "This is a constant string"; -- When initialising from a string literal, the compiler knows the bounds, -- so we don't have to define them. -- Strings are arrays. Note how parentheses are used to access elements of -- an array? This is mathematical notation and was used because square -- brackets were not available on all keyboards at the time Ada was -- created. Also, because an array can be seen as a function from a -- mathematical perspective, so it made converting between arrays and -- functions easier. Char : constant Character := Str (Str'First); -- "'First" is a type -- attribute. -- Ada 2022 includes the use of [] for array initialisation when using -- containers, which were added in Ada 2012. -- Arrays are usually always defined as a type. -- They can be any dimension. type My_Array_1 is array (1 .. 4, 3 .. 7, -20 .. 20) of Integer; -- Yes, unlike other languages, you can index arrays with other discrete -- types such as enumerations and modular types or arbitrary ranges. type Axes is (X, Y, Z); -- You can define the array's range using the 'Range attribute from -- another type. type Vector is array (Axes'Range) of Float; V1 : constant Vector := (0.0, 0.0, 1.0); -- A record is the same as a structure in C, C++. type Entities is record Name : String (1 .. 10); -- Always starts at a positive value, -- inclusive range. Position : Vector; end record; -- In Ada, array bounds are immutable. You therefore have to provide a -- string literal with a value for every character. E1 : constant Entities := ("Blob ", (0.0, 0.0, 0.0)); -- An alternative is to use an array aggregate and assign a default value -- to every element that wasn't previously assigned in this aggregate. -- "others" is used to indicate anything else that has not been -- explicitly initialized. E2 : constant Entities := (('B', 'l', 'o', 'b', others => ' '), (0.0, 0.0, 0.0)); -- There are dynamic length strings (see references section) available in -- the standard library. -- We can make an object be initialised to its default values with the box -- notation, "<>". "others" is used to indicate anything else that has not -- been explicitly initialized. Null_Entity : constant Entities := (others => <>); -- Object-orientation is accomplished via an extension of record syntax, -- tagged records, see link above in first paragraph. -- We can rename objects (aliases) to make readability a bit better. package IO renames Ada.Text_IO; begin -- We can output enumerations as names. IO.Put_Line ("Blue_Hue = " & -- & is the string concatenation operator. Blue'Image); -- ' accesses attributes on objects. -- The Image attribute converts a value to a string. -- Ada 2022 has extended Image to custom types too. -- Access this with -gnat2022 compiler flag. IO.Put_Line ("Yellow_Hue = " & -- We can use the type's attribute. Primaries'Image (Yellow_Hue)); -- We can define local variables within a declare block, this can be made -- more readable by giving it a label. Enum_IO : declare package Hue_IO is new IO.Enumeration_IO (Hues); -- Using a package makes everything inside that package visible within -- this block, it is good practice to only do this locally and not on -- a whole package within the context clause. use Hue_IO; begin -- We can print out the enumeration values too. Put (Purple); -- Note we don't have to prefix the Put procedure with -- Hue_IO. IO.New_Line; -- We still need to prefix with IO here. Put (Red_Hue); IO.New_Line; end Enum_IO; -- Loops have a consistent form. "
loop ... end loop". -- Where "form" can be "while" or "for" or missing as below, if -- you place the "loop ... end loop;" construct on their own lines, -- you can comment out or experiment with different loop constructs more -- easily. declare Counter : Positive := Positive'First; -- This is 1. begin -- We can label loops so we can exit from them more easily if we need to. Infinite : loop IO.Put_Line ("[Infinite loop] Counter = " & Counter'Image); Counter := Counter + 1; -- This next line implements a repeat ... until or do ... while loop construct. -- Comment it out for an infinite loop. exit Infinite when Counter = 5; -- Equality tests use a single "=". end loop Infinite; -- Useful when implementing state machines. end; declare -- We don't have to have a label. Counter : Positive := Positive'First; -- This is 1. begin while Counter < 10 loop IO.Put_Line ("Counter = " & Counter'Image); Counter := Counter + 1; -- There is no explicit inc/decrement. -- Ada 2022 introduced @ for LHS, so the above would be written as -- Counter := @ + 1; -- Try it, -gnat2022. end loop; end; declare package Hue_IO is new IO.Enumeration_IO (Hues); -- We can have multiple packages on one line, but I tend to use one -- package per line for readability. use IO, Hue_IO; begin Put ("Hues : "); -- Note, no prefix. -- Because we are using the 'Range attribute, the compiler knows it is -- safe and can omit run-time checks here. for Hue in Hues'Range loop Put (Hue); -- Types and objects know about their bounds, their First .. Last -- values. These can be specified as range types. if Hue /= Hues'Last then -- The /= means "not equal to" like the -- maths symbol ≠. Put (", "); end if; end loop; IO.New_Line; end; -- All objects know their bounds, including strings. declare C : Character := Str (50); -- Warning caused and exception raised at -- runtime. -- The exception raised above can only be handled by an outer scope, -- see wikibook link below. begin null; -- We will never get to this point because of the above. end; exception when Constraint_Error => IO.Put_Line ("Caught the exception"); end LearnAdaInY; ``` Now, that's a lot of information for a basic intro to Ada, and I've only touched the surface, there's much more to look at in the references section below. I haven't even touched on dynamic memory allocation which includes [pools](https://ada-lang.io/docs/arm/AA-13/AA-13.11), this is because for the most part, Ada programs don't need it, you can do a lot without it. As I stated above, Ada barely looks like Pascal and if you look at the original [Green specification](https://apps.dtic.mil/sti/trecms/pdf/ADB950587.pdf) (Warning: Huge 4575 page scanned PDF - starting on page 460), it looks nothing like it at all (page 505 of that PDF). The above source code will compile, but also will give warnings showing the power of the strong static type system. ## Download this source If you already have the GNAT toolchain installed, you can cut and paste the above into a new file, e.g. ```learn-ada-in-y.ada``` and then run the following: ```bash $ gnatchop learn-ada-in-y.ada # This breaks the program into its specification ".ads" and body ".adb". $ gnatmake empty.adb # gnatmake takes care of compilation of all units and linking. $ gnatmake hello.adb $ gnatmake learnadainy.adb ``` Or, download [Alire](https://alire.ada.dev), copy it to somewhere in your PATH and then do the following: **N.B.** Alire will automatically install the toolchain for you if you don't have one installed and will ask you to select which you want to use. ```bash $ alr search learnadainy $ alr get learnadainy $ cd learnadainy $ alr run empty $ alr run hello $ alr run learnadainy ``` ## Further Reading * [Ada Programming Language](https://ada-lang.io) * [Ada 2022 Reference Manual](https://ada-lang.io/docs/arm) * [Ada Style Guide](https://ada-lang.io/docs/style-guide/Ada_Style_Guide) * [Learn more Ada/Spark at AdaCore's site](https://learn.adacore.com) ## References from the source above 1. [wikibook](https://en.wikibooks.org/wiki/Ada_Programming/Exceptions#Exception_handlers) 2. [C](https://ada-lang.io/docs/arm/AA-B/AA-B.3) 3. [Fortran](https://ada-lang.io/docs/arm/AA-B/AA-B.5/) 4. [COBOL](https://ada-lang.io/docs/arm/AA-B/AA-B.4/) 5. [dynamic length strings](https://ada-lang.io/docs/arm/AA-A/AA-A.4#Subclause_A.4.5) ### Multi-line comments Multi-line comments are not allowed as they are error prone. > Such comments would require a closing comment delimiter and this would again raise the dangers associated with the (unintentional) omission of the closing delimiter: entire sections of a program could be ignored by the compiler without the programmer realizing it > > [Ada 83 Rationale](http://archive.adaic.com/standards/83rat/html/ratl-02-01.html#2.1) ================================================ FILE: agda.md ================================================ --- name: Agda filename: learnagda.agda contributors: - ["pe200012", "https://github.com/pe200012"] --- Agda is a dependently typed functional programming language. It is an extension of Martin-Löf's Type Theory. In Agda, programs and proofs are written in the same language. In Agda, there is no separation between types and values: types can depend on values, and values can act as types. This allows you to encode logical invariants (like the length of a vector) directly into the type system, making Agda a powerful tool for both programming and theorem proving. Agda is heavily reliant on Unicode characters. Most editors (like Emacs or VS Code) support entering these via LaTeX-like abbreviations (e.g., `\to` for `→`, `\all` for `∀`, `\bN` for `ℕ`). To install Agda, you typically use Haskell's cabal or stack. See the [wiki](https://wiki.portal.chalmers.se/agda/pmwiki.php) for details. ```agda -- A module must have the same name as the file (excluding .agda) module learnagda where -- We can import other modules. -- Agda's standard library is commonly used, but here we will define -- the basics from scratch for educational purposes. -- Agda is a dependently typed functional programming language. -- It is strictly total: -- all programs must terminate, and all patterns must be matched. -- Agda logic relies heavily on the Curry-Howard correspondence: -- Propositions are Types -- Proofs are Programs -- Comments use double dashes for single lines. {- Multi-line comments are enclosed in braces and hyphens. -} -- Agda uses Unicode extensively. -- In the Emacs mode (or VS Code), you type these using LaTeX-like shortcuts: -- \to → -- \bN ℕ -- \== ≡ -- \all ∀ -- \:: ∷ -------------------------------------------------------------------------------- -- Datatypes and Pattern Matching -------------------------------------------------------------------------------- -- 'Set' is the type of types (similar to 'Type' in other languages). -- We define Booleans as an inductive data type. data Bool : Set where true : Bool false : Bool -- We can define functions using pattern matching. -- 'not' takes a Bool and returns a Bool. not : Bool → Bool -- The type signature is mandatory. not true = false not false = true -- Natural numbers (Peano encoding). -- This defines an infinite set of terms: zero, suc zero, -- suc (suc zero), ... data ℕ : Set where zero : ℕ suc : ℕ → ℕ -- We can tell Agda to treat ℕ as normal numbers for literals -- by using a pragma. {-# BUILTIN NATURAL ℕ #-} -- Addition defined recursively. -- Underscores denote where the arguments go for infix operators. -- This is Agda's "Mixfix" notation. You can put underscores anywhere! _+_ : ℕ → ℕ → ℕ zero + n = n suc m + n = suc (m + n) -- We can define precedence for operators. infixl 6 _+_ -- Example evaluation: -- 2 + 3 = 5 -- To verify this in an editor: -- Type "2 + 3", select it, and press C-c C-n (Compute Normal Form). -- Mixfix examples: -- if_then_else_ : Bool → A → A → A -- if true then x else y -------------------------------------------------------------------------------- -- Interaction and Holes -------------------------------------------------------------------------------- -- Before introducing other concepts, we need to introduce 'holes'. -- Agda development is interactive. -- You write types, and the system helps fill terms. -- A question mark ? or {! !} creates a "hole". -- example : 2 + 2 ≡ 4 -- example = ? -- While in Emacs/VS Code: -- C-c C-l : Load file (type checks). -- C-c C-space : Given a hole, ask Agda to fill it (Auto). -- C-c C-r : Refine. If the hole is for a data type, -- splits constructors. -- C-c C-, : Goal type and context. Tells you what you need to prove. -- POP QUIZ: Define multiplication for natural numbers. -- Hint: split cases, and then do induction. _*_ : ℕ → ℕ → ℕ x * y = ? -------------------------------------------------------------------------------- -- Polymorphism and Variables -------------------------------------------------------------------------------- -- In modern Agda, we can declare generalizable variables to avoid -- repetitive `forall` syntax in type signatures. variable A B : Set n m : ℕ -- Lists are parameterized by a type A. infixr 5 _::_ data List (A : Set) : Set where [] : List A -- Empty list _::_ : A → List A → List A -- Cons constructor -- A list of numbers: 1 :: 2 :: 3 :: [] nums : List ℕ nums = 1 :: 2 :: 3 :: [] -- Map function showing explicit universe polymorphism (optional) -- Here we use implicit arguments (denoted by { }). -- Agda infers them from context. -- ∀ {A B} makes A and B implicit type variables. map : ∀ {A B : Set} → (A → B) → List A → List B map f [] = [] map f (x :: xs) = f x :: map f xs -- Anonymous functions (lambdas) -- We can write `λ x → x + 1` plus1 : ℕ → ℕ plus1 = λ x → x + 1 -------------------------------------------------------------------------------- -- Dependent Types -------------------------------------------------------------------------------- -- Dependent types allow types to depend on values. -- A classic example is a Vector: a list with a fixed length -- encoded in its type. data Vec (A : Set) : ℕ → Set where [] : Vec A zero _::_ : ∀ {n} → A → Vec A n → Vec A (suc n) -- If we try to create a vector with the wrong length, it's a type error. vec3 : Vec ℕ 3 vec3 = 1 :: 2 :: 3 :: [] -- Because the length is known, we can define 'safe' operations. -- This function cannot be called on an empty vector. head : Vec A (suc n) → A head (x :: xs) = x -- We can calculate the exact type of a concatenation. _++_ : Vec A n → Vec A m → Vec A (n + m) [] ++ ys = ys (x :: xs) ++ ys = x :: (xs ++ ys) -------------------------------------------------------------------------------- -- Equality and Proofs -------------------------------------------------------------------------------- -- The identity type (equality) is the heart of proving in Agda. -- x ≡ y is a type that has a value only if x and y are the same normal form. infix 4 _≡_ data _≡_ {A : Set} (x : A) : A → Set where refl : x ≡ x {-# BUILTIN EQUALITY _≡_ #-} -- PROOFS ARE PROGRAMS -- To prove a property, we write a function that produces a value of that type. -- Proving 1 + 1 equals 2. 1+1≡2 : 1 + 1 ≡ 2 1+1≡2 = refl -- Congruence: applying a function to equal values yields equal results. cong : ∀ {A B : Set} (f : A → B) {x y : A} → x ≡ y → f x ≡ f y cong f refl = refl -- Symmetry sym : ∀ {A : Set} {x y : A} → x ≡ y → y ≡ x sym refl = refl -- Transitivity trans : ∀ {A : Set} {x y z : A} → x ≡ y → y ≡ z → x ≡ z trans refl refl = refl -- Proving associativity of addition. -- This requires induction on x. -- We split cases on x. -- If x is zero: zero + (y + z) ≡ zero + y + z -- reduces to y + z ≡ y + z. -- If x is suc x: we use the inductive hypothesis (recursion). +-assoc : ∀ (x y z : ℕ) → (x + y) + z ≡ x + (y + z) +-assoc zero y z = refl +-assoc (suc x) y z = let -- The inductive hypothesis ih = +-assoc x y z in -- We need to prove: suc (x + y) + z ≡ suc (x + (y + z)) -- Using congruence on the IH gives us exactly that. cong suc ih -- Agda provides a 'rewrite' keyword to simplify this. -- It pattern matches on the equality proof effectively replacing x with y. +-identity : (n : ℕ) → n + zero ≡ n +-identity zero = refl +-identity (suc n) rewrite +-identity n = refl -------------------------------------------------------------------------------- -- Equational Reasoning -------------------------------------------------------------------------------- -- Agda allows defining custom syntax to write proofs -- that look like calculations. -- This is similar to Lean's `calc` mode but defined within the language. module Reasoning {A : Set} where infix 1 begin_ infixr 2 _≡⟨⟩_ _≡⟨_⟩_ infix 3 _∎ begin_ : ∀ {x y : A} → x ≡ y → x ≡ y begin p = p _≡⟨⟩_ : ∀ (x : A) {y : A} → x ≡ y → x ≡ y x ≡⟨⟩ p = p _≡⟨_⟩_ : ∀ (x : A) {y z : A} → x ≡ y → y ≡ z → x ≡ z x ≡⟨ x≡y ⟩ y≡z = trans x≡y y≡z _∎ : ∀ (x : A) → x ≡ x x ∎ = refl open Reasoning -- Proof of associativity using reasoning syntax +-assoc' : ∀ (x y z : ℕ) → (x + y) + z ≡ x + (y + z) +-assoc' zero y z = refl +-assoc' (suc x) y z = begin (suc x + y) + z ≡⟨⟩ -- Definition of + suc (x + y) + z ≡⟨⟩ -- Definition of + suc ((x + y) + z) ≡⟨ cong suc (+-assoc' x y z) ⟩ suc (x + (y + z)) ≡⟨⟩ suc x + (y + z) ∎ -------------------------------------------------------------------------------- -- Inductive Relations -------------------------------------------------------------------------------- -- Relations can also be defined as inductive types. -- Here we define "less than or equal to" for natural numbers. data _≤_ : ℕ → ℕ → Set where z≤n : ∀ {n} → zero ≤ n s≤s : ∀ {m n} → m ≤ n → suc m ≤ suc n -- Proof that 2 ≤ 4 2≤4 : 2 ≤ 4 2≤4 = s≤s (s≤s z≤n) -------------------------------------------------------------------------------- -- Mutual Recursion: Even and Odd -------------------------------------------------------------------------------- -- We can define types that depend on each other using `mutual`. mutual data Even : ℕ → Set where zero : Even zero suc : ∀ {n} → Odd n → Even (suc n) data Odd : ℕ → Set where suc : ∀ {n} → Even n → Odd (suc n) mutual e+e≡e : ∀ {m n} → Even m → Even n → Even (m + n) e+e≡e zero en = en e+e≡e (suc om) en = suc (o+e≡o om en) o+e≡o : ∀ {m n} → Odd m → Even n → Odd (m + n) o+e≡o (suc em) en = suc (e+e≡e em en) -------------------------------------------------------------------------------- -- Records and Type Classes -------------------------------------------------------------------------------- -- Records are similar to structs. record Isomorphism (A B : Set) : Set where field to : A → B from : B → A from∘to : ∀ (x : A) → from (to x) ≡ x to∘from : ∀ (y : B) → to (from y) ≡ y -- Agda supports "Instance Arguments" via {{ }}. -- This works like Type Classes in Haskell or Lean. record Monoid (A : Set) : Set where field mempty : A _<>_ : A → A → A -- A function using the type class concat : ∀ {A : Set} {{m : Monoid A}} → List A → A concat {{m}} [] = Monoid.mempty m concat {{m}} (x :: xs) = Monoid._<>_ m x (concat {{m}} xs) -- Instances are defined like normal values but marked 'instance' instance natPlusMonoid : Monoid ℕ natPlusMonoid = record { mempty = 0 ; _<>_ = _+_ } -- Now we can use it implicitly sumList : ℕ sumList = concat (1 :: 2 :: 3 :: []) -- Result: 6 -------------------------------------------------------------------------------- -- Propositions as Types -------------------------------------------------------------------------------- data _×_ (A B : Set) : Set where -- AND _,_ : A → B → A × B data _⊎_ (A B : Set) : Set where -- OR inj₁ : A → A ⊎ B inj₂ : B → A ⊎ B data ⊥ : Set where -- FALSE -- No constructors -- Ex Falso Quodlibet: From falsehood, anything follows. -- We use an absurd pattern () to indicate this case is impossible. ⊥-elim : ∀ {A : Set} → ⊥ → A ⊥-elim () -- Negation is defined as "implies False". ¬_ : Set → Set ¬ A = A → ⊥ -- Example: Proving 1 is not equal to 0. -- We assume 1 ≡ 0 is true (argument eq), and show it leads to -- a contradiction. 1≢0 : ¬ (1 ≡ 0) 1≢0 () -- The pattern () automatically realizes that 1 ≡ 0 is an impossible match -- because the constructors 'suc' and 'zero' do not clash -- in the definition of ≡. -- Decidable Propositions -- A property P is decidable if we can compute whether it holds -- or not. data Dec (P : Set) : Set where yes : P → Dec P no : (P → ⊥) → Dec P -- Computable equality for Naturals _==_ : (n m : ℕ) → Dec (n ≡ m) zero == zero = yes refl zero == suc m = no λ() suc n == zero = no λ() suc n == suc m with n == m ... | yes p = yes (cong suc p) ... | no ¬p = no (λ { refl → ¬p refl }) ``` ## Further Reading * [PLFA (Programming Language Foundations in Agda)](https://plfa.github.io/) - Highly recommended deep dive. * [The Agda Wiki](https://wiki.portal.chalmers.se/agda/pmwiki.php) * [Agda Documentation](https://agda.readthedocs.io/en/latest/) * [Standard Library](https://github.com/agda/agda-stdlib) - The official standard library. ================================================ FILE: amd.md ================================================ --- category: tool name: AMD contributors: - ["Frederik Ring", "https://github.com/m90"] filename: learnamd.js --- ## Getting Started with AMD The **Asynchronous Module Definition** API specifies a mechanism for defining JavaScript modules such that the module and its dependencies can be asynchronously loaded. This is particularly well suited for the browser environment where synchronous loading of modules incurs performance, usability, debugging, and cross-domain access problems. ### Basic concept ```javascript // The basic AMD API consists of nothing but two methods: `define` and `require` // and is all about module definition and consumption: // `define(id?, dependencies?, factory)` defines a module // `require(dependencies, callback)` imports a set of dependencies and // consumes them in the passed callback // Let's start by using define to define a new named module // that has no dependencies. We'll do so by passing a name // and a factory function to define: define('awesomeAMD', function(){ var isAMDAwesome = function(){ return true; }; // The return value of a module's factory function is // what other modules or require calls will receive when // requiring our `awesomeAMD` module. // The exported value can be anything, (constructor) functions, // objects, primitives, even undefined (although that won't help too much). return isAMDAwesome; }); // Now, let's define another module that depends upon our `awesomeAMD` module. // Notice that there's an additional argument defining our // module's dependencies now: define('loudmouth', ['awesomeAMD'], function(awesomeAMD){ // dependencies will be passed to the factory's arguments // in the order they are specified var tellEveryone = function(){ if (awesomeAMD()){ alert('This is sOoOo rad!'); } else { alert('Pretty dull, isn\'t it?'); } }; return tellEveryone; }); // As we do know how to use define now, let's use `require` to // kick off our program. `require`'s signature is `(arrayOfDependencies, callback)`. require(['loudmouth'], function(loudmouth){ loudmouth(); }); // To make this tutorial run code, let's implement a very basic // (non-asynchronous) version of AMD right here on the spot: function define(name, deps, factory){ // notice how modules without dependencies are handled define[name] = require(factory ? deps : [], factory || deps); } function require(deps, callback){ var args = []; // first let's retrieve all the dependencies needed // by the require call for (var i = 0; i < deps.length; i++){ args[i] = define[deps[i]]; } // satisfy all the callback's dependencies return callback.apply(null, args); } // you can see this code in action here: http://jsfiddle.net/qap949pd/ ``` ### Real-world usage with require.js In contrast to the introductory example, `require.js` (the most popular AMD library) actually implements the **A** in **AMD**, enabling you to load modules and their dependencies asynchronously via XHR: ```javascript /* file: app/main.js */ require(['modules/someClass'], function(SomeClass){ // the callback is deferred until the dependency is loaded var thing = new SomeClass(); }); console.log('So here we are, waiting!'); // this will run first ``` By convention, you usually store one module in one file. `require.js` can resolve module names based on file paths, so you don't have to name your modules, but can simply reference them using their location. In the example `someClass` is assumed to be in the `modules` folder, relative to your configuration's `baseUrl`: * app/ * main.js * modules/ * someClass.js * someHelpers.js * ... * daos/ * things.js * ... This means we can define `someClass` without specifying a module id: ```javascript /* file: app/modules/someClass.js */ define(['daos/things', 'modules/someHelpers'], function(thingsDao, helpers){ // module definition, of course, will also happen asynchronously function SomeClass(){ this.method = function(){/**/}; // ... } return SomeClass; }); ``` To alter the default path mapping behavior use `requirejs.config(configObj)` in your `main.js`: ```javascript /* file: main.js */ requirejs.config({ baseUrl : 'app', paths : { // you can also load modules from other locations jquery : '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min', coolLibFromBower : '../bower_components/cool-lib/coollib' } }); require(['jquery', 'coolLibFromBower', 'modules/someHelpers'], function($, coolLib, helpers){ // a `main` file needs to call require at least once, // otherwise no code will ever run coolLib.doFancyStuffWith(helpers.transform($('#foo'))); }); ``` `require.js`-based apps will usually have a single entry point (`main.js`) that is passed to the `require.js` script tag as a data-attribute. It will be automatically loaded and executed on pageload: ```html A hundred script tags? Never again! ``` ### Optimizing a whole project using r.js Many people prefer using AMD for sane code organization during development, but still want to ship a single script file in production instead of performing hundreds of XHRs on page load. `require.js` comes with a script called `r.js` (that you will probably run in node.js, although Rhino is supported too) that can analyse your project's dependency graph, and build a single file containing all your modules (properly named), minified and ready for consumption. Install it using `npm`: ```shell $ npm install requirejs -g ``` Now you can feed it with a configuration file: ```shell $ r.js -o app.build.js ``` For our above example the configuration might look like: ```javascript /* file : app.build.js */ ({ name : 'main', // name of the entry point out : 'main-built.js', // name of the file to write the output to baseUrl : 'app', paths : { // `empty:` tells r.js that this should still be loaded from the CDN, using // the location specified in `main.js` jquery : 'empty:', coolLibFromBower : '../bower_components/cool-lib/coollib' } }) ``` To use the built file in production, simply swap `data-main`: ```html ``` An incredibly detailed [overview of build options](https://github.com/jrburke/r.js/blob/master/build/example.build.js) is available in the GitHub repo. ### Topics not covered in this tutorial * [Loader plugins / transforms](http://requirejs.org/docs/plugins.html) * [CommonJS style loading and exporting](http://requirejs.org/docs/commonjs.html) * [Advanced configuration](http://requirejs.org/docs/api.html#config) * [Shim configuration (loading non-AMD modules)](http://requirejs.org/docs/api.html#config-shim) * [CSS loading and optimizing with require.js](http://requirejs.org/docs/optimization.html#onecss) * [Using almond.js for builds](https://github.com/jrburke/almond) ### Further reading: * [Official Spec](https://github.com/amdjs/amdjs-api/wiki/AMD) * [Why AMD?](http://requirejs.org/docs/whyamd.html) * [Universal Module Definition](https://github.com/umdjs/umd) ### Implementations: * [require.js](http://requirejs.org) * [dojo toolkit](http://dojotoolkit.org/documentation/tutorials/1.9/modules/) * [cujo.js](http://cujojs.com/) * [curl.js](https://github.com/cujojs/curl) * [lsjs](https://github.com/zazl/lsjs) * [mmd](https://github.com/alexlawrence/mmd) ================================================ FILE: angularjs.md ================================================ --- category: framework name: AngularJS contributors: - ["Walter Cordero", "http://waltercordero.com"] filename: learnangular.txt --- ## AngularJS Tutorial. AngularJS version 1.0 was released in 2012. Miško Hevery, a Google employee, started to work with AngularJS in 2009. The idea turned out very well, and the project is now officially supported by Google. AngularJS is a JavaScript framework. It can be added to an HTML page with a "script" tag. AngularJS extends HTML attributes with Directives, and binds data to HTML with Expressions. ## What You Should Already Know Before you study AngularJS, you should have a basic understanding of: - HTML - CSS - JavaScript ```html // AngularJS is a JavaScript framework. It is a library written in JavaScript. // AngularJS is distributed as a JavaScript file, and can be added to a web page with a script tag: // /////////////////////////////////// // AngularJS Extends HTML //AngularJS extends HTML with ng-directives. //The ng-app directive defines an AngularJS application. //The ng-model directive binds the value of HTML controls (input, select, textarea) to application data. //The ng-bind directive binds application data to the HTML view.

Name:

/* * Example explained: * AngularJS starts automatically when the web page has loaded. * The ng-app directive tells AngularJS that the
element is the "owner" of an AngularJS application. * The ng-model directive binds the value of the input field to the application variable name. * The ng-bind directive binds the innerHTML of the

element to the application variable name. */ Here are content to be interpreted /////////////////////////////////// // AngularJS Expressions // AngularJS expressions are written inside double braces: {{ expression }}. // AngularJS expressions binds data to HTML the same way as the ng-bind directive. // AngularJS will "output" data exactly where the expression is written. // AngularJS expressions are much like JavaScript expressions: They can contain literals, operators, and variables. // Example {{ 5 + 5 }} or {{ firstName + " " + lastName }}

My first expression: {{ 5 + 5 }}

//If you remove the ng-app directive, HTML will display the expression as it is, without solving it:

My first expression: {{ 5 + 5 }}

// AngularJS expressions bind AngularJS data to HTML the same way as the ng-bind directive.

Name:

{{name}}

// AngularJS numbers are like JavaScript numbers:

Total in dollar: {{ quantity * cost }}

//AngularJS strings are like JavaScript strings:

The name is

//AngularJS objects are like JavaScript objects:

The name is {{ person.lastName }}

//AngularJS arrays are like JavaScript arrays:

The third result is {{ points[2] }}

// Like JavaScript expressions, AngularJS expressions can contain literals, operators, and variables. // Unlike JavaScript expressions, AngularJS expressions can be written inside HTML. // AngularJS expressions do not support conditionals, loops, and exceptions, while JavaScript expressions do. // AngularJS expressions support filters, while JavaScript expressions do not. /////////////////////////////////// // AngularJS Directives //AngularJS directives are extended HTML attributes with the prefix ng-. //The ng-app directive initializes an AngularJS application. //The ng-init directive initializes application data. //The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.

Name:

You wrote: {{ firstName }}

//Using ng-init is not very common. You will learn how to initialize data in the chapter about controllers. //The ng-repeat directive repeats an HTML element:
  • {{ x }}
//The ng-repeat directive used on an array of objects:
  • {{ x.name + ', ' + x.country }}
// AngularJS is perfect for database CRUD (Create Read Update Delete) applications. // Just imagine if these objects were records from a database. // The ng-app directive defines the root element of an AngularJS application. // The ng-app directive will auto-bootstrap (automatically initialize) the application when a web page is loaded. // Later you will learn how ng-app can have a value (like ng-app="myModule"), to connect code modules. // The ng-init directive defines initial values for an AngularJS application. // Normally, you will not use ng-init. You will use a controller or module instead. // You will learn more about controllers and modules later. //The ng-model directive binds the value of HTML controls (input, select, textarea) to application data. //The ng-model directive can also: //Provide type validation for application data (number, email, required). //Provide status for application data (invalid, dirty, touched, error). //Provide CSS classes for HTML elements. //Bind HTML elements to HTML forms. //The ng-repeat directive clones HTML elements once for each item in a collection (in an array). /////////////////////////////////// // AngularJS Controllers // AngularJS controllers control the data of AngularJS applications. // AngularJS controllers are regular JavaScript Objects. // AngularJS applications are controlled by controllers. // The ng-controller directive defines the application controller. // A controller is a JavaScript Object, created by a standard JavaScript object constructor.
First Name:
Last Name:

Full Name: {{firstName + " " + lastName}}
//Application explained: //The AngularJS application is defined by ng-app="myApp". The application runs inside the
. //The ng-controller="myCtrl" attribute is an AngularJS directive. It defines a controller. //The myCtrl function is a JavaScript function. //AngularJS will invoke the controller with a $scope object. //In AngularJS, $scope is the application object (the owner of application variables and functions). //The controller creates two properties (variables) in the scope (firstName and lastName). //The ng-model directives bind the input fields to the controller properties (firstName and lastName). //The example above demonstrated a controller object with two properties: lastName and firstName. //A controller can also have methods (variables as functions):
First Name:
Last Name:

Full Name: {{fullName()}}
//In larger applications, it is common to store controllers in external files. //Just copy the code between the tags into an external file named personController.js:
First Name:
Last Name:

Full Name: {{firstName + " " + lastName}}
// For the next example we will create a new controller file: angular.module('myApp', []).controller('namesCtrl', function($scope) { $scope.names = [ {name:'Jani',country:'Norway'}, {name:'Hege',country:'Sweden'}, {name:'Kai',country:'Denmark'} ]; }); //Save the file as namesController.js: //And then use the controller file in an application:
  • {{ x.name + ', ' + x.country }}
/////////////////////////////////// // AngularJS Filters // Filters can be added to expressions and directives using a pipe character. // AngularJS filters can be used to transform data: - **currency**: Format a number to a currency format. - **filter**: Select a subset of items from an array. - **lowercase**: Format a string to lower case. - **orderBy**: Orders an array by an expression. - **uppercase**: Format a string to upper case. //A filter can be added to an expression with a pipe character (|) and a filter. //(For the next two examples we will use the person controller from the previous chapter) //The uppercase filter format strings to upper case:

The name is {{ lastName | uppercase }}

//The lowercase filter format strings to lower case:

The name is {{ lastName | lowercase }}

//The currency filter formats a number as currency:

Total = {{ (quantity * price) | currency }}

//A filter can be added to a directive with a pipe character (|) and a filter. //The orderBy filter orders an array by an expression:
  • {{ x.name + ', ' + x.country }}
//An input filter can be added to a directive with a pipe character (|) //and filter followed by a colon and a model name. //The filter selects a subset of an array:

  • {{ (x.name | uppercase) + ', ' + x.country }}
/////////////////////////////////// // AngularJS AJAX - $http //$http is an AngularJS service for reading data from remote servers. // The following data can be provided by a web server: // http://www.w3schools.com/angular/customers.php // **Check the URL to see the data format** // AngularJS $http is a core service for reading data from web servers. // $http.get(url) is the function to use for reading server data.
  • {{ x.Name + ', ' + x.Country }}
Application explained: // The AngularJS application is defined by ng-app. The application runs inside a
. // The ng-controller directive names the controller object. // The customersCtrl function is a standard JavaScript object constructor. // AngularJS will invoke customersCtrl with a $scope and $http object. // $scope is the application object (the owner of application variables and functions). // $http is an XMLHttpRequest object for requesting external data. // $http.get() reads JSON data from http://www.w3schools.com/angular/customers.php. // If success, the controller creates a property (names) in the scope, with JSON data from the server. // Requests for data from a different server (than the requesting page), are called cross-site HTTP requests. // Cross-site requests are common on the web. Many pages load CSS, images, and scripts from different servers. // In modern browsers, cross-site HTTP requests from scripts are restricted to same site for security reasons. // The following line, in our PHP examples, has been added to allow cross-site access. header("Access-Control-Allow-Origin: *"); /////////////////////////////////// // AngularJS Tables // Displaying tables with angular is very simple:
{{ x.Name }} {{ x.Country }}
// To sort the table, add an orderBy filter:
{{ x.Name }} {{ x.Country }}
// To display the table index, add a with $index:
{{ $index + 1 }} {{ x.Name }} {{ x.Country }}
// Using $even and $odd
{{ x.Name }} {{ x.Name }} {{ x.Country }} {{ x.Country }}
/////////////////////////////////// // AngularJS HTML DOM //AngularJS has directives for binding application data to the attributes of HTML DOM elements. // The ng-disabled directive binds AngularJS application data to the disabled attribute of HTML elements.

Button

//Application explained: // The ng-disabled directive binds the application data mySwitch to the HTML button's disabled attribute. // The ng-model directive binds the value of the HTML checkbox element to the value of mySwitch. // If the value of mySwitch evaluates to true, the button will be disabled:

// If the value of mySwitch evaluates to false, the button will not be disabled:

// The ng-show directive shows or hides an HTML element.

I am visible.

I am not visible.

// The ng-show directive shows (or hides) an HTML element based on the value of ng-show. // You can use any expression that evaluates to true or false:

I am visible.

/////////////////////////////////// // AngularJS Events // AngularJS has its own HTML events directives. // The ng-click directive defines an AngularJS click event.

{{ count }}

// The ng-hide directive can be used to set the visibility of a part of an application. // The value ng-hide="true" makes an HTML element invisible. // The value ng-hide="false" makes the element visible.

First Name:
Last Name:

Full Name: {{firstName + " " + lastName}}

//Application explained: // The first part of the personController is the same as in the chapter about controllers. // The application has a default property (a variable): $scope.myVar = false; // The ng-hide directive sets the visibility, of a

element with two input fields, // according to the value (true or false) of myVar. // The function toggle() toggles myVar between true and false. // The value ng-hide="true" makes the element invisible. // The ng-show directive can also be used to set the visibility of a part of an application. // The value ng-show="false" makes an HTML element invisible. // The value ng-show="true" makes the element visible. // Here is the same example as above, using ng-show instead of ng-hide:

First Name:
Last Name:

Full Name: {{firstName + " " + lastName}}

/////////////////////////////////// // AngularJS Modules // An AngularJS module defines an application. // The module is a container for the different parts of an application. // The module is a container for the application controllers. // Controllers always belong to a module. // This application ("myApp") has one controller ("myCtrl"):
{{ firstName + " " + lastName }}
// It is common in AngularJS applications to put the module and the controllers in JavaScript files. // In this example, "myApp.js" contains an application module definition, while "myCtrl.js" contains the controller:
{{ firstName + " " + lastName }}
//myApp.js var app = angular.module("myApp", []); // The [] parameter in the module definition can be used to define dependent modules. // myCtrl.js app.controller("myCtrl", function($scope) { $scope.firstName = "John"; $scope.lastName= "Doe"; }); // Global functions should be avoided in JavaScript. They can easily be overwritten // or destroyed by other scripts. // AngularJS modules reduces this problem, by keeping all functions local to the module. // While it is common in HTML applications to place scripts at the end of the // element, it is recommended that you load the AngularJS library either // in the or at the start of the . // This is because calls to angular.module can only be compiled after the library has been loaded.
{{ firstName + " " + lastName }}
/////////////////////////////////// // AngularJS Applications // AngularJS modules define AngularJS applications. // AngularJS controllers control AngularJS applications. // The ng-app directive defines the application, the ng-controller directive defines the controller.
First Name:
Last Name:

Full Name: {{firstName + " " + lastName}}
// AngularJS modules define applications: var app = angular.module('myApp', []); // AngularJS controllers control applications: app.controller('myCtrl', function($scope) { $scope.firstName= "John"; $scope.lastName= "Doe"; }); ``` ## Source & References **Examples** - [http://www.w3schools.com/angular/angular_examples.asp](http://www.w3schools.com/angular/angular_examples.asp) **References** - [http://www.w3schools.com/angular/angular_ref_directives.asp](http://www.w3schools.com/angular/angular_ref_directives.asp) - [http://www.w3schools.com/angular/default.asp](http://www.w3schools.com/angular/default.asp) - [https://teamtreehouse.com/library/angular-basics/](https://teamtreehouse.com/library/angular-basics/) ================================================ FILE: ansible.md ================================================ --- category: tool name: Ansible contributors: - ["Jakub Muszynski" , "http://github.com/sirkubax"] - ["Pat Myron" , "https://github.com/patmyron"] - ["Divay Prakash", "https://github.com/divayprakash"] filename: LearnAnsible.txt --- ## Introduction ```yaml --- "{{ Ansible }}" is an orchestration tool written in Python. ... ``` Ansible is (one of many) orchestration tools. It allows you to control your environment (infrastructure and code) and automate the manual tasks. Ansible has great integration with multiple operating systems (even Windows) and some hardware (switches, Firewalls, etc). It has multiple tools that integrate with the cloud providers. Almost every noteworthy cloud provider is present in the ecosystem (AWS, Azure, Google, DigitalOcean, OVH, etc...). But ansible is way more! It provides execution plans, an API, library, and callbacks. ### Main pros and cons #### Pros * It is an agent-less tool. In most scenarios, it uses ssh as a transport layer. In some way you can use it as 'bash on steroids'. * It is very easy to start. If you are familiar with the concept of ssh - you already know Ansible (ALMOST). * It executes 'as is' - other tools (salt, puppet, chef - might execute in different scenario than you would expect) * Documentation is at the world-class standard! * Writing your own modules and extensions is fairly easy. * Ansible AWX is the open source version of Ansible Tower we have been waiting for, which provides an excellent UI. #### Cons * It is an agent-less tool - every agent consumes up to 16MB ram - in some environments, it may be noticeable amount. * It is agent-less - you have to verify your environment consistency 'on-demand' - there is no built-in mechanism that would warn you about some change automatically (this can be achieved with reasonable effort) * Official GUI - Ansible Tower - is great but expensive. * There is no 'small enterprise' payment plan, however Ansible AWX is the free open source version we were all waiting for. #### Neutral Migration - Ansible <-> Salt is fairly easy - so if you would need an event-driven agent environment - it would be a good choice to start quick with Ansible, and convert to Salt when needed. #### Some concepts Ansible uses ssh or paramiko as a transport layer. In a way you can imagine that you are using a ssh with API to perform your action. The simplest way is to execute remote command in more controlled way (still using ssh). On the other hand - in advanced scope - you can wrap Ansible (use python Ansible code as a library) with your own Python scripts! It would act a bit like Fabric then. ## Example An example playbook to install apache and configure log level ```yaml --- - hosts: apache vars: apache2_log_level: "warn" handlers: - name: restart apache service: name: apache2 state: restarted enabled: True notify: - Wait for instances to listen on port 80 become: True - name: reload apache service: name: apache2 state: reloaded notify: - Wait for instances to listen on port 80 become: True - name: Wait for instances to listen on port 80 wait_for: state: started host: localhost port: 80 timeout: 15 delay: 5 tasks: - name: Update cache apt: update_cache: yes cache_valid_time: 7200 become: True - name: Install packages apt: name={{ item }} with_items: - apache2 - logrotate notify: - restart apache become: True - name: Configure apache2 log level lineinfile: dest: /etc/apache2/apache2.conf line: "LogLevel {{ apache2_log_level }}" regexp: "^LogLevel" notify: - reload apache become: True ... ``` ## Installation ```bash # Universal way $ pip install ansible # Debian, Ubuntu $ apt-get install ansible ``` * [Appendix A - How do I install ansible](#infrastructure-as-a-code) * [Additional Reading.](http://docs.ansible.com/ansible/latest/intro_installation.html) ### Your first ansible command (shell execution) ```bash # Command pings localhost (defined in default inventory: /etc/ansible/hosts) $ ansible -m ping localhost # You should see this output localhost | SUCCESS => { "changed": false, "ping": "pong" } ``` ### Shell Commands There are few commands you should know about * `ansible` (to run modules in CLI) * `ansible-playbook` (to run playbooks) * `ansible-vault` (to manage secrets) * `ansible-galaxy` (to install roles from github/galaxy) ### Module A program (usually python) that executes, does some work and returns proper JSON output. This program performs specialized task/action (like manage instances in the cloud, execute shell command). The simplest module is called `ping` - it just returns a JSON with `pong` message. Example of modules: * Module: `ping` - the simplest module that is useful to verify host connectivity * Module: `shell` - a module that executes a shell command on a specified host(s). ```bash $ ansible -m ping all $ ansible -m shell -a 'date; whoami' localhost #hostname_or_a_group_name ``` * Module: `command` - executes a single command that will not be processed through the shell, so variables like `$HOME` or operands like ``|` `;`` will not work. The command module is more secure, because it will not be affected by the user’s environment. For more complex commands - use shell module. ```bash $ ansible -m command -a 'date; whoami' # FAILURE $ ansible -m command -a 'date' all $ ansible -m command -a 'whoami' all ``` * Module: `file` - performs file operations (stat, link, dir, ...) * Module: `raw` - executes a low-down and dirty SSH command, not going through the module subsystem (useful to install python2.7) ### Task Execution of a single Ansible **module** is called a **task**. The simplest module is called `ping` as you could see above. Another example of the module that allows you to execute a command remotely on multiple resources is called `shell`. See above how you were using them already. ### Playbook **Execution plan** written in a form of script file(s) is called **playbook**. Playbooks consist of multiple elements - * a list (or group) of hosts that 'the play' is executed against * `task(s)` or `role(s)` that are going to be executed * multiple optional settings (like default variables, and way more) Playbook script language is YAML. You can think that playbook is very advanced CLI script that you are executing. #### Example of the playbook This example-playbook would execute (on all hosts defined in inventory) two tasks: * `ping` that would return message *pong* * `shell` that execute three commands and return the output to our terminal ```yaml - hosts: all tasks: - name: "ping all" ping: - name: "execute a shell command" shell: "date; whoami; df -h;" ``` Run the playbook with the command: ```bash $ ansible-playbook path/name_of_the_playbook.yml ``` Note: Example playbook is explained in the next chapter: 'Roles' ### More on ansible concept ### Inventory An inventory is a set of objects or hosts, against which we are executing our playbooks or single tasks via shell commands. For these few minutes, let's assume that we are using the default ansible inventory (which in Debian based system is placed in `/etc/ansible/hosts`). ``` localhost [some_group] hostA.mydomain.com hostB.localdomain 1.2.3.4 [a_group_of_a_groups:children] some_group some_other_group ``` * [Additional Reading.](http://docs.ansible.com/ansible/latest/intro_inventory.html) ### ansible-roles (a 'template-playbooks' with right structure) You already know that the tasks (modules) can be run via CLI. You also know the playbooks - the execution plans of multiple tasks (with variables and logic). A concept called `role` was introduced for parts of the code (playbooks) that should be reusable. **Role** is a structured way to manage your set of tasks, variables, handlers, default settings, and way more (meta, files, templates). Roles allow reusing the same parts of code in multiple playbooks (you can parametrize the role 'further' during its execution). Its a great way to introduce `object oriented` management for your applications. Role can be included in your playbook (executed via your playbook). ```yaml - hosts: all tasks: - name: "ping all" ping: - name: "execute a shell command" shell: "date; whoami; df -h;" roles: - some_role - { role: another_role, some_variable: 'learnxiny', tags: ['my_tag'] } pre_tasks: - name: some pre-task shell: echo 'this task is the last, but would be executed before roles, and before tasks' ``` #### For remaining examples we would use additional repository This example installs ansible in `virtualenv` so it is independent from the system. You need to initialize it into your shell-context with the `source environment.sh` command. We are going to use this repository with examples: [https://github.com/sirkubax/ansible-for-learnXinYminutes](https://github.com/sirkubax/ansible-for-learnXinYminutes) ```bash $ # The following example contains a shell-prompt to indicate the venv and relative path $ git clone git@github.com:sirkubax/ansible-for-learnXinYminutes.git user@host:~/$ cd ansible-for-learnXinYminutes user@host:~/ansible-for-learnXinYminutes$ source environment.sh $ $ # First lets execute the simple_playbook.yml (venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/simple_playbook.yml ``` Run the playbook with roles example ```bash $ source environment.sh $ # Now we would run the above playbook with roles (venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/simple_role.yml ``` #### Role directory structure ``` roles/ some_role/ defaults/ # contains default variables files/ # for static files templates/ # for jinja templates tasks/ # tasks handlers/ # handlers vars/ # more variables (higher priority) meta/ # meta - package (role) info ``` #### Role Handlers Handlers are tasks that can be triggered (notified) during execution of a playbook, but they execute at the very end of a playbook. It is the best way to restart a service, check if the application port is active (successful deployment criteria), etc. Get familiar with how you can use roles in the simple_apache_role example ``` playbooks/roles/simple_apache_role/ ├── tasks │ └── main.yml └── templates └── main.yml ``` ### ansible - variables Ansible is flexible - it has 21 levels of variable precedence. [read more](http://docs.ansible.com/ansible/latest/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable) For now you should know that CLI variables have the top priority. You should also know, that a nice way to pool some data is a **lookup** ### Lookups Awesome tool to query data from various sources!!! Awesome! query from: * pipe (load shell command output into variable!) * file * stream * etcd * password management tools * url ```bash # read playbooks/lookup.yml # then run (venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/lookup.yml ``` You can use them in CLI too ```yaml ansible -m shell -a 'echo "{{ my_variable }}"' -e 'my_variable="{{ lookup("pipe", "date") }}"' localhost ansible -m shell -a 'echo "{{ my_variable }}"' -e 'my_variable="{{ lookup("pipe", "hostname") }}"' all # Or use in playbook (venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/lookup.yml ``` ### Register and Conditional #### Register Another way to dynamically generate the variable content is the `register` command. `Register` is also useful to store an output of a task and use its value for executing further tasks. ``` (venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/register_and_when.yml ``` ```yaml --- - hosts: localhost tasks: - name: check the system capacity shell: df -h / register: root_size - name: debug root_size debug: msg: "{{ root_size }}" - name: debug root_size return code debug: msg: "{{ root_size.rc }}" # when: example - name: Print this message when return code of 'check the system capacity' was ok debug: msg: "{{ root_size.rc }}" when: root_size.rc == 0 ... ``` #### Conditionals - when: You can define complex logic with Ansible and Jinja functions. Most common is usage of `when:`, with some variable (often dynamically generated in previous playbook steps with `register` or `lookup`) ```yaml --- - hosts: localhost tasks: - name: check the system capacity shell: df -h / when: some_variable in 'a string' roles: - { role: mid_nagios_probe, when: allow_nagios_probes } ... ``` ### ansible - tags, limit You should know about a way to increase efficiency by this simple functionality #### TAGS You can tag a task, role (and its tasks), include, etc, and then run only the tagged resources ``` ansible-playbook playbooks/simple_playbook.yml --tags=tagA,tag_other ansible-playbook playbooks/simple_playbook.yml -t tagA,tag_other There are special tags: always --skip-tags can be used to exclude a block of code --list-tags to list available tags ``` [Read more](http://docs.ansible.com/ansible/latest/playbooks_tags.html) #### LIMIT You can limit an execution of your tasks to defined hosts ``` ansible-playbook playbooks/simple_playbook.yml --limit localhost --limit my_hostname --limit groupname --limit some_prefix* --limit hostname:group #JM ``` ### Templates Templates are a powerful way to deliver some (partially) dynamic content. Ansible uses **Jinja2** language to describe the template. ``` Some static content {{ a_variable }} {% for item in loop_items %} this line item is {{ item }} {% endfor %} ``` Jinja may have some limitations, but it is a powerful tool that you might like. Please examine this simple example that installs apache2 and generates index.html from the template "playbooks/roles/simple_apache_role/templates/index.html" ```bash $ source environment.sh $ # Now we would run the above playbook with roles (venv) user@host:~/ansible-for-learnXinYminutes$ ansible-playbook playbooks/simple_role.yml --tags apache2 ``` #### Jinja2 CLI You can use the jinja in the CLI too ```bash ansible -m shell -a 'echo {{ my_variable }}' -e 'my_variable=something, playbook_parameter=twentytwo' localhost ``` In fact - jinja is used to template parts of the playbooks too ```yaml # check part of this playbook: playbooks/roles/sys_debug/tasks/debug_time.yml - local_action: shell date +'%F %T' register: ts become: False changed_when: False - name: Timestamp debug: msg="{{ ts.stdout }}" when: ts is defined and ts.stdout is defined become: False ``` #### Jinja2 filters Jinja is powerful. It has many built-in useful functions. ``` # get first item of the list {{ some_list | first() }} # if variable is undefined - use default value {{ some_variable | default('default_value') }} ``` [Read More](http://docs.ansible.com/ansible/latest/playbooks_filters.html) ### ansible-vault To maintain **infrastructure as code** you need to store secrets. Ansible provides a way to encrypt confidential files so you can store them in the repository, yet the files are decrypted on-the-fly during ansible execution. The best way to use it is to store the secret in some secure location, and configure ansible to use them during runtime. ```bash # Try (this would fail) $ ansible-playbook playbooks/vault_example.yml $ echo some_very_very_long_secret > ~/.ssh/secure_located_file # in ansible.cfg set the path to your secret file $ vi ansible.cfg ansible_vault_password_file = ~/.ssh/secure_located_file #or use env $ export ANSIBLE_VAULT_PASSWORD_FILE=~/.ssh/secure_located_file $ ansible-playbook playbooks/vault_example.yml # encrypt the file $ ansible-vault encrypt path/somefile # view the file $ ansible-vault view path/somefile # check the file content: $ cat path/somefile # decrypt the file $ ansible-vault decrypt path/somefile ``` ### dynamic inventory You might like to know, that you can build your inventory dynamically. (For Ansible) inventory is just JSON with proper structure - if you can deliver that to ansible - anything is possible. You do not need to reinvent the wheel - there are plenty of ready to use inventory scripts for the most popular Cloud providers and a lot of in-house popular usecases. [AWS example](http://docs.ansible.com/ansible/latest/intro_dynamic_inventory.html#example-aws-ec2-external-inventory-script) ```bash $ etc/inv/ec2.py --refresh $ ansible -m ping all -i etc/inv/ec2.py ``` [Read more](http://docs.ansible.com/ansible/latest/intro_dynamic_inventory.html) ### ansible profiling - callback Playbook execution takes some time. It is OK. First make it run, then you may like to speed things up. Since ansible 2.x there is built-in callback for task execution profiling. ``` vi ansible.cfg # set this to: callback_whitelist = profile_tasks ``` ### facts-cache and ansible-cmdb You can pull some information about your environment from another host. If the information does not change - you may consider using a facts_cache to speed things up. ``` vi ansible.cfg # if set to a persistent type (not 'memory', for example 'redis') fact values # from previous runs in Ansible will be stored. This may be useful when # wanting to use, for example, IP information from one group of servers # without having to talk to them in the same playbook run to get their # current IP information. fact_caching = jsonfile fact_caching_connection = ~/facts_cache fact_caching_timeout = 86400 ``` I like to use `jsonfile` as my backend. It allows to use another project `ansible-cmdb` [(project on GitHub)](https://github.com/fboender/ansible-cmdb) that generates a HTML page of your inventory resources. A nice 'free' addition! ### Debugging ansible [chapter in progress] When your job fails - it is good to be effective with debugging. 1. Increase verbosity by using multiple -v **[ -vvvvv]** 2. If variable is undefined - `grep -R path_of_your_inventory -e missing_variable` 3. If variable (dictionary or a list) is undefined - `grep -R path_of_your_inventory -e missing_variable` 4. Jinja template debug 5. Strange behaviour - try to run the code 'at the destination' ### Infrastructure as code You already know, that ansible-vault allows you to store your confidential data along with your code. You can go further - and define your ansible installation and configuration as code. See `environment.sh` to learn how to install the ansible itself inside a `virtualenv` that is not attached to your operating system (can be changed by non-privileged user), and as additional benefit - upgrading version of ansible is as easy as installing new version in new virtualenv. What is more, you can have multiple versions of Ansible present at the same time. ```bash # recreate ansible 2.x venv $ rm -rf venv2 $ source environment2.sh # execute playbook (venv2)$ ansible-playbook playbooks/ansible1.9_playbook.yml # would fail - deprecated syntax # now lets install ansible 1.9.x next to ansible 2.x (venv2)$ deactivate $ source environment.1.9.sh # execute playbook (venv1.9)$ ansible-playbook playbooks/ansible1.9_playbook.yml # works! # please note that you have both venv1.9 and venv2 present - you need to (de)activate one - that is all ``` #### become-user, become In Ansible - to become `sudo` - use the `become` parameter. Use `become_user` to specify the username. ``` - name: Ensure the httpd service is running service: name: httpd state: started become: true ``` Note: You may like to execute Ansible with `--ask-sudo-pass` or add the user to sudoers file in order to allow non-supervised execution if you require 'admin' privileges. [Read more](http://docs.ansible.com/ansible/latest/become.html) ## Tips and tricks #### --check -C Always make sure that your playbook can execute in 'dry run' mode (--check), and its execution is not declaring 'Changed' objects. #### --diff -D Diff is useful to see nice detail of the files changed. It compare 'in memory' the files like `diff -BbruN fileA fileB`. #### Execute hosts with 'regex' ```bash ansible -m ping web* ``` #### Host groups can be joined, negated, etc ```bash ansible -m ping web*:!backend:monitoring:&allow_change ``` #### Tagging You should tag some (not all) objects - a task in a playbook, all tasks included form a role, etc. It allows you to execute the chosen parts of the playbook. #### no_logs: True You may see, that some roles print a lot of output in verbose mode. There is also a debug module. This is the place where credentials may leak. Use `no_log` to hide the output. #### Debug module allows to print a value to the screen - use it! #### Register the output of a task You can register the output (stdout), rc (return code), stderr of a task with the `register` command. #### Conditionals: when: #### Loop: with, with\_items, with\_dict, with\_together [Read more](http://docs.ansible.com/ansible/latest/playbooks_conditionals.html) ## Additional Resources * [Servers For Hackers: An Ansible Tutorial](https://serversforhackers.com/c/an-ansible-tutorial) * [A system administrator's guide to getting started with Ansible - FAST!](https://www.redhat.com/en/blog/system-administrators-guide-getting-started-ansible-fast) * [Ansible Tower](https://www.ansible.com/products/tower) - Ansible Tower provides a web UI, dashboard and rest interface to ansible. * [Ansible AWX](https://github.com/ansible/awx) - The Open Source version of Ansible Tower. * [Ansible Tutorial for Beginners: Ultimate Playbook & Examples](https://spacelift.io/blog/ansible-tutorial) ================================================ FILE: apl.md ================================================ --- name: APL contributors: - ["nooodl", "https://github.com/nooodl"] filename: learnapl.apl --- ```apl ⍝ Comments in APL are prefixed by ⍝. ⍝ A list of numbers. (¯ is negative) 2 3e7 ¯4 50.3 ⍝ An expression, showing some functions. In APL, there's ⍝ no order of operations: everything is parsed right-to- ⍝ left. This is equal to 5 + (4 × (2 ÷ (5 - 3))) = 9: 5 + 4 × 2 ÷ 5 - 3 ⍝ 9 ⍝ These functions work on lists, too: 1 2 3 4 × 5 ⍝ 5 10 15 20 1 2 3 4 × 5 6 7 8 ⍝ 5 12 21 32 ⍝ All functions have single-argument and dual-argument ⍝ meanings. For example, "×" applied to two arguments ⍝ means multiply, but when applied to only a right-hand ⍝ side, it returns the sign: × ¯4 ¯2 0 2 4 ⍝ ¯1 ¯1 0 1 1 ⍝ Values can be compared using these operators (1 means ⍝ "true", 0 means "false"): 10 20 30 = 10 20 99 ⍝ 1 1 0 10 20 30 < 10 20 99 ⍝ 0 0 1 ⍝ "⍳n" returns a vector containing the first n naturals. ⍝ Matrices can be constructed using ⍴ (reshape): 4 3 ⍴ ⍳5 ⍝ 0 1 2 ⍝ 3 4 0 ⍝ 1 2 3 ⍝ 4 0 1 ⍝ Single-argument ⍴ gives you the dimensions back: ⍴ 4 3 ⍴ ⍳5 ⍝ 4 3 ⍝ Values can be stored using ←. Let's calculate the mean ⍝ value of a vector of numbers: A ← 10 60 55 23 ⍝ Sum of elements of A (/ is reduce): +/A ⍝ 148 ⍝ Length of A: ⍴A ⍝ 4 ⍝ Mean: (+/A) ÷ (⍴A) ⍝ 37 ⍝ We can define this as a function using {} and ⍵: mean ← {(+/⍵)÷⍴⍵} mean A ⍝ 37 ``` ## Further Reading - [APL Wiki](https://aplwiki.com/) - An older version of APL book by the creator: [Kenneth Iverson - A Programming Language](https://archive.org/details/aprogramminglanguage1962) - Additional Books: [APL Books](https://aplwiki.com/wiki/Books) ================================================ FILE: ar/html.md ================================================ --- contributors: - ["Christophe THOMAS", "https://github.com/WinChris"] translators: - ["Ader", "https://github.com/y1n0"] --- HTML اختصار ل HyperText Markup Language، أي "لغة ترميز النص التشعبي". هي لغة تمكننا من كتابة صفحات موجهة لشبكة الويب العالمي. هي لغة توصيف للنص، تسمح بكتابة صفحات ويب عن طريق تحديد كيفية عرض النصوص والمعلومات. في الحقيقة، ملفات html هي ملفات تحتوي على نصوص بسيطة. ما هو توصيف النص هذا؟ هو طريقة لتنظيم معلومات النص عن طريق إحاطته بوُسوم فتح ووسوم غلق. هذه الوسوم تعطي معاني محددة للنص الذي تحيطه. كباقي لغات الحاسوب، هناك الكثير من إصدارات HTML. سنتحدث هنا عن HTLM5. **ملاحظة:** يمكنك تجريب مختلف الوسوم والعناصر بينما تقرأ الدرس عبر موقع كـ [codepen](http://codepen.io/pen/) حتى ترى تأثيرها وتعرف كيف تعمل وتتعود على استعمالها. هذه المادة تُعنى أساسا بتركيب HTML .وبعض النصائح المفيدة ```html موقعي

مرحبا بالعالم!

الق نظرة كيف يبدو هذا من هنا

هذه فقرة.

هذه فقرة أخرى.

  • هذا عنصر من لائحة غير مرقمة. (لائحة بالعرائض)
  • هذا عنصر آخر
  • وهذا آخر عنصر في اللائحة
موقعي

مرحبا بالعالم!

ألق نظرة كيف يبدو هذا من هنا

هذه فقرة.

هذه فقرة أخرى.

  • هذا عنصر من لائحة غير مرقمة. (لائحة بالعرائض)
  • هذا عنصر آخر
  • وهذا آخر عنصر في اللائحة
العنوان الأول العنوان الثاني
الصف الأول، العمود الأول الصف الأول، العمود الثاني
الصف الثاني، العمود الأول الصف الثاني، العمود الأول
``` ## الاستعمال HTML يُكتب في ملفات تنتهي بـ `.html`. ## لمعرفة المزيد * [wikipedia](https://en.wikipedia.org/wiki/HTML) * [HTML tutorial](https://developer.mozilla.org/en-US/docs/Web/HTML) * [W3School](http://www.w3schools.com/html/html_intro.asp) ================================================ FILE: ar/python.md ================================================ --- contributors: - ["Louie Dinh", "http://pythonpracticeprojects.com"] - ["Steven Basart", "http://github.com/xksteven"] - ["Andre Polykanine", "https://github.com/Oire"] - ["Zachary Ferguson", "http://github.com/zfergus2"] - ["evuez", "http://github.com/evuez"] - ["Rommel Martinez", "https://ebzzry.io"] - ["Roberto Fernandez Diaz", "https://github.com/robertofd1995"] translators: - ["Ahmad Hegazy", "https://github.com/ahegazy"] --- لقد أُنشئت لغة البايثون بواسطة جايدو ڤان روسم في بداية التسعينات. هي الأن أحد أشهر اللغات الموجودة. لقد أحببت لغة البايثون بسبب وضوحها. هي في الأساس عبارة عن سودوكود قابل للتنفيذ. ملحوظة: هذا المقال يُطبق على بايثون 3 فقط. راجع المقال [هنا](../pythonlegacy/) إذا أردت تعلم لغة البايثون نسخة 2.7 الأقدم ```python # تعليق من سطر واحد يبدأ برمز الرقم. """ يمكن كتابة تعليق يتكون من أكثر من سطر باستخدام ثلاثة علامات " ، وعادة يُستخدم في كتابة التوثيقات. """ #################################################### ## 1. أنواع البيانات البدائية والعمليات #################################################### # لديك أرقام 3 # => 3 # العمليات الحسابية هي ما تتوقعه 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 # نتائج قسمة الأرقام الصحيحية تُقرب للأصغر سواءًا كانت الأرقام موجبة أو سالبة. 5 // 3 # => 1 5.0 // 3.0 # => 1.0 # يعمل في حالة الكسور أيضا -5 // 3 # => -2 -5.0 // 3.0 # => -2.0 # ناتج القسمة هو دائما كسر 10.0 / 3 # => 3.3333333333333335 # عملية باقي القسمة 7 % 3 # => 1 # الأُس (س ** ص، رفع س لقوى ص) 2**3 # => 8 # أفرض ترتيب العمليات الحسابية بالأقواس (1 + 3) * 2 # => 8 # القيم الثنائية هي المعروفة عموما (ﻻحظ: تكبير أول حرف) True False # أنفي بـ (not) not True # => False not False # => True # العمليات على القيم الثنائية # ﻻحظ ﻻيهم حالة الحرف (كبير أو صغير) في "and" و "or" True and False # => False False or True # => True # True و False هما في الواقع 1 و 0 لكن بمسميات مختلفة True + True # => 2 True * 8 # => 8 False - 5 # => -5 # عمليات المقارنة تنظر الي القيمة الرقمية لل True وال False 0 == False # => True 1 == True # => True 2 == True # => False -5 != False # => True # عند استخدام المنطق الثنائي على القيم الصحيحة يتم تحويلهم الي قيم ثنائية لإجرات العمليات عليهم، لكن قيمهم الأصلية تعود # ﻻ تخلط بين bool(قيمة صحيحة) و العمليات المنطقية الثناية and/or (&,|) bool(0) # => False bool(4) # => True bool(-6) # => True 0 and 2 # => 0 -5 or 0 # => -5 # مقارنة التساوي ب == 1 == 1 # => True 2 == 1 # => False # مقارنة الاختلاف ب != 1 != 1 # => False 2 != 1 # => True # مقارنات أخرى 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # لمعرفة هل القيمة في نطاق معين 1 < 2 and 2 < 3 # => True 2 < 3 and 3 < 2 # => False # التسلسل يجعلها تبدو أجمل 1 < 2 < 3 # => True 2 < 3 < 2 # => False # (is مقابل ==) is تتحق من أن المتغيرين يشيران إلي نفس العنصر, # لكن == تتحقق من أن العنصرين المُشار اليهما بالمتغيرين لهما نفس القيمة. a = [1, 2, 3, 4] # اجعل a تشير إلي قائمة جديدة, [1, 2, 3, 4] b = a # اجعل a تُشير الي ما تُشير إليه b b is a # => True, a و b يُشيران إلي نفس العنصر b == a # => True, قيمة عنصر a و b متساوية b = [1, 2, 3, 4] # اجعل b تشير الي قائمة جديدة , [1, 2, 3, 4] b is a # => False, a و b do ﻻ يشيران إلي نفس العنصر b == a # => True, قيمة عنصر a و b متساوية # يمكنك إنشاء الكلمات (تسلسلات الحروف) عن طريق " أو ' "This is a string." 'This is also a string.' # يمكنك جمع هذا النوع أيضا! لكن حاول ألا تفعل هذا. "Hello " + "world!" # => "Hello world!" # يمكنك الربط بين الكلمات بدون استخدام '+' (لكن ليس المتغيرات) "Hello " "world!" # => "Hello world!" # يمكنك معاملة الكلمات كقائمة من الحروف "This is a string"[0] # => 'T' # يمكنك معرفة طول الكلمة len("This is a string") # => 16 # .format يمكنك استخدامها لبناء الجمل بشكل معين, مثل هذا: "{} can be {}".format("Strings", "interpolated") # => "Strings can be interpolated" # يمكنك تكرار معاملات بناء الجملة لتقليل الكتابة. "{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick") # => "Jack be nimble, Jack be quick, Jack jump over the candle stick" # يمكنك استخدام الكلمات المفتاحية إذا لم تُرد العد. "{name} wants to eat {food}".format(name="Bob", food="lasagna") # => "Bob wants to eat lasagna" # إذا كان كود بايثون 3 الخاص بك يحتاج لبايثون 2.5 أو نسخة أقدم # يمكنك استخدام أسلوب بناء الجمل القديم: "%s can be %s the %s way" % ("Strings", "interpolated", "old") # => "Strings can be interpolated the old way" # يمكنك أبضا بناء الجمل باستخدام f-strings أو حروف بناء الجمل (في بايثون 3.6 فما فوق) name = "Reiko" f"She said her name is {name}." # => "She said her name is Reiko" # يمكنك ببساطة وضع أي كود بايثون داخل أقواس وستقوم بإخراج الجملة. f"{name} is {len(name)} characters long." # None عبارة عن كائن None # => None # ﻻ تستخدم رمز المساواة "==" لمقارنة العناصر ب None # استخدم is بدلا منه. يقوم بالتحقق من مساواة هوية العنصر "etc" is None # => False None is None # => True # None, 0, قوائم/جمل/قواميس/صفوف فارغة كلها تُترجم إلي False. # كل القيم الأخرى True. bool(0) # => False bool("") # => False bool([]) # => False bool({}) # => False bool(()) # => False #################################################### ## 2. المتغيرات والمجموعات #################################################### # بايثون لديها دالة عرض "print" print("I'm Python. Nice to meet you!") # => I'm Python. Nice to meet you! # الافتراضي دالة print تطبع سطر جديد في النهاية. # استخدم المعامل end لتغيير أخر الجملة المعروضة. print("Hello, World", end="!") # => Hello, World! # طريقة بسيطة لطلب مدخل من الطرفية input_string_var = input("Enter some data: ") # يقوم بإعادة البيانات ك "string" # لاحظ: في النسخ القديمة من بايثون، دالة input() كان اسمها raw_input() # ﻻ يوجد تعريفات للمتغيرات، يتم تعيين قيمة المتغير مباشرة. # العٌرف تسمية المتغيرات حروف_صغيرة_مع_خطوط_سُفلية some_var = 5 some_var # => 5 # محاولة استخدام متغير غير مُعين يعتبر خطأ # إقرأ جزء 3.مسار التحكم لمعرفة المزيد عن التحكم في الأخطاء some_unknown_var # يعرض خطأ NameError # يمكن استخدام if كتعبير واحد # مساوِ للتعبير الأتي في لغة السي '?:' عملية ثلاثية "yahoo!" if 3 > 2 else 2 # => "yahoo!" # القوائم تحفظ المتسلسلات li = [] # يمكنك البدأ بقائمة مليئة other_li = [4, 5, 6] # إضافة بيانات لأخر القائمة عن طريق append li.append(1) # li is now [1] li.append(2) # li is now [1, 2] li.append(4) # li is now [1, 2, 4] li.append(3) # li is now [1, 2, 4, 3] # حذف أخر عنصر في القائمة عن طريق pop li.pop() # => 3 and li is now [1, 2, 4] # هيا نعيده ثانية li.append(3) # li is now [1, 2, 4, 3] again. # يمكنك الوصول لعناصر القائمة كما تفعل في ال array # Access a list like you would any array li[0] # => 1 # للوصول لأخر عنصر li[-1] # => 3 # محاولة الوصول لعنصر خارج نطاق القائمة يعتبر خطأ: IndexError li[4] # يعرض خطأ IndexError # يمكنك النظر للنطاقات باستخدام تركيب التقطيع # مؤشر/رقم/فهرس البداية مُضمن، مؤشر النهاية ﻻ # (لمحبي الرياضيات هو نطاق مفتوح/مغلق) li[1:3] # => [2, 4] # إحذف أول عنصر ثم إعرض القائمة li[2:] # => [4, 3] # إحذف أخر عنصر ثم إعرض القائمة li[:3] # => [1, 2, 4] # حدد عنصر ثم إحذف الذي يليه ثم حدد عنصر وهكذا li[::2] # =>[1, 4] # اعرض نسخة معكوسة من القائمة li[::-1] # => [3, 4, 2, 1] # إستخدم أي تجميعة من الطرق المذكورة لعمل تقطيعات متقدمة # li[start:end:step] # عمل نسخة من طبقة واحدة باستخدم التقطيع li2 = li[:] # => li2 = [1, 2, 4, 3] لكن عند عمل(li2 is li) سينتج False. # إمسح أي عنصر من القائمة باستخدام "del" del li[2] # li is now [1, 2, 3] # إمسح أول ظهور لقيمة. li.remove(2) # li is now [1, 3] li.remove(2) # يعرض خطأ ValueError لأن 2 غير موجود في القائمة # أضف عنصر في خانة معينة li.insert(1, 2) # li is now [1, 2, 3] مرة أخرى # أحصل على مؤشر/رقم لأول ظهور للقيمة li.index(2) # => 1 li.index(4) # يعرض خطأ ValueError لأن 4 غير موجودة في القائمة # يمكنك جمع قوائم # لاحظ: لا يتم تعديل قيمة li و other_li li + other_li # => [1, 2, 3, 4, 5, 6] # إستخدم دالة "extend()" لربط القوائم li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6] # راجع وجود قيمة في القائمة باستخدام "in" 1 in li # => True # إحصل على طول القائمة باستخدام دالة "len()" len(li) # => 6 # الصفوف تشبه القوائم لكنها غير قابلة للتغيير. tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # يعرض خطأ TypeError # لاحظ أن صف طوله عنصر واحد يحتاج لإضافة فاصلة "," بعد أخر عنصر # لكن الصفوف من أي طول أخر، حتى صفر لا تحتاج. type((1)) # => type((1,)) # => type(()) # => # يمكنك عمل معظم عمليات القوائم على الصفوف. len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True # يمكنك تفريغ الصفوف (أو القوائم) في متغيرات a, b, c = (1, 2, 3) # a is now 1, b is now 2 and c is now 3 # يمكنك أيضا عمل تفريغ واسع a, *b, c = (1, 2, 3, 4) # a is now 1, b is now [2, 3] and c is now 4 # الصفوف تُنشأ تلقائيا إذا تركت الأقواس d, e, f = 4, 5, 6 # تم توسعة الصف 4, 5 ,6 في المتغيرات d, e, f # بالترتيب حيث d = 4, e = 5 و f = 6 # الأن إنظر إلي مدى سهولة التبديل بين قيم متغيرين e, d = d, e # d is now 5 and e is now 4 # القواميس تُخزن خرائط من المفتاح للقيمة empty_dict = {} # هذا قاموس مملوء filled_dict = {"one": 1, "two": 2, "three": 3} # لاحظ أن القواميس يجب أن تكون أنواع غير قابلة للتغيير. # هذا للتأكد من أن المفتاح يمكن تحويله لقيمة ثابتة للوصول السريع. # الأنواع الغير قابلة للتغير تتضمن: الأرقام الصحيحة، الكسور، الكلمات، الصفوف. invalid_dict = {[1,2,3]: "123"} # =>يعرض خطأ TypeError: unhashable type: 'list' valid_dict = {(1,2,3):[1,2,3]} # القيم يمكن أن تكون من أي نوع. # يمكنك البحث عن قيمة باستخدام [] filled_dict["one"] # => 1 # يمكنك الحصول على كل المفاتيح باستخدام "keys()". # نحتاج لإرسالها لدالة list() لتحويلها لقائمة. سنتعلم هذا لاحقًا # لاحظ - لنسخ بايثون قبل 3.7، ترتيب مفاتيح القاموس غير مضمون. نتائجك # يمكن ألا تساوي المثال بالأسفل. مع ذلك، من أول بايثون 3.7، # عناصر القاموس تحتفظ بالترتيب الذي تم إضافة المفاتيح به في القاموس. list(filled_dict.keys()) # => ["three", "two", "one"] in Python <3.7 list(filled_dict.keys()) # => ["one", "two", "three"] in Python 3.7+ # يمكنك الحصول على كل القيم باستخدام "values()". # مرة أخرى نستخدم list() للحصول عليها كقائمة. # نفس الكلام السابق بخصوص ترتيب المفاتيح list(filled_dict.values()) # => [3, 2, 1] in Python <3.7 list(filled_dict.values()) # => [1, 2, 3] in Python 3.7+ # إفحص للتأكد من وجود مغتاح في القاموس باستخدام "in" "one" in filled_dict # => True 1 in filled_dict # => False # البحث عن مفتاح غير موجود يعرض خطأ KeyError filled_dict["four"] # KeyError # استخدم "get()" لتجنب الخطأ KeyError filled_dict.get("one") # => 1 filled_dict.get("four") # => None # دالة get تدعم إدخال قيمة افتراضية عند عدم وجود البحث filled_dict.get("one", 4) # => 1 filled_dict.get("four", 4) # => 4 # "setdefault()" تقوم بإدخال قيمة جديدة في القاموس في حالة عدم وجود المفتاح فقط. filled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5 filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5 # إضافة عنصر للقاموس filled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} filled_dict["four"] = 4 # طريقة أخرى للإضافة # مسح المفاتيح من القاموس باستخدام del del filled_dict["one"] # Removes the key "one" from filled dict # من بايثون 3.5 فما فوق يمكنك أيضا استخدام خيارات تفريغ إضافية {'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} {'a': 1, **{'a': 2}} # => {'a': 2} # المجموعات تُخزن .. مجموعات empty_set = set() # .تهيئة مجموعة بمجموعة قيم. نعم، تشبه قليلا تهيئة القاموس. أسف some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} # مثل مفتاح القاموس، عناصر المجموعة يجب أن تكون غير قابلة للتغيير. invalid_set = {[1], 1} # => يعرض خطأ TypeError: unhashable type: 'list' valid_set = {(1,), 1} # إضافة عنصر أخر للمجموعة filled_set = some_set filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} # المجموعات لا يمكن أن تحتوي على عناصر مكررة filled_set.add(5) # it remains as before {1, 2, 3, 4, 5} # تقاطع مجموعتين باستخدام & other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} # اتحاد مجموعتين باستخدام | filled_set | other_set # => {1, 2, 3, 4, 5, 6} # الفرق بين مجموعتين باستخدام - {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # الفروق بين مجموعتين باستخدام ^ {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} # لفحص هل المجموعة على اليسار مجموعة عُليا للمجموعة على اليمين (تحتوي على كل عناصرها) {1, 2} >= {1, 2, 3} # => False # لفحص هل المجموعة على اليسار مجموعة فرعية من المجموعة على اليمين {1, 2} <= {1, 2, 3} # => True # للتأكد من وجود عن في مجموعة استخدم in 2 in filled_set # => True 10 in filled_set # => False #################################################### ## 3. مسار التحكم والعمليات التكرارية #Control Flow and Iterables #################################################### # هيا ننشيء متغير some_var = 5 # الأن الأمر if. الفجوات (المسافات قبل الأوامر) مهمة في البايثون! # العُرف استخدام أربع مسافات. ليس تبويب. # هذا السطر البرمجي يطبع "some_var is smaller than 10" if some_var > 10: print("some_var is totally bigger than 10.") elif some_var < 10: # This elif clause is optional. print("some_var is smaller than 10.") else: # This is optional too. print("some_var is indeed 10.") """ For عبارة عن حلقات تدور حول عناصر قوائم :ثم تطبع dog is a mammal cat is a mammal mouse is a mammal """ for animal in ["dog", "cat", "mouse"]: # يمكنك استخدام format() لترجمة كلمات بشكل معين. print("{} is a mammal".format(animal)) """ "range(number)" يقوم بإعادة مجموعة من الأرقام يمكن الدوران حولها من الصفر إلي رقم معين ثم يطبع: 0 1 2 3 """ for i in range(4): print(i) """ "range(lower, upper)" يقوم بإعادة مجموعة من الأرقام يمكن الدوران حولها من القيمة السُفلى lower حتى القيمة العُليا upper ثم يطبع: 4 5 6 7 """ for i in range(4, 8): print(i) """ "range(lower, upper, step)" يقوم بإعادة مجموعة من الأرقام يمكن الدوران حولها من القيمة السُفلى lower حتى القيمة العُليا upper، ثم يقوم بالزيادة قيمة الstep. إذا لم تُحدد ال step, القيمة الأفتراضية 1. ثم يطبع: 4 6 """ for i in range(4, 8, 2): print(i) """ While هي عبارة عن حلقات تدور حتى عدم تحقق شرط معين. وتطبع: 0 1 2 3 """ x = 0 for while x < 4: print(x) x += 1 # اختصار ل x = x + 1 # يمكنك التحكم في الأخطاء والاستثناءات باستخدام مجموعة try/except try: # استخدم "raise" لرفع خطأ. raise IndexError("This is an index error") except IndexError as e: pass # Pass: هو مجرد أمر ﻻ تفعل شيء. عادة تقوم بتصحيح الخطأ هنا. except (TypeError, NameError): pass # يمكنك التحكم في أكثر من خطأ في نفس الوقت، إذا أقتضت الضرورة else: # فقرة اختيارية في مجموعة try/except. يجب أن يتبع جميع مجموعات معارضة الأخطاء print("All good!") # تُنفذ في حالة أن السطور البرمجية داخل ال try لم ترفع أي خطأ finally: # تُنفذ في كل الحالات print("We can clean up resources here") # بدلا من مجموعة try/finally لتنظيف الموارد يمكنك استخدام سطر with with open("myfile.txt") as f: for line in f: print(line) # يتيح البايثون تجريد أساسي يسمى المُكرَر. # المُكرٍَر عبارة عن متغير يمكن التعامل معه كسلسلة. # الكائن الذي يعود من دالة نطاق، يسمى المُكرَر. filled_dict = {"one": 1, "two": 2, "three": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['one', 'two', 'three']) # هذا عبارة عن متغير يعرض عناصر مفاتيح المُكرَر. # يمكننا الدوران حوله. for i in our_iterable: print(i) # Prints one, two, three # مع ذلك ﻻ يمكننا الوصول للعناصر بالمؤشر. our_iterable[1] # يرفع خطأ TypeError # المُكرَر هو عبارة عن عنصر يعلم كيفية إنشاء مُكرِر our_iterator = iter(our_iterable) # المُكرِر هو عبارة عن عنصر يمكنه تذكر الحالة أثناء مرورنا بعناصره. # يمكننا الحصول على العنصر التالي عن طريق "next()" next(our_iterator) # => "one" # يحفظ الحالة أثناء الدوران. next(our_iterator) # => "two" next(our_iterator) # => "three" # بعد عرض المُكرِر كل عناصره، يرفع استثناء StopIteration next(our_iterator) # يرفع StopIteration # يمكنك الحصول على كل عناصر المُكرر بمناداة دالة list() عليه. list(filled_dict.keys()) # => Returns ["one", "two", "three"] #################################################### ## 4. الدوال #################################################### # إستخدم "def" لإنشاء دوال جديدة. def add(x, y): print("x is {} and y is {}".format(x, y)) return x + y # يمكنك إرجاع قيمة من الدالة بسطر return # مناداة دوال بمعطيات add(5, 6) # => prints out "x is 5 and y is 6" and returns 11 # طريقة أخرى لمناداة دوال باستخدام كلمات مفتاحية. add(y=6, x=5) # الكلمة المفتاحية يمكن أن تُعطى بأي ترتيب. # يمكنك تعريف دوال تأخذ عدد متغير من المُعطيات def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) # يمكنك تعريف دوال تأخذ عدد متغير من الكلمات المفتاحية كمعطيات أيضا. def keyword_args(**kwargs): return kwargs # هيا ننادي على الدالة لنرى ماذا سيحدث keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} # يمكنك فعل الأثنين معًا في نفس الوقت، إذا أردت def all_the_args(*args, **kwargs): print(args) print(kwargs) """ all_the_args(1, 2, a=3, b=4) prints: (1, 2) {"a": 3, "b": 4} """ # عندما تنادي على دوال، يمكنك عمل عكس المعطيات/المفاتيح! # استخدم * لتوسعة الصفوف، واستخدم ** لتوسعة المفاتيح. args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # مساوٍ ل all_the_args(1, 2, 3, 4) all_the_args(**kwargs) # مساوٍ ل to all_the_args(a=3, b=4) all_the_args(*args, **kwargs) # مساوٍ ل to all_the_args(1, 2, 3, 4, a=3, b=4) # يقوم بإعادة مجموعة من القيم (بتعيين الصفوف) def swap(x, y): return y, x # يقوم بإعادة مجموعة من القيم على شكل صفوف بدون الأقواس # (لاحظ: الأقواس حُذفت لكن يمكن إضافتها) x = 1 y = 2 x, y = swap(x, y) # => x = 2, y = 1 # (x, y) = swap(x,y) # مرة أخرى الأقواس حُذفت لكن يمكن إضافتها. # مجال الدالة x = 5 def set_x(num): # المتغير المحلي x ليس هو المتغير العام x x = num # => 43 print(x) # => 43 def set_global_x(num): global x print(x) # => 5 x = num #المتغير العام x الأن مساوٍ ل 6 print(x) # => 6 set_x(43) set_global_x(6) # بايثون تدعم دوال الفئة أولية [first class functions] (أي أنه يمكن إرسال الدوال كمعطيات لدوال أخرى) def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 # يوجد أيضا دوال مجهولة (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 # يوجد دوال مدمجة من درجة أعلى list(map(add_10, [1, 2, 3])) # => [11, 12, 13] list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] # يمكن إشتمال القوائم على خرائط وفلاتر حسنة الشكل # هذه القوائم تحفظ المُخرج كقائمة والتي بدورها يمكن أن تكون قائمة مداخلة [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # يمكنك بناء مجموعات وقواميس على هذا المنوال أيضا {x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### ## 5. الوحدات البرمجية (الموديولات) #################################################### # يمكنك استدعاء موديولات import math print(math.sqrt(16)) # => 4.0 # يمكنك استدعاء دالة معينة من موديول from math import ceil, floor print(ceil(3.7)) # => 4.0 print(floor(3.7)) # => 3.0 # يمكنك استدعاء كل الدوال من مديول. # تحذير: هذا الفعل غير موصى به from math import * # يمكنك تصغير اسم موديول import math as m math.sqrt(16) == m.sqrt(16) # => True # موديولات البايثون عبارة عن ملفات بايثون عادية. # يمكنك كتابة الموديولات الخاصة بك, واستدعاها. # اسم الموديول يكون نفس اسم الملف. # يمكنك معرفة أي الدوال والصفات مُعرفة في الموديول. import math dir(math) # إذا كان لديك سكربت بايثون يسمى math.py # في نفس المجلد الموجود به السكربت الخاص بك، الملف الخاص بك math.py # سَيُستدعى بدلا من موديول البايثون بنفس الاسم # هذا يحدث لأن المجلدات المحلية لديها أولوية عن مكتبات البايثون المُدمجة #################################################### ## 6. الفئات/القوالب (الكلاسات) #################################################### # نستخدم السطر البرمجي "class" لإنشاء قالب class Human: # صفة القالب. مشتركة بين كل نسخ القالب species = "H. sapiens" # مُهيئ إبتدائي، يُنادى عليه عندما يتم استدعاء القالب. # لاحظ أن الشرطة السٌفلية المُكررة مرتين __ قبل وبعد الاسم تُعبر عن الكائنات # أو الصفات المُستخدمة عن طريق بايثون لكنها تعيش في مساحة تحكم المُستخدم. # العمليات -الدوال- (أو الكائنات أو الصفات) مثل: __init__, __str__,__repr__ ألخ. # تُسمى عمليات خاصة (أو أحيانا تسمى عمليات سحرية أو dunder methods) # يجب عليك ألا تُسمي مثل هذه الاسماء بنفسك. def __init__(self, name): # ساوِ المُعطى بالصفة name الخاصة بهذه النسخة من القالب. self.name = name # هيئ الصفة self._age = 0 # عملية/دالة خاصة بنسخة القالب. كل العمليات تأخذ "self" كأول مُعطى # An instance method. All methods take "self" as the first argument def say(self, msg): print("{name}: {message}".format(name=self.name, message=msg)) # عملية أخرى خاصة بنسخة القالب. def sing(self): return 'yo... yo... microphone check... one two... one two...' # عمليات القالب مشتركة بين كل أجزاء القالب # يتم مناداتهم عن طريق جعل القالب المُنادي أول معطى # They are called with the calling class as the first argument @classmethod def get_species(cls): return cls.species # تُنادى العملية الثابتة بدون قالب أو نسخة قالب @staticmethod def grunt(): return "*grunt*" # الخاصية تشبه تماما إمر الطلب # تُحَوِل العملية age() إلي صفة مقروءة فقط بنفس الاسم. # ﻻ حاجة لكتابة أوامر طلب أو تهيئة @property def age(self): return self._age # هذا يتيح تهيئة الخاصية @age.setter def age(self, age): self._age = age # هذا يتيح حذف الخاصية @age.deleter def age(self): del self._age # عندما يقرأ مُترجم البايثون ملف مصدري يقوم بتنفيذ كل الكود. # فحص ال __name__ يجعل هذا الجزء من الكود يُنَفَذ فقط # في حالة أن هذا الموديول هو البرنامج الرئيسي if __name__ == '__main__': # Instantiate a class i = Human(name="Ian") i.say("hi") # "Ian: hi" j = Human("Joel") j.say("hello") # "Joel: hello" # i و j نُسخ من النوع Human, أول بكلمات أخرى: هما كائنات للقالب Human # نادي على عملية القالب i.say(i.get_species()) # "Ian: H. sapiens" # عدل الخاصية المُشتركة Human.species = "H. neanderthalensis" i.say(i.get_species()) # => "Ian: H. neanderthalensis" j.say(j.get_species()) # => "Joel: H. neanderthalensis" # نادي على العملية الثابتة print(Human.grunt()) # => "*grunt*" # لا يمكن مناداة العملية الثابتة من نسخة الكائن # لأن i.grunt() سيقوم تلقائيا بوضع "self" (الكائن i) كمُعطى للعملية print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given # حدًث الخاصية لهذه النسخة i.age = 42 # أحصل على الخاصية i.say(i.age) # => "Ian: 42" j.say(j.age) # => "Joel: 0" # إحذف الخاصية del i.age # i.age # => سوف يرفع استثناء AttributeError #################################################### ## 6.1 الإرث #################################################### # الإرث يتيح لقالب ابن أن يُعَرف ويرث بعض عمليات/دوال ومتغيرات القالب الأب. # باستخدام القالب Human المُعَرف بالأعلى كأساس أو كقالب أب، # يمكننا تعريف قالب ابن،Superhero ، يرث متغيرات القالب مثل "species", "name", و "age"، # وأيضا العمليات، مثل "sing", "grunt" # من القالب Human، لكنه أيضا لديه خواصه الفريدة # للاستفادة من التقطيع بالملف يمكنك وضع القوالب بالأعلى في ملفاتهم الخاصة، # مثلا، human.py # لاستيراد دالة من ملف أخر استخدم الطريقة التالية # from "اسم الملف بدون مُلحق" import "اسم الدالة أو القالب" from human import Human # حدد القالب/ات الأب كمُعطى أثناء تعريف القالب. class Superhero(Human): # إذا أردت أن يرث القالب الابن كل تعريفات القالب الأب بدون تعديل # يمكنك استخدام الكلمة المفتاحية "pass" (بدون شيء أخر) # لكن في هذه الحالة تم أهمالها لإنشاء قالب ابن فريد: # pass # القوالب الابن يمكنها تعديل صفات القوالب الأب species = 'Superhuman' # القوالب الابن ترث تلقائيا عمليات الإنشاء الخاصة بالقالب الأب بالإضافة إلي مُعطياتهم # لكن يمكن أيضا تعريف مُعطيات إضافية أو تعريفات # وتعديل العمليات مثل منشيء القالب. # هذا المُنشيء يرث المُعطى "name" من القالب "Human" # ويضيف المعطيات"superpower" و "movies": def __init__(self, name, movie=False, superpowers=["super strength", "bulletproofing"]): # إضافة صفة جديدة للقالب self.fictional = True self.movie = movie # كن على علم بالقيم الافتراضية المتغيرة، حيث أن القيم الافتراضية تُشارك self.superpowers = superpowers # الدالة "super" تتيح لك الوصول لعمليات القالب الأب # التي تم تغييرها عن طريق الابن، في هذه الحالة، العملية __init__< # هذا السطر يُنادي على منشيء القالب الأب. super().__init__(name) # تعديل العملية sing def sing(self): return 'Dun, dun, DUN!' # إضافة عملية جديدة للنسخة def boast(self): for power in self.superpowers: print("I wield the power of {pow}!".format(pow=power)) if __name__ == '__main__': sup = Superhero(name="Tick") # فحص نوع النسخة if isinstance(sup, Human): print('I am human') if type(sup) is Superhero: print('I am a superhero') # إحصل على ترتيب قرار البحث للعملية (Method Resolution search Order) المُستخدمة بواسطة العمليات getattr() و super() # هذه الصفة ديناميكية ويمكن أن تُحَدًث. print(Superhero.__mro__) # => (, # => , ) # نادي العملية الأب لكن استخدم صفات القالب الخاص بها. print(sup.get_species()) # => Superhuman # نادي العملية المُعدلة. print(sup.sing()) # => Dun, dun, DUN! # نادي العملية من القالب Human sup.say('Spoon') # => Tick: Spoon # نادي عملية موجودة فقط في Superhero sup.boast() # => I wield the power of super strength! # => I wield the power of bulletproofing! # وَرَثَ صفات القالب sup.age = 31 print(sup.age) # => 31 # صفة موجودة فقط في القالب Superhero print('Am I Oscar eligible? ' + str(sup.movie)) #################################################### ## 6.2 الإرث المُتعدد #################################################### # تعريف قالب أخرA # bat.py class Bat: species = 'Baty' def __init__(self, can_fly=True): self.fly = can_fly # هذا القالب لديه عملية تسمى say def say(self, msg): msg = '... ... ...' return msg # ولديه عمليته الخاصة به أيضا def sonar(self): return '))) ... (((' if __name__ == '__main__': b = Bat() print(b.say('hello')) print(b.fly) # تعريف قالب أخر يرث من Superhero و Bat # superhero.py from superhero import Superhero from bat import Bat # عَرٍف Batman كقالب ابن يرث من كلا من Superhero و Bat class Batman(Superhero, Bat): def __init__(self, *args, **kwargs): # عادة لكي ترث صفة يجد أن تنادي على super: # super(Batman, self).__init__(*args, **kwargs) # لكننا في هذه الحالة نتعامل مع إرث متعدد هنا، و super() # تعمل فقط مع القالب التالي في قائمة ال MRO. # لذا بدلا من ذلك ننادي على __init__ صراحة لكل الأباء. # استخدام *args و **kwargs يتيح طريقة نظيفة لتمرير المعطيات. # لكل أب "تقشير طبقة من البصل". Superhero.__init__(self, 'anonymous', movie=True, superpowers=['Wealthy'], *args, **kwargs) Bat.__init__(self, *args, can_fly=False, **kwargs) # تعديل قيمة الصفة name self.name = 'Sad Affleck' def sing(self): return 'nan nan nan nan nan batman!' if __name__ == '__main__': sup = Batman() # إحصل على ترتيب قرار البحث للعملية (Method Resolution search Order) المُستخدمة بواسطة العمليات getattr() و super() # هذه الصفة ديناميكية ويمكن أن تُحَدًث. print(Batman.__mro__) # => (, # => , # => , # => , ) # نادي على العملية الخاصة بالأب لكن استخدم الصفات الخاصة بالقالب الابن print(sup.get_species()) # => Superhuman # نادي على العملية المُعدلة print(sup.sing()) # => nan nan nan nan nan batman! # نادي على العملية من القالب Human, لأن الترتيب في الأرث مهم. sup.say('I agree') # => Sad Affleck: I agree # نادي على العملية الموجودة فقط في القالب الأب الثاني print(sup.sonar()) # => ))) ... ((( # الصفة الموروثة من القالب الأب sup.age = 100 print(sup.age) # => 100 # الصفة الموروثة من القالب الأب الثاني، الذي تم تعديل قيمته الافتراضية print('Can I fly? ' + str(sup.fly)) # => Can I fly? False #################################################### ## 7. مُتَقدم #################################################### # المولدات تُساعدك على كتابة كود كسول. def double_numbers(iterable): for i in iterable: yield i + i # المولدات فعالة من حيث الذاكرة، لأنها تُحمٍل الذاكرة بالبيانات التي تحتاج # لإجراء العملية عليها في الخطوة التالية في المُكَرِر. # هذا يتيح إجراء عمليات على قيم كبيرة ممنوعة في حالات أخرى. # ﻻحظ: `range` بديل ل `xrange` في بايثون 3. for i in double_numbers(range(1, 900000000)): # `range` is a generator. print(i) if i >= 30: break # كما يمكنك إنشاء قوائم اشتمال، يمكنك إنشاء مولدات اشتمال أيضا values = (-x for x in [1,2,3,4,5]) for x in values: print(x) # prints -1 -2 -3 -4 -5 to console/terminal # يمكنك أيضا تغيير نوع مولد الاشتمال مباشرة إلي قائمة values = (-x for x in [1,2,3,4,5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] # المُحسنات # في هذا المثال الدالة`beg` تُغلف الدالة `say`. # إذا كانت say_please تساوي True # إذا ستُغير الرسالة الراجعة من الدالة from functools import wraps def beg(target_function): @wraps(target_function) def wrapper(*args, **kwargs): msg, say_please = target_function(*args, **kwargs) if say_please: return "{} {}".format(msg, "Please! I am poor :(") return msg return wrapper @beg def say(say_please=False): msg = "Can you buy me a beer?" return msg, say_please print(say()) # Can you buy me a beer? print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( ``` ## جاهز للمزيد? ### مجانا عبر الانترنت * [أتمتتة المهمات المُملة عبر بايثون](https://automatetheboringstuff.com) * [التوثيقات الرسمية](http://docs.python.org/3/) * [دليل المُسافر لبايثون](http://docs.python-guide.org/en/latest/) * [دورة بايثون](http://www.python-course.eu/index.php) * [أولى الخطوات مع بايثون](https://realpython.com/learn/python-first-steps/) * [قائمة مُختارة من إطارات عمل بايثون الرائعة, المكتبات والبرمجيات](https://github.com/vinta/awesome-python) * [الدليل الرسمي لنمط البايثون](https://peps.python.org/pep-0008/) * [بايثون 3 دوائر علوم الحاسب](http://cscircles.cemc.uwaterloo.ca/) * [غُص في بايثون 3](http://www.diveintopython3.net/index.html) ================================================ FILE: ar/sql.md ================================================ --- contributors: - ["Bob DuCharme", "http://bobdc.com/"] translators: - ["Ahmed Omar Eissa", "https://twitter.com/AhmedOmarEissa"] ---
لغة الاستعلام الهيكلية (SQL) هي لغة قياسية [ISO/IEC 9075](https://www.iso.org/standard/63555.html) لإنشاء قواعد البيانات المخزنة في مجموعة من الجداول التعامل معها. عادةً ما تضيف التطبيقات امتدادات خاصة بها إلى اللغة ؛ تعد [مقارنة نسخ SQL المختلفة](http://troels.arvin.dk/db/rdbms/) مرجعًا جيدًا لاختلافات النسخ. توفر النسخ عادةً موجه سطر أوامر command line prompt حيث يمكنك إدخال الأوامر المعروضة هنا بشكل تفاعلي، كما أنها توفر طريقة لتنفيذ سلسلة من هذه الأوامر المخزنة في ملف نصي. إظهار رسالة الانتهاء من العمل مع الموجه التفاعلي مثال جيد على امكانية اضافة أوامر غير قياسية، معظم النسخ تدعم أحد أوامر QUIT , EXIT .أو كليهما في الامثلة بالأسفل تعتمدالعديد من الأوامرأن قاعدة بيانات الموظفين [MySQL employee sample database](https://dev.mysql.com/doc/employee/en/) الموجودة على [GitHub](https://github.com/datacharmer/test_db) قد تم تحميلها مسبقا. الملفات على GitHub هي مجموعة من الاوامر تشبه الموجودة بالاسفل و تقوم الأوامر بإنشاء الجدوال وإدخال بيانات مجموعة من الموظفين المتخيلين في شركة. تعتمد الأوامر المستخدمة في هذا البرنامج على نسخة SQL التي تستخدمها،
```sql -- تبدأ التعليقات بشرطتين. قم بإنهاء كل أمر بفاصلة منقوطة -- حساسة لحالة الاحرف SQL لا تعتبر -- فقط ليسهل تمييزها عن أسماه الأعمدة والجداول وقواعد البيانات UPPER-CASE الاوامر الموجودة هنا تستخدم الحالة العليا للاحرف -- إنشاء ومسح قاعدة بيانات، أسماء قواعد البيانات والجداول حساسة لحالة الأحرف CREATE DATABASE someDatabase; DROP DATABASE someDatabase; -- عرض قواعد البيانات الموجودة SHOW DATABASES; --استخدام قاعدة بيانات محددة USE employees; -- في قاعدة البيانات المستخدمة departments ارجاع كل السطور والاعمدة في جدول -- ستظهر النتائج على الشاشة بشكل تلقائي لتتصفحها. SELECT * FROM departments; -- فقط dept_name و dept_no لكن سنسترجع عمودي departments استرجاع كل أسطر من جدول -- لا مانع من تقسيم الاوامر بين السطور SELECT dept_no, dept_name FROM departments; -- لكن هذه المرة سنسترجع ٥ أسطر فقط departments استرجاع كل الاعمدة من جدول SELECT * FROM departments LIMIT 5; --en يحتوي علي dept_name في حالة أن عمود departments من جدول dept_name استرجاع عمود SELECT dept_name FROM departments WHERE dept_name LIKE '%en%'; -- S استرجاع كل أعمدة جدول الاقسام في حالة أن اسم القسم يبدأ بحرف -- متبوعا بأربعة حروف SELECT * FROM departments WHERE dept_name LIKE 'S____'; -- استرجاع قيم العناوين من جدول العناوين بدون تكرار SELECT DISTINCT title FROM titles; -- نفس المثال السابق مع ترتيب العناوين أبجديا SELECT DISTINCT title FROM titles ORDER BY title; -- اظهار عدد السطور في جدول الأقسام SELECT COUNT(*) FROM departments; -- en اظهار عدد السطور في جدول الأقسام التي تحتوي في عمود اسم القسم علي SELECT COUNT(*) FROM departments WHERE dept_name LIKE '%en%'; -- ربط المعلومات بين الجداول، جدول العناوين يظهر رقم كل موظف ومسماه الوظيفي -- ومتي حصل على هذا المسمى وإلي متى ولكن بدلا من اظهار رقم الموظف سنستخدم هذا الرقم -- للحصول على اسم الموظف الاول والأخير من جدول الموظفين مع إظهار ١٠ سطور فقط SELECT employees.first_name, employees.last_name, titles.title, titles.from_date, titles.to_date FROM titles INNER JOIN employees ON employees.emp_no = titles.emp_no LIMIT 10; -- إظهار كل الجدوال في كل قواعد البيانات -- النسخ المختلفة تقدم اختصارات لمثل هذا الأمر لقاعدة البيانات المستخدمة SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'; -- يحتوى على عمودان في قاعدة البيانات المستخدمة tablename1 أنشاء جدول يسمى -- يوجد العديد من الطرق لتعريف الاعمدة وأنواع البيانات في العمود CREATE TABLE tablename1 (fname VARCHAR(20), lname VARCHAR(20)); -- هذا بافتراض ان الجدول يمكن اضافة الاسطر له .tablename1 اضافة سطر في جدول INSERT INTO tablename1 VALUES('Richard','Mutt'); --John إلى fname سنغير قيمة عمود tablename1 في -- Mutt هي lname في حالة أن قيمة العمود UPDATE tablename1 SET fname='John' WHERE lname='Mutt'; -- 'M' تبدأ ب lname في حالة أن قيمة عمود tablename1 مسح السطور من جدول DELETE FROM tablename1 WHERE lname like 'M%'; -- مع ترك الجدول فارغ tablename1 مسح جميع السطور من جدول DELETE FROM tablename1; -- تماما tablename1 إزالة جدول DROP TABLE tablename1; ```
## اقرأ أكثر * [Codecademy - SQL](https://www.codecademy.com/learn/learn-sql)مقدمة جيدة للتعلم عن طريق التطبيق. * [Database System Concepts](https://www.db-book.com) الفصل رقم ٣ من الكتاب مقدمة في (SQL) تحتوى علي شرح مفصل لمفاهيم (SQL)
================================================ FILE: arturo.md ================================================ --- name: Arturo filename: learnarturo.art contributors: - ["Dr.Kameleon", "https://github.com/drkameleon"] --- ```red ; this is a comment ; this is another comment ;--------------------------------- ; VARIABLES & VALUES ;--------------------------------- ; numbers a1: 2 a2: 3.14 a3: to :complex [1 2.0] ; 1.0+2.0i ; strings c1: "this is a string" c2: { this is a multiline string that is indentation-agnostic } c3: {: this is a verbatim multiline string which will remain exactly as the original :} ; characters ch: `c` ; blocks/arrays d: [1 2 3] ; dictionaries e: #[ name: "John" surname: "Doe" age: 34 likes: [pizza spaghetti] ] ; yes, functions are values too f: function [x][ 2 * x ] ; dates g: now ; 2021-05-03T17:10:48+02:00 ; booleans h1: true h2: false ;--------------------------------- ; BASIC OPERATORS ;--------------------------------- ; simple arithmetic 1 + 1 ; => 2 8 - 1 ; => 7 4.2 - 1.1 ; => 3.1 10 * 2 ; => 20 35 / 4 ; => 8 35 // 4 ; => 8.75 2 ^ 5 ; => 32 5 % 3 ; => 2 ; bitwise operators and 3 5 ; => 1 or 3 5 ; => 7 xor 3 5 ; => 6 ; pre-defined constants pi ; => 3.141592653589793 epsilon ; => 2.718281828459045 null ; => null true ; => true false ; => false ;--------------------------------- ; COMPARISON OPERATORS ;--------------------------------- ; equality 1 = 1 ; => true 2 = 1 ; => false ; inequality 1 <> 1 ; => false 2 <> 1 ; => true ; more comparisons 1 < 10 ; => true 1 =< 10 ; => true 10 =< 10 ; => true 1 > 10 ; => false 1 >= 10 ; => false 11 >= 10 ; => true ;--------------------------------- ; CONDITIONALS ;--------------------------------- ; logical operators and? true true ; => true and? true false ; => false or? true false ; => true or? false false ; => false and? [1=2][2<3] ; => false ; (the second block will not be evaluated) ; simple if statements if 2 > 1 [ print "yes!"] ; yes! if 3 <> 2 -> print "true!" ; true! ; if/else statements if? 2 > 3 -> print "2 is greater than 3" else -> print "2 is not greater than 3" ; 2 is not greater than 3 ; switch statements switch 2 > 3 -> print "2 is greater than 3" -> print "2 is not greater than 3" ; 2 is not greater than 3 a: (2 > 3)["yes"]["no"] ; a: "no" a: (2 > 3)? -> "yes" -> "no" ; a: "no" (exactly the same as above) ; case/when statements case [1] when? [>2] -> print "1 is greater than 2. what?!" when? [<0] -> print "1 is less than 0. nope..." else -> print "here we are!" ; here we are! ;--------------------------------- ; LOOPS ;--------------------------------- ; with `loop` arr: [1 4 5 3] loop arr 'x [ print ["x =" x] ] ; x = 1 ; x = 4 ; x = 5 ; x = 3 ; with loop and custom index loop.with:'i arr 'x [ print ["item at position" i "=>" x] ] ; item at position 0 => 1 ; item at position 1 => 4 ; item at position 2 => 5 ; item at position 3 => 3 ; using ranges loop 1..3 'x -> ; since it's a single statement print x ; there's no need for [block] notation ; we can wrap it up using the `->` syntactic sugar loop `a`..`c` 'ch -> print ch ; a ; b ; c ; picking multiple items loop 1..10 [x y] -> print ["x =" x ", y =" y] ; x = 1 , y = 2 ; x = 3 , y = 4 ; x = 5 , y = 6 ; x = 7 , y = 8 ; x = 9 , y = 10 ; looping through a dictionary dict: #[name: "John", surname: "Doe", age: 34] loop dict [key value][ print [key "->" value] ] ; name -> John ; surname -> Doe ; age -> 34 ; while loops i: new 0 while [i<3][ print ["i =" i] inc 'i ] ; i = 0 ; i = 1 ; i = 2 ;--------------------------------- ; STRINGS ;--------------------------------- ; case a: "tHis Is a stRinG" print upper a ; THIS IS A STRING print lower a ; this is a string print capitalize a ; tHis Is a stRinG ; concatenation a: "Hello " ++ "World!" ; a: "Hello World!" ; strings as an array split "hello" ; => [h e l l o] split.words "hello world" ; => [hello world] print first "hello" ; h print last "hello" ; o ; conversion to :string 123 ; => "123" to :integer "123" ; => 123 ; joining strings together join ["hello" "world"] ; => "helloworld" join.with:"-" ["hello" "world"] ; => "hello-world" ; string interpolation x: 2 print ~"x = |x|" ; x = 2 ; interpolation with `print` print ["x =" x] ; x = 2 ; (`print` works by calculating the given block ; and joining the different values as strings ; with a single space between them) ; templates print render.template { <||= switch x=2 [ ||> Yes, x = 2 <||][||> No, x is not 2 <||]||> } ; Yes, x = 2 ; matching prefix? "hello" "he" ; => true suffix? "hello" "he" ; => false contains? "hello" "ll" ; => true contains? "hello" "he" ; => true contains? "hello" "x" ; => false in? "ll" "hello" ; => true in? "x" "hello" ; => false ;--------------------------------- ; BLOCKS ;--------------------------------- ; calculate a block arr: [1 1+1 1+1+1] @arr ; => [1 2 3] ; execute a block sth: [print "Hello world"] ; this is perfectly valid, ; could contain *anything* ; and will not be executed... do sth ; Hello world ; (...until we tell it to) ; array indexing arr: ["zero" "one" "two" "three"] print first arr ; zero print arr\0 ; zero print last arr ; three print arr\3 ; three x: 2 print get arr x ; two print arr \ 2 ; two ; (using the `\` infix alias for get - ; notice space between the operands! ; otherwise, it'll be parsed as a path) ; setting an array element arr\0: "nada" set arr 2 "dos" print arr ; nada one dos three ; adding elements to an array arr: new [] 'arr ++ "one" 'arr ++ "two" print arr ; one two ; remove elements from an array arr: new ["one" "two" "three" "four"] 'arr -- "two" ; arr: ["one" "three" "four"] remove 'arr .index 0 ; arr: ["three" "four"] ; getting the size of an array arr: ["one" 2 "three" 4] print size arr ; 4 ; getting a slice of an array print slice ["one" "two" "three" "four"] 0 1 ; one two ; check if array contains a specific element print contains? arr "one" ; true print contains? arr "five" ; false ; sorting array arr: [1 5 3 2 4] sort arr ; => [1 2 3 4 5] sort.descending arr ; => [5 4 3 2 1] ; mapping values map 1..10 [x][2*x] ; => [2 4 6 8 10 12 14 16 18 20] map 1..10 'x -> 2*x ; same as above map 1..10 => [2*&] ; same as above map 1..10 => [2*] ; same as above ; selecting/filtering array values select 1..10 [x][odd? x] ; => [1 3 5 7 9] select 1..10 => odd? ; same as above filter 1..10 => odd? ; => [2 4 6 8 10] ; (now, we leave out all odd numbers - ; while select keeps them) ; misc operations arr: ["one" 2 "three" 4] reverse arr ; => [4 "three" 2 "one"] shuffle arr ; => [2 4 "three" "one"] unique [1 2 3 2 3 1] ; => [1 2 3] permutate [1 2 3] ; => [[1 2 3] [1 3 2] [3 1 2] [2 1 3] [2 3 1] [3 2 1]] take 1..10 3 ; => [1 2 3] repeat [1 2] 3 ; => [1 2 1 2 1 2] ;--------------------------------- ; FUNCTIONS ;--------------------------------- ; declaring a function f: function [x][ 2*x ] f: function [x]-> 2*x ; same as above f: $[x]->2*x ; same as above (only using the `$` alias ; for the `function`... function) ; calling a function f 10 ; => 20 ; returning a value g: function [x][ if x < 2 -> return 0 res: 0 loop 0..x 'z [ res: res + z ] return res ] ;--------------------------------- ; CUSTOM TYPES ;--------------------------------- ; defining a custom type define :person [ ; define a new custom type "Person" name ; with fields: name, surname, age surname age ][ ; with custom post-construction initializer init: [ this\name: capitalize this\name ] ; custom print function print: [ render "NAME: |this\name|, SURNAME: |this\surname|, AGE: |this\age|" ] ; custom comparison operator compare: 'age ] ; create a method for our custom type sayHello: function [this][ ensure -> is? :person this print ["Hello" this\name] ] ; create new objects of our custom type a: to :person ["John" "Doe" 34] ; let's create 2 "Person"s b: to :person ["jane" "Doe" 33] ; and another one ; call pseudo-inner method sayHello a ; Hello John sayHello b ; Hello Jane ; access object fields print ["The first person's name is:" a\name] ; The first person's name is: John print ["The second person's name is:" b\name] ; The second person's name is: Jane ; changing object fields a\name: "Bob" sayHello a ; Hello Bob ; verifying object type print type a ; :person print is? :person a ; true ; printing objects print a ; NAME: John, SURNAME: Doe, AGE: 34 ; sorting user objects (using custom comparator) sort @[a b] ; Jane..., John... sort.descending @[a b] ; John..., Jane... ``` ## Additional resources - [Official documentation](https://arturo-lang.io/documentation/) - Arturo official documentation & reference. - [Online playground](https://arturo-lang.io/playground/) - Online REPL for the Arturo programming language. ================================================ FILE: asciidoc.md ================================================ --- name: AsciiDoc contributors: - ["Ryan Mavilia", "http://unoriginality.rocks/"] - ["Abel Salgado Romero", "https://twitter.com/abelsromero"] filename: asciidoc.adoc --- AsciiDoc is a markup language similar to Markdown and it can be used for anything from books to blogs. Created in 2002 by Stuart Rackham the language is simple but it allows for a great amount of customization. Document Header Headers are optional and can't contain blank lines. It must be offset from content by at least one blank line. Title Only ``` = Document Title First sentence of document. ``` Title and Author ``` = Document Title First Last Start of this document. ``` Multiple Authors ``` = Document Title John Doe ; Jane Doe; Black Beard Start of a doc with multiple authors. ``` Revision Line (requires an author line) ``` = Doc Title V1 Potato Man v1.0, 2016-01-13 This article about chips is going to be fun. ``` Paragraphs ``` You don't need anything special for paragraphs. Add a blank line between paragraphs to separate them. To create a line blank add a + and you will receive a line break! ``` Formatting Text ``` _underscore creates italics_ *asterisks for bold* *_combine for extra fun_* `use ticks to signify monospace` `*bolded monospace*` ``` Section Titles ``` = Level 0 (may only be used in document's header) == Level 1

=== Level 2

==== Level 3

===== Level 4

``` Lists To create a bulleted list use asterisks. ``` * foo * bar * baz ``` To create a numbered list use periods. ``` . item 1 . item 2 . item 3 ``` You can nest lists by adding extra asterisks or periods up to five times. ``` * foo 1 ** foo 2 *** foo 3 **** foo 4 ***** foo 5 . foo 1 .. foo 2 ... foo 3 .... foo 4 ..... foo 5 ``` ## Further Reading There are two tools to process AsciiDoc documents: 1. [AsciiDoc](http://asciidoc.org/): original Python implementation available in the main Linux distributions. Stable and currently in maintenance mode. 2. [Asciidoctor](http://asciidoctor.org/): alternative Ruby implementation, usable also from Java and JavaScript. Under active development, it aims to extend the AsciiDoc syntax with new features and output formats. Following links are related to `Asciidoctor` implementation: * [Markdown - AsciiDoc syntax comparison](http://asciidoctor.org/docs/user-manual/#comparison-by-example): side-by-side comparison of common Markdown and AsciiDoc elements. * [Getting started](http://asciidoctor.org/docs/#get-started-with-asciidoctor): installation and quick start guides to render simple documents. * [Asciidoctor User Manual](http://asciidoctor.org/docs/user-manual/): complete single-document manual with syntax reference, examples, rendering tools, amongst others. ================================================ FILE: assemblyscript.md ================================================ --- name: AssemblyScript contributors: - ["Philippe Vlérick", "https://github.com/pvlerick"] - ["Steve Huguenin-Elie", "https://github.com/StEvUgnIn"] - ["Sebastian Speitel", "https://github.com/SebastianSpeitel"] - ["Max Graey", "https://github.com/MaxGraey"] filename: learnassemblyscript.ts --- __AssemblyScript__ compiles a variant of __TypeScript__ (basically JavaScript with types) to __WebAssembly__ using __Binaryen__. It generates lean and mean WebAssembly modules while being just an `npm install` away. This article will focus only on AssemblyScript extra syntax, as opposed to [TypeScript](../typescript/) and [JavaScript](../javascript/). To test AssemblyScript's compiler, head to the [Playground](https://www.assemblyscript.org/editor.html#IyFydW50aW1lPXN0dWIKLyoqIENhbGN1bGF0ZXMgdGhlIG4tdGggRmlib25hY2NpIG51bWJlci4gKi8KZXhwb3J0IGZ1bmN0aW9uIGZpYihuOiBpMzIpOiBpMzIgewogIHZhciBhID0gMCwgYiA9IDEKICBpZiAobiA+IDApIHsKICAgIHdoaWxlICgtLW4pIHsKICAgICAgbGV0IHQgPSBhICsgYgogICAgICBhID0gYgogICAgICBiID0gdAogICAgfQogICAgcmV0dXJuIGIKICB9CiAgcmV0dXJuIGEKfQoKIyFodG1sCjx0ZXh0YXJlYSBpZD0ib3V0cHV0IiBzdHlsZT0iaGVpZ2h0OiAxMDAlOyB3aWR0aDogMTAwJSIgcmVhZG9ubHk+PC90ZXh0YXJlYT4KPHNjcmlwdD4KbG9hZGVyLmluc3RhbnRpYXRlKG1vZHVsZV93YXNtLCB7IC8qIGltcG9ydHMgKi8gfSkKICAudGhlbigoeyBleHBvcnRzIH0pID0+IHsKICAgIGNvbnN0IG91dHB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdvdXRwdXQnKQogICAgZm9yIChsZXQgaSA9IDA7IGkgPD0gMTA7ICsraSkgewogICAgICBvdXRwdXQudmFsdWUgKz0gYGZpYigke2l9KSA9ICR7ZXhwb3J0cy5maWIoaSl9XG5gCiAgICB9CiAgfSkKPC9zY3JpcHQ+Cg==) where you will be able to type code, have auto completion and directly see the emitted WebAssembly. ```ts // There are many basic types in AssemblyScript, let isDone: boolean = false; let name: string = "Anders"; // but integer type come as signed (sized from 8 to 64 bits) let lines8: i8 = 42; let lines16: i16 = 42; let lines32: i32 = 42; let lines64: i64 = 42; // and unsigned (sized from 8 to 64 bits), let ulines8: u8 = 42; let ulines16: u16 = 42; let ulines32: u32 = 42; let ulines64: u64 = 42; // and float has two sizes possible (32/64). let rate32: f32 = 1.0 let rate64: f64 = 1.0 // But you can omit the type annotation if the variables are derived // from explicit literals let _isDone = false; let _lines = 42; let _name = "Anders"; // Use const keyword for constants const numLivesForCat = 9; numLivesForCat = 1; // Error // For collections, there are typed arrays and generic arrays let list1: i8[] = [1, 2, 3]; // Alternatively, using the generic array type let list2: Array = [1, 2, 3]; // For enumerations: enum Color { Red, Green, Blue }; let c: Color = Color.Green; // Functions imported from JavaScript need to be declared as external // @ts-ignore decorator @external("alert") declare function alert(message: string): void; // and you can also import JS functions in a namespace declare namespace window { // @ts-ignore decorator @external("window", "alert") function alert(message: string): void; } // Lastly, "void" is used in the special case of a function returning nothing export function bigHorribleAlert(): void { alert("I'm a little annoying box!"); // calling JS function here } // Functions are first class citizens, support the lambda "fat arrow" syntax // The following are equivalent, the compiler does not offer any type // inference for functions yet, and same WebAssembly will be emitted. export function f1 (i: i32): i32 { return i * i; } // "Fat arrow" syntax let f2 = (i: i32): i32 => { return i * i; } // "Fat arrow" syntax, braceless means no return keyword needed let f3 = (i: i32): i32 => i * i; // Classes - members are public by default export class Point { // Properties x: f64; // Constructor - the public/private keywords in this context will generate // the boiler plate code for the property and the initialization in the // constructor. // In this example, "y" will be defined just like "x" is, but with less code // Default values are also supported constructor(x: f64, public y: f64 = 0) { this.x = x; } // Functions dist(): f64 { return Math.sqrt(this.x * this.x + this.y * this.y); } // Static members static origin: Point = new Point(0, 0); } // Classes can be explicitly marked as extending a parent class. // Any missing properties will then cause an error at compile-time. export class PointPerson extends Point { constructor(x: f64, y: f64, public name: string) { super(x, y); } move(): void {} } let p1 = new Point(10, 20); let p2 = new Point(25); //y will be 0 // Inheritance export class Point3D extends Point { constructor(x: f64, y: f64, public z: f64 = 0) { super(x, y); // Explicit call to the super class constructor is mandatory } // Overwrite dist(): f64 { let d = super.dist(); return Math.sqrt(d * d + this.z * this.z); } } // Namespaces, "." can be used as separator for sub namespaces export namespace Geometry { class Square { constructor(public sideLength: f64 = 0) { } area(): f64 { return Math.pow(this.sideLength, 2); } } } let s1 = new Geometry.Square(5); // Generics // AssemblyScript compiles generics to one concrete method or function per set // of unique contextual type arguments, also known as [monomorphisation]. // Implications are that a module only includes and exports concrete functions // for sets of type arguments actually used and that concrete functions can be // shortcutted with [static type checks] at compile time, which turned out to // be quite useful. // Classes export class Tuple { constructor(public item1: T1, public item2: T2) { } } export class Pair { item1: T; item2: T; } // And functions export function pairToTuple (p: Pair): Tuple { return new Tuple(p.item1, p.item2); }; let tuple = pairToTuple({ item1: "hello", item2: "world" }); // Including references to a TypeScript-only definition file: /// // Template Strings (strings that use backticks) // String Interpolation with Template Strings let name = 'Tyrone'; let greeting = `Hi ${name}, how are you?` // Multiline Strings with Template Strings let multiline = `This is an example of a multiline string`; let numbers: Array = [0, 1, 2, 3, 4]; let moreNumbers: Array = numbers; moreNumbers[5] = 5; // Error, elements are read-only moreNumbers.push(5); // Error, no push method (because it mutates array) moreNumbers.length = 3; // Error, length is read-only numbers = moreNumbers; // Error, mutating methods are missing // Type inference in Arrays let ints = [0, 1, 2, 3, 4] // will infer as Array let floats: f32[] = [0, 1, 2, 3, 4] // will infer as Array let doubles = [0.0, 1.0, 2, 3, 4] // will infer as Array let bytes1 = [0 as u8, 1, 2, 3, 4] // will infer as Array let bytes2 = [0, 1, 2, 3, 4] as u8[] // will infer as Array let bytes3: u8[] = [0, 1, 2, 3, 4] // will infer as Array ``` ## Further Reading * [AssemblyScript Official website](https://www.assemblyscript.org/) * [AssemblyScript source documentation](https://github.com/AssemblyScript/website/tree/main/src) * [Source Code on GitHub](https://github.com/AssemblyScript/assemblyscript) ================================================ FILE: asymptotic-notation.md ================================================ --- category: Algorithms & Data Structures name: Asymptotic Notation contributors: - ["Jake Prather", "http://github.com/JakeHP"] - ["Divay Prakash", "http://github.com/divayprakash"] --- # Asymptotic Notations ## What are they? Asymptotic Notations are languages that allow us to analyze an algorithm's running time by identifying its behavior as the input size for the algorithm increases. This is also known as an algorithm's growth rate. Does the algorithm suddenly become incredibly slow when the input size grows? Does it mostly maintain its quick run time as the input size increases? Asymptotic Notation gives us the ability to answer these questions. ## Are there alternatives to answering these questions? One way would be to count the number of primitive operations at different input sizes. Though this is a valid solution, the amount of work this takes for even simple algorithms does not justify its use. Another way is to physically measure the amount of time an algorithm takes to complete given different input sizes. However, the accuracy and relativity (times obtained would only be relative to the machine they were computed on) of this method is bound to environmental variables such as computer hardware specifications, processing power, etc. ## Types of Asymptotic Notation In the first section of this doc, we described how an Asymptotic Notation identifies the behavior of an algorithm as the input size changes. Let us imagine an algorithm as a function f, n as the input size, and f(n) being the running time. So for a given algorithm f, with input size n you get some resultant run time f(n). This results in a graph where the Y-axis is the runtime, the X-axis is the input size, and plot points are the resultants of the amount of time for a given input size. You can label a function, or algorithm, with an Asymptotic Notation in many different ways. Some examples are, you can describe an algorithm by its best case, worst case, or average case. The most common is to analyze an algorithm by its worst case. You typically don’t evaluate by best case because those conditions aren’t what you’re planning for. An excellent example of this is sorting algorithms; particularly, adding elements to a tree structure. The best case for most algorithms could be as low as a single operation. However, in most cases, the element you’re adding needs to be sorted appropriately through the tree, which could mean examining an entire branch. This is the worst case, and this is what we plan for. ### Types of functions, limits, and simplification ``` Logarithmic Function - log n Linear Function - an + b Quadratic Function - an^2 + bn + c Polynomial Function - an^z + . . . + an^2 + a*n^1 + a*n^0, where z is some constant Exponential Function - a^n, where a is some constant ``` These are some fundamental function growth classifications used in various notations. The list starts at the slowest growing function (logarithmic, fastest execution time) and goes on to the fastest growing (exponential, slowest execution time). Notice that as ‘n’ or the input, increases in each of those functions, the result increases much quicker in quadratic, polynomial, and exponential, compared to logarithmic and linear. It is worth noting that for the notations about to be discussed, you should do your best to use the simplest terms. This means to disregard constants, and lower order terms, because as the input size (or n in our f(n) example) increases to infinity (mathematical limits), the lower order terms and constants are of little to no importance. That being said, if you have constants that are 2^9001, or some other ridiculous, unimaginable amount, realize that simplifying skew your notation accuracy. Since we want simplest form, lets modify our table a bit... ``` Logarithmic - log n Linear - n Quadratic - n^2 Polynomial - n^z, where z is some constant Exponential - a^n, where a is some constant ``` ### Big-O Big-O, commonly written as **O**, is an Asymptotic Notation for the worst case, or ceiling of growth for a given function. It provides us with an _**asymptotic upper bound**_ for the growth rate of the runtime of an algorithm. Say `f(n)` is your algorithm runtime, and `g(n)` is an arbitrary time complexity you are trying to relate to your algorithm. `f(n)` is O(g(n)), if for some real constants c (c > 0) and n0, `f(n)` <= `c g(n)` for every input size n (n > n0). *Example 1* ``` f(n) = 3log n + 100 g(n) = log n ``` Is `f(n)` O(g(n))? Is `3 log n + 100` O(log n)? Let's look to the definition of Big-O. ``` 3log n + 100 <= c * log n ``` Is there some pair of constants c, n0 that satisfies this for all n > n0? ``` 3log n + 100 <= 150 * log n, n > 2 (undefined at n = 1) ``` Yes! The definition of Big-O has been met therefore `f(n)` is O(g(n)). *Example 2* ``` f(n) = 3*n^2 g(n) = n ``` Is `f(n)` O(g(n))? Is `3 * n^2` O(n)? Let's look at the definition of Big-O. ``` 3 * n^2 <= c * n ``` Is there some pair of constants c, n0 that satisfies this for all n > n0? No, there isn't. `f(n)` is NOT O(g(n)). ### Big-Omega Big-Omega, commonly written as **Ω**, is an Asymptotic Notation for the best case, or a floor growth rate for a given function. It provides us with an _**asymptotic lower bound**_ for the growth rate of the runtime of an algorithm. `f(n)` is Ω(g(n)), if for some real constants c (c > 0) and n0 (n0 > 0), `f(n)` is >= `c g(n)` for every input size n (n > n0). ### Note The asymptotic growth rates provided by big-O and big-omega notation may or may not be asymptotically tight. Thus we use small-o and small-omega notation to denote bounds that are not asymptotically tight. ### Small-o Small-o, commonly written as **o**, is an Asymptotic Notation to denote the upper bound (that is not asymptotically tight) on the growth rate of runtime of an algorithm. `f(n)` is o(g(n)), if for all real constants c (c > 0) and n0 (n0 > 0), `f(n)` is < `c g(n)` for every input size n (n > n0). The definitions of O-notation and o-notation are similar. The main difference is that in f(n) = O(g(n)), the bound f(n) <= g(n) holds for _**some**_ constant c > 0, but in f(n) = o(g(n)), the bound f(n) < c g(n) holds for _**all**_ constants c > 0. ### Small-omega Small-omega, commonly written as **ω**, is an Asymptotic Notation to denote the lower bound (that is not asymptotically tight) on the growth rate of runtime of an algorithm. `f(n)` is ω(g(n)), if for all real constants c (c > 0) and n0 (n0 > 0), `f(n)` is > `c g(n)` for every input size n (n > n0). The definitions of Ω-notation and ω-notation are similar. The main difference is that in f(n) = Ω(g(n)), the bound f(n) >= g(n) holds for _**some**_ constant c > 0, but in f(n) = ω(g(n)), the bound f(n) > c g(n) holds for _**all**_ constants c > 0. ### Theta Theta, commonly written as **Θ**, is an Asymptotic Notation to denote the _**asymptotically tight bound**_ on the growth rate of runtime of an algorithm. `f(n)` is Θ(g(n)), if for some real constants c1, c2 and n0 (c1 > 0, c2 > 0, n0 > 0), `c1 g(n)` is < `f(n)` is < `c2 g(n)` for every input size n (n > n0). ∴ `f(n)` is Θ(g(n)) implies `f(n)` is O(g(n)) as well as `f(n)` is Ω(g(n)). Feel free to head over to additional resources for examples on this. Big-O is the primary notation use for general algorithm time complexity. ### Endnotes It's hard to keep this kind of topic short, and you should go through the books and online resources listed. They go into much greater depth with definitions and examples. More where x='Algorithms & Data Structures' is on its way; we'll have a doc up on analyzing actual code examples soon. ## Books * [Algorithms](http://www.amazon.com/Algorithms-4th-Robert-Sedgewick/dp/032157351X) * [Algorithm Design](http://www.amazon.com/Algorithm-Design-Foundations-Analysis-Internet/dp/0471383651) ## Online Resources * [MIT](http://web.mit.edu/16.070/www/lecture/big_o.pdf) * [KhanAcademy](https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/asymptotic-notation) * [Big-O Cheatsheet](http://bigocheatsheet.com/) - common structures, operations, and algorithms, ranked by complexity. ================================================ FILE: ats.md ================================================ --- name: ATS contributors: - ["Mark Barbone", "https://github.com/mb64"] filename: learnats.dats --- ATS is a low-level functional programming language. It has a powerful type system which lets you write programs with the same level of control and efficiency as C, but in a memory safe and type safe way. The ATS type system supports: * Full type erasure: ATS compiles to efficient C * Dependent types, including [LF](http://twelf.org/wiki/LF) and proving metatheorems * Refinement types * Linearity for resource tracking * An effect system that tracks exceptions, mutation, termination, and other side effects This tutorial is not an introduction to functional programming, dependent types, or linear types, but rather to how they all fit together in ATS. That said, ATS is a very complex language, and this tutorial doesn't cover it all. Not only does ATS's type system boast a wide array of confusing features, its idiosyncratic syntax can make even "simple" examples hard to understand. In the interest of keeping it a reasonable length, this document is meant to give a taste of ATS, giving a high-level overview of what's possible and how, rather than attempting to fully explain how everything works. You can [try ATS in your browser](http://www.ats-lang.org/SERVER/MYCODE/Patsoptaas_serve.php), or install it from [http://www.ats-lang.org/](http://www.ats-lang.org/). ```ocaml // Include the standard library #include "share/atspre_define.hats" #include "share/atspre_staload.hats" // To compile, either use // $ patscc -DATS_MEMALLOC_LIBC program.dats -o program // or install the ats-acc wrapper https://github.com/sparverius/ats-acc and use // $ acc pc program.dats // C-style line comments /* and C-style block comments */ (* as well as ML-style block comments *) /*************** Part 1: the ML fragment ****************/ val () = print "Hello, World!\n" // No currying fn add (x: int, y: int) = x + y // fn vs fun is like the difference between let and let rec in OCaml/F# fun fact (n: int): int = if n = 0 then 1 else n * fact (n-1) // Multi-argument functions need parentheses when you call them; single-argument // functions can omit parentheses val forty_three = add (fact 4, 19) // let is like let in SML fn sum_and_prod (x: int, y: int): (int, int) = let val sum = x + y val prod = x * y in (sum, prod) end // 'type' is the type of all heap-allocated, non-linear types // Polymorphic parameters go in {} after the function name fn id {a:type} (x: a) = x // ints aren't heap-allocated, so we can't pass them to 'id' // val y: int = id 7 // doesn't compile // 't@ype' is the type of all non-linear potentially unboxed types. It is a // supertype of 'type'. // Templated parameters go in {} before the function name fn {a:t@ype} id2 (x: a) = x val y: int = id2 7 // works // can't have polymorphic t@ype parameters // fn id3 {a:t@ype} (x: a) = x // doesn't compile // explicitly specifying type parameters: fn id4 {a:type} (x: a) = id {a} x // {} for non-template parameters fn id5 {a:type} (x: a) = id2 x // <> for template parameters fn id6 {a:type} (x: a) = id {..} x // {..} to explicitly infer it // Heap allocated shareable datatypes // using datatypes leaks memory datatype These (a:t@ype, b:t@ype) = This of a | That of b | These of (a, b) // Pattern matching using 'case' fn {a,b: t@ype} from_these (x: a, y: b, these: These(a,b)): (a, b) = case these of | This(x) => (x, y) // Shadowing of variable names is fine; here, x shadows // the parameter x | That(y) => (x, y) | These(x, y) => (x, y) // Partial pattern match using 'case-' // Will throw an exception if passed This fn {a,b:t@ype} unwrap_that (these: These(a,b)): b = case- these of | That(y) => y | These(_, y) => y /*************** Part 2: refinements ****************/ // Parameterize functions by what values they take and return fn cool_add {n:int} {m:int} (x: int n, y: int m): int (n+m) = x + y // list(a, n) is a list of n a's fun square_all {n:int} (xs: list(int, n)): list(int, n) = case xs of | list_nil() => list_nil() | list_cons(x, rest) => list_cons(x * x, square_all rest) fn {a:t@ype} get_first {n:int | n >= 1} (xs: list(a, n)): a = case+ xs of // '+' asks ATS to prove it's total | list_cons(x, _) => x // Can't run get_first on lists of length 0 // val x: int = get_first (list_nil()) // doesn't compile // in the stdlib: // sortdef nat = {n:int | n >= 0} // sortdef pos = {n:int | n >= 1} fn {a:t@ype} also_get_first {n:pos} (xs: list(a, n)): a = let val+ list_cons(x, _) = xs // val+ also works in x end // tail-recursive reverse fun {a:t@ype} reverse {n:int} (xs: list(a, n)): list(a, n) = let // local functions can use type variables from their enclosing scope // this one uses both 'a' and 'n' fun rev_helper {i:nat} (xs: list(a, n-i), acc: list(a, i)): list(a, n) = case xs of | list_nil() => acc | list_cons(x, rest) => rev_helper(rest, list_cons(x, acc)) in rev_helper(xs, list_nil) end // ATS has three context-dependent namespaces // the two 'int's mean different things in this example, as do the two 'n's fn namespace_example {n:int} (n: int n): int n = n // ^^^ sort namespace // ^ ^^^ ^ ^^^ ^ statics namespace // ^^^^^^^^^^^^^^^^^ ^ ^ value namespace // a termination metric can go in .< >. // it must decrease on each recursive call // then ATS will prove it doesn't infinitely recurse fun terminating_factorial {n:nat} .. (n: int n): int = if n = 0 then 1 else n * terminating_factorial (n-1) /*************** Part 3: the LF fragment ****************/ // ATS supports proving theorems in LF (http://twelf.org/wiki/LF) // Relations are represented by inductive types // Proofs that the nth fibonacci number is f dataprop Fib(n:int, m:int) = | FibZero(0, 0) | FibOne(1, 1) | {n, f1, f2: int} FibInd(n, f1 + f2) of (Fib(n-1,f1), Fib(n-2,f2)) // Proved-correct fibonacci implementation // [A] B is an existential type: "there exists A such that B" // (proof | value) fun fib {n:nat} .. (n: int n): [f:int] (Fib(n,f) | int f) = if n = 0 then (FibZero | 0) else if n = 1 then (FibOne | 1) else let val (proof1 | val1) = fib (n-1) val (proof2 | val2) = fib (n-2) // the existential type is inferred in (FibInd(proof1, proof2) | val1 + val2) end // Faster proved-correct fibonacci implementation fn fib_tail {n:nat} (n: int n): [f:int] (Fib(n,f) | int f) = let fun loop {i:int | i < n} {f1, f2: int} .. (p1: Fib(i,f1), p2: Fib(i+1,f2) | i: int i, f1: int f1, f2: int f2, n: int n ): [f:int] (Fib(n,f) | int f) = if i = n - 1 then (p2 | f2) else loop (p2, FibInd(p2,p1) | i+1, f2, f1+f2, n) in if n = 0 then (FibZero | 0) else loop (FibZero, FibOne | 0, 0, 1, n) end // Proof-level lists of ints, of type 'sort' datasort IntList = ILNil of () | ILCons of (int, IntList) // ILAppend(x,y,z) iff x ++ y = z dataprop ILAppend(IntList, IntList, IntList) = | {y:IntList} AppendNil(ILNil, y, y) | {a:int} {x,y,z: IntList} AppendCons(ILCons(a,x), y, ILCons(a,z)) of ILAppend(x,y,z) // prfuns/prfns are compile-time functions acting on proofs // metatheorem: append is total prfun append_total {x,y: IntList} .. (): [z:IntList] ILAppend(x,y,z) = scase x of // scase lets you inspect static arguments (only in prfuns) | ILNil() => AppendNil | ILCons(a,rest) => AppendCons(append_total()) /*************** Part 4: views ****************/ // views are like props, but linear; ie they must be consumed exactly once // prop is a subtype of view // 'type @ address' is the most basic view fn {a:t@ype} read_ptr {l:addr} (pf: a@l | p: ptr l): (a@l | a) = let // !p searches for usable proofs that say something is at that address val x = !p in (pf | x) end // oops, tried to dereference a potentially invalid pointer // fn {a:t@ype} bad {l:addr} (p: ptr l): a = !p // doesn't compile // oops, dropped the proof (leaked the memory) // fn {a:t@ype} bad {l:addr} (pf: a@l | p: ptr l): a = !p // doesn't compile fn inc_at_ptr {l:addr} (pf: int@l | p: ptr l): (int@l | void) = let // !p := value writes value to the location at p // like !p, it implicitly searches for usable proofs that are in scope val () = !p := !p + 1 in (pf | ()) end // threading proofs through gets annoying fn inc_three_times {l:addr} (pf: int@l | p: ptr l): (int@l | void) = let val (pf2 | ()) = inc_at_ptr (pf | p) val (pf3 | ()) = inc_at_ptr (pf2 | p) val (pf4 | ()) = inc_at_ptr (pf3 | p) in (pf4 | ()) end // so there's special syntactic sugar for when you don't consume a proof fn dec_at_ptr {l:addr} (pf: !int@l | p: ptr l): void = !p := !p - 1 // ^ note the exclamation point fn dec_three_times {l:addr} (pf: !int@l | p: ptr l): void = let val () = dec_at_ptr (pf | p) val () = dec_at_ptr (pf | p) val () = dec_at_ptr (pf | p) in () end // dataview is like dataprop, but linear // A proof that either the address is null, or there is a value there dataview MaybeNull(a:t@ype, addr) = | NullPtr(a, null) | {l:addr | l > null} NonNullPtr(a, l) of (a @ l) fn maybe_inc {l:addr} (pf: !MaybeNull(int, l) | p: ptr l): void = if ptr1_is_null p then () else let // Deconstruct the proof to access the proof of a @ l prval NonNullPtr(value_exists) = pf val () = !p := !p + 1 // Reconstruct it again for the caller prval () = pf := NonNullPtr(value_exists) in () end // array_v(a,l,n) represents and array of n a's at location l // this gets compiled into an efficient for loop, since all proofs are erased fn sum_array {l:addr}{n:nat} (pf: !array_v(int,l,n) | p: ptr l, n: int n): int = let fun loop {l:addr}{n:nat} .. ( pf: !array_v(int,l,n) | ptr: ptr l, length: int n, acc: int ): int = if length = 0 then acc else let prval (head, rest) = array_v_uncons(pf) val result = loop(rest | ptr_add(ptr, 1), length - 1, acc + !ptr) prval () = pf := array_v_cons(head, rest) in result end in loop (pf | p, n, 0) end // 'var' is used to create stack-allocated (lvalue) variables val seven: int = let var res: int = 3 // they can be modified val () = res := res + 1 // addr@ res is a pointer to it, and view@ res is the associated proof val (pf | ()) = inc_three_times(view@ res | addr@ res) // need to give back the view before the variable goes out of scope prval () = view@ res := pf in res end // References let you pass lvalues, like in C++ fn square (x: &int): void = x := x * x // they can be modified val sixteen: int = let var res: int = 4 val () = square res in res end fn inc_at_ref (x: &int): void = let // like vars, references have views and addresses val (pf | ()) = inc_at_ptr(view@ x | addr@ x) prval () = view@ x := pf in () end // Like ! for views, & references are only legal as argument types // fn bad (x: &int): &int = x // doesn't compile // this takes a proof int n @ l, but returns a proof int (n+1) @ l // since they're different types, we can't use !int @ l like before fn refined_inc_at_ptr {n:int}{l:addr} ( pf: int n @ l | p: ptr l ): (int (n+1) @ l | void) = let val () = !p := !p + 1 in (pf | ()) end // special syntactic sugar for returning a proof at a different type fn refined_dec_at_ptr {n:int}{l:addr} ( pf: !int n @ l >> int (n-1) @ l | p: ptr l ): void = !p := !p - 1 // legal but very bad code prfn swap_proofs {v1,v2:view} (a: !v1 >> v2, b: !v2 >> v1): void = let prval tmp = a prval () = a := b prval () = b := tmp in () end // also works with references fn refined_square {n:int} (x: &int n >> int (n*n)): void = x := x * x fn replace {a,b:vtype} (dest: &a >> b, src: b): a = let val old = dest val () = dest := src in old end // values can be uninitialized fn {a:vt@ype} write (place: &a? >> a, value: a): void = place := value val forty: int = let var res: int val () = write (res, 40) in res end // viewtype: a view and a type viewtypedef MaybeNullPtr(a:t@ype) = [l:addr] (MaybeNull(a, l) | ptr l) // MaybeNullPtr has type 'viewtype' (aka 'vtype') // type is a subtype of vtype and t@ype is a subtype of vt@ype // The most general identity function: fn {a:vt@ype} id7 (x: a) = x // since they contain views, viewtypes must be used linearly // fn {a:vt@ype} duplicate (x: a) = (x, x) // doesn't compile // fn {a:vt@ype} ignore (x: a) = () // doesn't compile // arrayptr(a,l,n) is a convenient built-in viewtype fn easier_sum_array {l:addr}{n:nat} (p: !arrayptr(int,l,n), n: int n): int = let fun loop {i:nat | i <= n} ( p: !arrayptr(int,l,n), n: int n, i: int i, acc: int ): int = if i = n then acc else loop(p, n, i+1, acc + p[i]) in loop(p, n, 0, 0) end /*************** Part 5: dataviewtypes ****************/ // a dataviewtype is a heap-allocated non-shared inductive type // in the stdlib: // dataviewtype list_vt(a:vt@ype, int) = // | list_vt_nil(a, 0) // | {n:nat} list_vt_cons(a, n+1) of (a, list_vt(a, n)) fn {a:vt@ype} length {n:int} (l: !list_vt(a, n)): int n = let // ^ since we're not consuming it fun loop {acc:int} (l: !list_vt(a, n-acc), acc: int acc): int n = case l of | list_vt_nil() => acc | list_vt_cons(head, tail) => loop(tail, acc + 1) in loop (l, 0) end // vvvvv not vt@ype, because you can't easily get rid of a vt@ype fun {a:t@ype} destroy_list {n:nat} (l: list_vt(a,n)): void = case l of // ~ pattern match consumes and frees that node | ~list_vt_nil() => () | ~list_vt_cons(_, tail) => destroy_list tail // unlike a datatype, a dataviewtype can be modified: fun {a:vt@ype} push_back {n:nat} ( x: a, l: &list_vt(a,n) >> list_vt(a,n+1) ): void = case l of | ~list_vt_nil() => l := list_vt_cons(x, list_vt_nil) // @ pattern match disassembles/"unfolds" the datavtype's view, so you can // modify its components | @list_vt_cons(head, tail) => let val () = push_back (x, tail) // reassemble it with fold@ prval () = fold@ l in () end fun {a:vt@ype} pop_last {n:pos} (l: &list_vt(a,n) >> list_vt(a,n-1)): a = let val+ @list_vt_cons(head, tail) = l in case tail of | list_vt_cons _ => let val res = pop_last tail prval () = fold@ l in res end | ~list_vt_nil() => let val head = head // Deallocate empty datavtype nodes with free@ val () = free@{..}{0} l val () = l := list_vt_nil() in head end /** Equivalently: * | ~list_vt_nil() => let * prval () = fold@ l * val+ ~list_vt_cons(head, ~list_vt_nil()) = l * val () = l := list_vt_nil() * in head end */ end // "holes" (ie uninitialized memory) can be created with _ on the RHS // This function uses destination-passing-style to copy the list in a single // tail-recursive pass. fn {a:t@ype} copy_list {n:nat} (l: !list_vt(a, n)): list_vt(a, n) = let var res: ptr fun loop {k:nat} (l: !list_vt(a, k), hole: &ptr? >> list_vt(a, k)): void = case l of | list_vt_nil() => hole := list_vt_nil | list_vt_cons(first, rest) => let val () = hole := list_vt_cons{..}{k-1}(first, _) // ^ on RHS: a hole val+list_vt_cons(_, new_hole) = hole // ^ on LHS: wildcard pattern (not a hole) val () = loop (rest, new_hole) prval () = fold@ hole in () end val () = loop (l, res) in res end // Reverse a linked-list *in place* -- no allocations or frees fn {a:vt@ype} in_place_reverse {n:nat} (l: list_vt(a, n)): list_vt(a, n) = let fun loop {k:nat} (l: list_vt(a, n-k), acc: list_vt(a, k)): list_vt(a, n) = case l of | ~list_vt_nil() => acc | @list_vt_cons(x, tail) => let val rest = replace(tail, acc) // the node 'l' is now part of acc instead of the original list prval () = fold@ l in loop (rest, l) end in loop (l, list_vt_nil) end /*************** Part 6: miscellaneous extras ****************/ // a record // Point has type 't@ype' typedef Point = @{ x= int, y= int } val origin: Point = @{ x= 0, y= 0 } // tuples and records are normally unboxed, but there are boxed variants // BoxedPoint has type 'type' typedef BoxedPoint = '{ x= int, y= int } val boxed_pair: '(int,int) = '(5, 3) // When passing a pair as the single argument to a function, it needs to be // written @(a,b) to avoid ambiguity with multi-argument functions val six_plus_seven = let fun sum_of_pair (pair: (int,int)) = pair.0 + pair.1 in sum_of_pair @(6, 7) end // When a constructor has no associated data, such as None(), the parentheses // are optional in expressions. However, they are mandatory in patterns fn inc_option (opt: Option int) = case opt of | Some(x) => Some(x+1) | None() => None // ATS has a simple FFI, since it compiles to C and (mostly) uses the C ABI %{ // Inline C code int scanf_wrapper(void *format, void *value) { return scanf((char *) format, (int *) value); } %} // If you wanted to, you could define a custom dataviewtype more accurately // describing the result of scanf extern fn scanf (format: string, value: &int): int = "scanf_wrapper" fn get_input_number (): Option int = let var x: int = 0 in if scanf("%d\n", x) = 1 then Some(x) else None end // extern is also used for separate declarations and definitions extern fn say_hi (): void // later on, or in another file: implement say_hi () = print "hi\n" // if you implement main0, it will run as the main function // implmnt is an alias for implement implmnt main0 () = () // as well as for axioms: extern praxi view_id {a:view} (x: a): a // you don't need to actually implement the axioms, but you could primplmnt view_id x = x // primplmnt is an alias for primplement // Some standard aliases are: // List0(a) = [n:nat] list(a,n) and List0_vt(a) = [n:nat] list_vt(a,n) // t0p = t@ype and vt0p = vt@ype fun {a:t0p} append (xs: List0 a, ys: List0 a): List0 a = case xs of | list_nil() => ys | list_cons(x, xs) => list_cons(x, append(xs, ys)) // there are many ways of doing things after one another val let_in_example = let val () = print "thing one\n" val () = print "thing two\n" in () end val parens_example = (print "thing one\n"; print "thing two\n") val begin_end_example = begin print "thing one\n"; print "thing two\n"; // optional trailing semicolon end // and many ways to use local variables fun times_four_let x = let fun times_two (x: int) = x * 2 in times_two (times_two x) end local fun times_two (x: int) = x * 2 in fun times_four_local x = times_two (times_two x) end fun times_four_where x = times_two (times_two x) where { fun times_two (x: int) = x * 2 } //// The last kind of comment in ATS is an end-of-file comment. Anything between the four slashes and the end of the file is ignored. Have fun with ATS! ``` ## Learn more This isn't all there is to ATS -- notably, some core features like closures and the effect system are left out, as well as other less type-y stuff like modules and the build system. If you'd like to write these sections yourself, contributions would be welcome! To learn more about ATS, visit the [ATS website](http://www.ats-lang.org/), in particular the [documentation page](http://www.ats-lang.org/Documents.html). ================================================ FILE: awk.md ================================================ --- category: tool name: AWK filename: learnawk.awk contributors: - ["Marshall Mason", "http://github.com/marshallmason"] --- AWK is a standard tool on every POSIX-compliant UNIX system. It's like flex/lex, from the command-line, perfect for text-processing tasks and other scripting needs. It has a C-like syntax, but without mandatory semicolons (although, you should use them anyway, because they are required when you're writing one-liners, something AWK excels at), manual memory management, or static typing. It excels at text processing. You can call to it from a shell script, or you can use it as a stand-alone scripting language. Why use AWK instead of Perl? Readability. AWK is easier to read than Perl. For simple text-processing scripts, particularly ones that read files line by line and split on delimiters, AWK is probably the right tool for the job. ```awk #!/usr/bin/awk -f # Comments are like this # AWK programs consist of a collection of patterns and actions. pattern1 { action; } # just like lex pattern2 { action; } # There is an implied loop and AWK automatically reads and parses each # record of each file supplied. Each record is split by the FS delimiter, # which defaults to white-space (multiple spaces,tabs count as one) # You can assign FS either on the command line (-F C) or in your BEGIN # pattern # One of the special patterns is BEGIN. The BEGIN pattern is true # BEFORE any of the files are read. The END pattern is true after # an End-of-file from the last file (or standard-in if no files specified) # There is also an output field separator (OFS) that you can assign, which # defaults to a single space BEGIN { # BEGIN will run at the beginning of the program. It's where you put all # the preliminary set-up code, before you process any text files. If you # have no text files, then think of BEGIN as the main entry point. # Variables are global. Just set them or use them, no need to declare. count = 0; # Operators just like in C and friends a = count + 1; b = count - 1; c = count * 1; d = count / 1; # integer division e = count % 1; # modulus f = count ^ 1; # exponentiation a += 1; b -= 1; c *= 1; d /= 1; e %= 1; f ^= 1; # Incrementing and decrementing by one a++; b--; # As a prefix operator, it returns the incremented value ++a; --b; # Notice, also, no punctuation such as semicolons to terminate statements # Control statements if (count == 0) print "Starting with count of 0"; else print "Huh?"; # Or you could use the ternary operator print (count == 0) ? "Starting with count of 0" : "Huh?"; # Blocks consisting of multiple lines use braces while (a < 10) { print "String concatenation is done" " with a series" " of" " space-separated strings"; print a; a++; } for (i = 0; i < 10; i++) print "Good ol' for loop"; # As for comparisons, they're the standards: # a < b # Less than # a <= b # Less than or equal # a != b # Not equal # a == b # Equal # a > b # Greater than # a >= b # Greater than or equal # Logical operators as well # a && b # AND # a || b # OR # In addition, there's the super useful regular expression match if ("foo" ~ "^fo+$") print "Fooey!"; if ("boo" !~ "^fo+$") print "Boo!"; # Arrays arr[0] = "foo"; arr[1] = "bar"; # You can also initialize an array with the built-in function split() n = split("foo:bar:baz", arr, ":"); # You also have associative arrays (indeed, they're all associative arrays) assoc["foo"] = "bar"; assoc["bar"] = "baz"; # And multi-dimensional arrays, with some limitations I won't mention here multidim[0,0] = "foo"; multidim[0,1] = "bar"; multidim[1,0] = "baz"; multidim[1,1] = "boo"; # You can test for array membership if ("foo" in assoc) print "Fooey!"; # You can also use the 'in' operator to traverse the keys of an array for (key in assoc) print assoc[key]; # The command line is in a special array called ARGV for (argnum in ARGV) print ARGV[argnum]; # You can remove elements of an array # This is particularly useful to prevent AWK from assuming the arguments # are files for it to process delete ARGV[1]; # The number of command line arguments is in a variable called ARGC print ARGC; # AWK has several built-in functions. They fall into three categories. I'll # demonstrate each of them in their own functions, defined later. return_value = arithmetic_functions(a, b, c); string_functions(); io_functions(); } # Here's how you define a function function arithmetic_functions(a, b, c, d) { # Probably the most annoying part of AWK is that there are no local # variables. Everything is global. For short scripts, this is fine, even # useful, but for longer scripts, this can be a problem. # There is a work-around (ahem, hack). Function arguments are local to the # function, and AWK allows you to define more function arguments than it # needs. So just stick local variable in the function declaration, like I # did above. As a convention, stick in some extra whitespace to distinguish # between actual function parameters and local variables. In this example, # a, b, and c are actual parameters, while d is merely a local variable. # Now, to demonstrate the arithmetic functions # Most AWK implementations have some standard trig functions d = sin(a); d = cos(a); d = atan2(b, a); # arc tangent of b / a # And logarithmic stuff d = exp(a); d = log(a); # Square root d = sqrt(a); # Truncate floating point to integer d = int(5.34); # d => 5 # Random numbers srand(); # Supply a seed as an argument. By default, it uses the time of day d = rand(); # Random number between 0 and 1. # Here's how to return a value return d; } function string_functions( localvar, arr) { # AWK, being a string-processing language, has several string-related # functions, many of which rely heavily on regular expressions. # Search and replace, first instance (sub) or all instances (gsub) # Both return number of matches replaced localvar = "fooooobar"; sub("fo+", "Meet me at the ", localvar); # localvar => "Meet me at the bar" gsub("e", ".", localvar); # localvar => "M..t m. at th. bar" # Search for a string that matches a regular expression # index() does the same thing, but doesn't allow a regular expression match(localvar, "t"); # => 4, since the 't' is the fourth character # Split on a delimiter n = split("foo-bar-baz", arr, "-"); # result: arr[1] = "foo"; arr[2] = "bar"; arr[3] = "baz"; n = 3 # Other useful stuff sprintf("%s %d %d %d", "Testing", 1, 2, 3); # => "Testing 1 2 3" substr("foobar", 2, 3); # => "oob" substr("foobar", 4); # => "bar" length("foo"); # => 3 tolower("FOO"); # => "foo" toupper("foo"); # => "FOO" } function io_functions( localvar) { # You've already seen print print "Hello world"; # There's also printf printf("%s %d %d %d\n", "Testing", 1, 2, 3); # AWK doesn't have file handles, per se. It will automatically open a file # handle for you when you use something that needs one. The string you used # for this can be treated as a file handle, for purposes of I/O. This makes # it feel sort of like shell scripting, but to get the same output, the # string must match exactly, so use a variable: outfile = "/tmp/foobar.txt"; print "foobar" > outfile; # Now the string outfile is a file handle. You can close it: close(outfile); # Here's how you run something in the shell system("echo foobar"); # => prints foobar # Reads a line from standard input and stores in localvar getline localvar; # Reads a line from a pipe (again, use a string so you close it properly) cmd = "echo foobar"; cmd | getline localvar; # localvar => "foobar" close(cmd); # Reads a line from a file and stores in localvar infile = "/tmp/foobar.txt"; getline localvar < infile; close(infile); } # As I said at the beginning, AWK programs consist of a collection of patterns # and actions. You've already seen the BEGIN pattern. Other # patterns are used only if you're processing lines from files or standard # input. # # When you pass arguments to AWK, they are treated as file names to process. # It will process them all, in order. Think of it like an implicit for loop, # iterating over the lines in these files. these patterns and actions are like # switch statements inside the loop. /^fo+bar$/ { # This action will execute for every line that matches the regular # expression, /^fo+bar$/, and will be skipped for any line that fails to # match it. Let's just print the line: print; # Whoa, no argument! That's because print has a default argument: $0. # $0 is the name of the current line being processed. It is created # automatically for you. # You can probably guess there are other $ variables. Every line is # implicitly split before every action is called, much like the shell # does. And, like the shell, each field can be access with a dollar sign # This will print the second and fourth fields in the line print $2, $4; # AWK automatically defines many other variables to help you inspect and # process each line. The most important one is NF # Prints the number of fields on this line print NF; # Print the last field on this line print $NF; } # Every pattern is actually a true/false test. The regular expression in the # last pattern is also a true/false test, but part of it was hidden. If you # don't give it a string to test, it will assume $0, the line that it's # currently processing. Thus, the complete version of it is this: $0 ~ /^fo+bar$/ { print "Equivalent to the last pattern"; } a > 0 { # This will execute once for each line, as long as a is positive } # You get the idea. Processing text files, reading in a line at a time, and # doing something with it, particularly splitting on a delimiter, is so common # in UNIX that AWK is a scripting language that does all of it for you, without # you needing to ask. All you have to do is write the patterns and actions # based on what you expect of the input, and what you want to do with it. # Here's a quick example of a simple script, the sort of thing AWK is perfect # for. It will read a name from standard input and then will print the average # age of everyone with that first name. Let's say you supply as an argument the # name of a this data file: # # Bob Jones 32 # Jane Doe 22 # Steve Stevens 83 # Bob Smith 29 # Bob Barker 72 # # Here's the script: BEGIN { # First, ask the user for the name print "What name would you like the average age for?"; # Get a line from standard input, not from files on the command line getline name < "/dev/stdin"; } # Now, match every line whose first field is the given name $1 == name { # Inside here, we have access to a number of useful variables, already # pre-loaded for us: # $0 is the entire line # $3 is the third field, the age, which is what we're interested in here # NF is the number of fields, which should be 3 # NR is the number of records (lines) seen so far # FILENAME is the name of the file being processed # FS is the field separator being used, which is " " here # ...etc. There are plenty more, documented in the man page. # Keep track of a running total and how many lines matched sum += $3; nlines++; } # Another special pattern is called END. It will run after processing all the # text files. Unlike BEGIN, it will only run if you've given it input to # process. It will run after all the files have been read and processed # according to the rules and actions you've provided. The purpose of it is # usually to output some kind of final report, or do something with the # aggregate of the data you've accumulated over the course of the script. END { if (nlines) print "The average age for " name " is " sum / nlines; } ``` Further Reading: * [Awk tutorial](http://www.grymoire.com/Unix/Awk.html) * [Awk man page](https://linux.die.net/man/1/awk) * [The GNU Awk User's Guide](https://www.gnu.org/software/gawk/manual/gawk.html) GNU Awk is found on most Linux systems. * [AWK one-liner collection](http://tuxgraphics.org/~guido/scripts/awk-one-liner.html) * [Awk alpinelinux wiki](https://wiki.alpinelinux.org/wiki/Awk) a technical summary and list of "gotchas" (places where different implementations may behave in different or unexpected ways). * [basic libraries for awk](https://github.com/dubiousjim/awkenough) ================================================ FILE: ballerina.md ================================================ --- name: Ballerina contributors: - ["Anjana Fernando", "https://github.com/lafernando"] filename: learn_ballerina.bal --- [Ballerina](https://ballerina.io/) is a statically-typed programming language for making development for the cloud an enjoyable experience. ```java // Single-line comment // Import modules into the current source file import ballerina/io; import ballerina/time; import ballerina/http; import ballerinax/java.jdbc; import ballerina/lang.'int as ints; import ballerinax/awslambda; // Module alias "af" used in code in place of the full module name import ballerinax/azure.functions as af; http:Client clientEP = new ("https://freegeoip.app/"); jdbc:Client accountsDB = new ({url: "jdbc:mysql://localhost:3306/AccountsDB", username: "test", password: "test"}); // A service is a first-class concept in Ballerina, and is one of the // entrypoints to a Ballerina program. // The Ballerina platform also provides support for easy deployment to // environments such as Kubernetes (https://ballerina.io/learn/deployment/kubernetes/). service geoservice on new http:Listener(8080) { @http:ResourceConfig { path: "/geoip/{ip}" } resource function geoip(http:Caller caller, http:Request request, string ip) returns @tainted error? { http:Response resp = check clientEP->get("/json/" + <@untainted>ip); check caller->respond(<@untainted> check resp.getTextPayload()); } } // Serverless Function-as-a-Service support with AWS Lambda. // The Ballerina compiler automatically generates the final deployment // artifact to be deployed. @awslambda:Function public function echo(awslambda:Context ctx, json input) returns json { return input; } @awslambda:Function public function notifyS3(awslambda:Context ctx, awslambda:S3Event event) returns json { return event.Records[0].s3.'object.key; } // Serverless Function-as-a-Service support with Azure Functions. // Similar to AWS Lambda, the compiler generates the deployment artifacts. @af:Function public function fromQueueToQueue(af:Context ctx, @af:QueueTrigger { queueName: "queue1" } string inMsg, @af:QueueOutput { queueName: "queue2" } af:StringOutputBinding outMsg) { outMsg.value = inMsg; } // A custom record type public type Person record { string id; // required field string name; int age?; // optional field string country = "N/A"; // default value }; @af:Function public function fromHttpTriggerCosmosDBInput( @af:HTTPTrigger { route: "c1/{country}" } af:HTTPRequest httpReq, @af:CosmosDBInput { connectionStringSetting: "CosmosDBConnection", databaseName: "db1", collectionName: "c1", sqlQuery: "select * from c1 where c1.country = {country}" } Person[] dbReq) returns @af:HTTPOutput string|error { return dbReq.toString(); } public function main() returns @tainted error? { int a = 10; // 64-bit signed integer float b = 1.56; // 64-bit IEEE 754-2008 binary floating point number string c = "hello"; // a unicode string boolean d = true; // true, false decimal e = 15.335; // decimal floating point number var f = 20; // type inference with 'var' - 'f' is an int int[] intArray = [1, 2, 3, 4, 5, 6]; int x = intArray.shift(); // similar to a dequeue operation x = intArray.pop(); // removes the last element intArray.push(10); // add to the end // Tuples - similar to a fixed length array with a distinct type for each slot [string, int] p1 = ["Jack", 1990]; [string, int] p2 = ["Tom", 1986]; io:println("Name: ", p1[0], " Birth Year: ", p1[1]); string name1; int birthYear1; [name1, birthYear1] = p1; // tuple destructuring var [name2, birthYear2] = p2; // declare and assign values in the same statement // If statements int ix = 10; if ix < 10 { io:println("value is less than 10"); } else if ix == 10 { io:println("value equals to 10"); } else { io:println("value is greater than 10"); } // Loops int count = 10; int i = 0; while i < 10 { io:println(i); } // Loop from 0 to count (inclusive) foreach var j in 0...count { io:println(j); } // Loop from 0 to count (non-inclusive) foreach var j in 0..{{name1}}{{birthYear1}}`; io:println(x1); // Access specific elements in the XML value io:println(x1/); // List all child items in the XML value io:println(x1/*); // Function invocations x = add(1, 2); io:println(multiply(2, 4)); // Invocation providing value for the defaultable parameter io:println(multiply(3, 4, true)); // Invocation with values to a rest parameter (multi-valued) io:println(addAll(1, 2, 3)); io:println(addAll(1, 2, 3, 4, 5)); // Function pointers (function (int, int) returns int) op1 = getOperation("add"); (function (int, int) returns int) op2 = getOperation("mod"); io:println(op1(5, 10)); io:println(op2(13, 10)); // Closures (function (int x) returns int) add5 = getAdder(5); (function (int x) returns int) add10 = getAdder(10); io:println(add5(10)); io:println(add10(10)); int[] numbers = [1, 2, 3, 4, 5, 6, 7, 8]; // Functional iteration int[] evenNumbers = numbers.filter(function (int x) returns boolean { return x % 2 == 0; }); // Union types - "input" is of type either string or byte[] string|byte[] uval = "XXX"; // A type test expression ("uval is string") can be used to check the // runtime type of a variable. if uval is string { // In the current scope, "uval" is a string value string data = "data:" + uval; } else { // Since the expression in the "if" statement ruled out that it's not a string, // the only type left is "byte[]"; so in the current scope, "uval" will always // be a "byte[]". int inputLength = uval.length(); } // Error handling string input = io:readln("Enter number: "); int|error result = ints:fromString(input); if result is int { io:println("Number: ", result); } else { io:println("Invalid number: ", input); } // A check expression can be used to directly return the error from // the current function if its subexpression evaluated to an error // value in the runtime. int number = check ints:fromString(input); // Concurrent execution using workers in a function doWorkers(); // Asynchronous execution with futures future f10 = start fib(10); var webresult = clientEP->get("/"); int fresult = wait f10; if webresult is http:Response { io:println(webresult.getTextPayload()); io:println(fresult); } // Mapping types map ageMap = {}; ageMap["Peter"] = 25; ageMap["John"] = 30; int? agePeter = ageMap["Peter"]; // int? is the union type int|() - int or nill if agePeter is int { io:println("Peter's age is ", agePeter); } else { io:println("Peter's age is not found"); } Person person1 = { id: "p1", name : "Anne", age: 28, country: "Sri Lanka" }; Scores score1 = { physics : 80, mathematics: 95 }; score1["chemistry"] = 75; io:println(score1["chemistry"]); Student student1 = { id: "s1", name: "Jack", age: 25, country: "Japan" }; student1.college = "Stanford"; string? jacksCollege = student1?.college; // optional field access if jacksCollege is string { io:println("Jack's college is ", jacksCollege); } // Due to the structural type system, "student1" can be assigned to "person2", // since the student1's structure is compatible with person2's, // where we can say, a "Student" is a "Person" as well. Person person2 = student1; map grades = {"Jack": 95, "Anne": 90, "John": 80, "Bill": 55}; Person px1 = {id: "px1", name: "Jack", age: 30, country: "Canada"}; Person px2 = {id: "px2", name: "John", age: 25}; Person px3 = {id: "px3", name: "Anne", age: 17, country: "UK"}; Person px4 = {id: "px4", name: "Bill", age: 15, country: "USA"}; Person[] persons = []; persons.push(px1); persons.push(px2); persons.push(px3); persons.push(px4); // Query expressions used to execute complex queries for list data Result[] results = from var person in persons let int lgrade = (grades[person.name] ?: 0) where lgrade > 75 let string targetCollege = "Stanford" select { name: person.name, college: targetCollege, grade: lgrade }; // Compile-time taint checking for handling untrusted data string s1 = "abc"; mySecureFunction(s1); // Explicitly make "s2" a tainted value. External input to a Ballerina // program such as command-line arguments and network input are by-default // marked as tainted data. string s2 = <@tainted> s1; // "s2x" is now a tainted value, since its value is derived using a // tainted value (s1). string s2x = s2 + "abc"; // The following line uncommented will result in a compilation error, // since we are passing a tainted value (s2x) to a function which // expects an untainted value. // mySecureFunction(s2x); // Instantiating objects Employee emp1 = new("E0001", "Jack Smith", "Sales", 2009); io:println("The company service duration of ", emp1.name, " is ", emp1.serviceDuration()); // Supported operations can be executed in a transaction by enclosing the actions // in a "transaction" block. transaction { // Executes the below database operations in a single local transactions var r1 = accountsDB->update("UPDATE Employee SET balance = balance + ? WHERE id = ?", 5500.0, "ID001"); var r2 = accountsDB->update("UPDATE Employee SET balance = balance + ? WHERE id = ?", 5500.0, "ID001"); } } // An object is a behavioural type, which encapsulates both data and functionality. type Employee object { // Private fields are only visible within the object and its methods private string empId; // Public fields can be accessed by anyone public string name; public string department; // The default qualifier is a "protected" field, // which are accessible only within the module. int yearJoined; // The object initialization function; automatically called when an object is instantiated. public function __init(string empId, string name, string department, int yearJoined) { self.empId = empId; self.name = name; self.department = department; self.yearJoined = yearJoined; } // An object method public function serviceDuration() returns int { time:Time ct = time:currentTime(); return time:getYear(ct) - self.yearJoined; } }; // Student is a subtype of Person type Student record { string id; string name; int age; string college?; string country; }; type Scores record { int physics; int mathematics; }; type Result record { string name; string college; int grade; }; public function getOperation(string op) returns (function (int, int) returns int) { if op == "add" { return add; } else if op == "mod" { return function (int a, int b) returns int { // anonymous function return a % b; }; } else { return (x, y) => 0; // single expression anonymous no-op function } } // Two required parameters public function add(int a, int b) returns int { return a + b; } // 'log' is a defaultable parameter public function multiply(int a, int b, boolean log = false) returns int { if log { io:println("Multiplying ", a, " with ", b); } return a * b; } // 'numbers' is a rest parameter - it can have multiple values, // similar to an array. public function addAll(int... numbers) returns int { int result = 0; foreach int number in numbers { result += number; } return result; } public function getAdder(int n) returns (function (int x) returns int) { return function (int x) returns int { // returns closure return x + n; }; } function fib(int n) returns int { if n <= 2 { return 1; } else { return fib(n - 1) + fib(n - 2); } } // The code in worker blocks "w1" and "w2" are executed concurrency // when this function is invoked. The "wait" expressions waits for // the given workers to finish to retrieve their results. public function doWorkers() { worker w1 returns int { int j = 10; j -> w2; int b; b = <- w2; return b * b; } worker w2 returns int { int a; a = <- w1; a * 2 -> w1; return a + 2; } record {int w1; int w2;} x = wait {w1, w2}; io:println(x); } // A function which takes in only an untainted string value. public function mySecureFunction(@untainted string input) { io:println(input); } ``` ### Further Reading * [Ballerina by Example](https://ballerina.io/learn/by-example/) * [User Guide](https://ballerina.io/learn/installing-ballerina/) * [API Documentation](https://ballerina.io/learn/api-docs/ballerina/) * [Language Specification](https://ballerina.io/spec/) ================================================ FILE: bash.md ================================================ --- name: Bash contributors: - ["Max Yankov", "https://github.com/golergka"] - ["Darren Lin", "https://github.com/CogBear"] - ["Alexandre Medeiros", "http://alemedeiros.sdf.org"] - ["Denis Arh", "https://github.com/darh"] - ["akirahirose", "https://twitter.com/akirahirose"] - ["Anton Strömkvist", "http://lutic.org/"] - ["Rahil Momin", "https://github.com/iamrahil"] - ["Gregrory Kielian", "https://github.com/gskielian"] - ["Etan Reisner", "https://github.com/deryni"] - ["Jonathan Wang", "https://github.com/Jonathansw"] - ["Leo Rudberg", "https://github.com/LOZORD"] - ["Betsy Lorton", "https://github.com/schbetsy"] - ["John Detter", "https://github.com/jdetter"] - ["Harry Mumford-Turner", "https://github.com/harrymt"] - ["Martin Nicholson", "https://github.com/mn113"] - ["Mark Grimwood", "https://github.com/MarkGrimwood"] - ["Emily Grace Seville", "https://github.com/EmilySeville7cfg"] filename: LearnBash.sh translators: - ["Dimitri Kokkonis", "https://github.com/kokkonisd"] --- Bash is a name of the unix shell, which was also distributed as the shell for the GNU operating system and as the default shell on most Linux distros. Nearly all examples below can be a part of a shell script or executed directly in the shell. ```bash #!/usr/bin/env bash # First line of the script is the shebang which tells the system how to execute # the script: https://en.wikipedia.org/wiki/Shebang_(Unix) # As you already figured, comments start with #. Shebang is also a comment. # Simple hello world example: echo "Hello world!" # => Hello world! # Each command starts on a new line, or after a semicolon: echo "This is the first command"; echo "This is the second command" # => This is the first command # => This is the second command # Declaring a variable looks like this: variable="Some string" # But not like this: variable = "Some string" # => returns error "variable: command not found" # Bash will decide that `variable` is a command it must execute and give an error # because it can't be found. # Nor like this: variable= "Some string" # => returns error: "Some string: command not found" # Bash will decide that "Some string" is a command it must execute and give an # error because it can't be found. In this case the "variable=" part is seen # as a variable assignment valid only for the scope of the "Some string" # command. # Using the variable: echo "$variable" # => Some string echo '$variable' # => $variable # When you use a variable itself — assign it, export it, or else — you write # its name without $. If you want to use the variable's value, you should use $. # Note that ' (single quote) won't expand variables! # You can write variables without surrounding double quotes but it's not # recommended due to how Bash handles variables with spaces in them. # Parameter expansion ${...}: echo "${variable}" # => Some string # This is a simple usage of parameter expansion such as two examples above. # Parameter expansion gets a value from a variable. # It "expands" or prints the value. # During the expansion time the value or parameter can be modified. # Below are other modifications that add onto this expansion. # String substitution in variables: echo "${variable/Some/A}" # => A string # This will substitute the first occurrence of "Some" with "A". # Prepend a / before the search string to substitute every instance of it. variable="Some string. Some character" echo "${variable//Some/A}" # => A string. A character # This will substitute every occurrence of "Some" with "A". # Substring from a variable: length=7 echo "${variable:0:length}" # => Some st # This will return only the first 7 characters of the value echo "${variable: -5}" # => tring # This will return the last 5 characters (note the space before -5). # The space before minus is mandatory here. # String length: echo "${#variable}" # => 11 # Indirect expansion: other_variable="variable" echo ${!other_variable} # => Some string # This will expand the value of `other_variable`. # The default value for variable: echo "${foo:-"DefaultValueIfFooIsMissingOrEmpty"}" # => DefaultValueIfFooIsMissingOrEmpty # This works for null (foo=) and empty string (foo=""); zero (foo=0) returns 0. # Note that it only returns default value and doesn't change variable value. # Declare an array with 6 elements: array=(one two three four five six) # Print the first element: echo "${array[0]}" # => "one" # Print all elements: echo "${array[@]}" # => "one two three four five six" # Print the number of elements: echo "${#array[@]}" # => "6" # Print the number of characters in third element echo "${#array[2]}" # => "5" # Print 2 elements starting from fourth: echo "${array[@]:3:2}" # => "four five" # Print all elements each of them on new line. for item in "${array[@]}"; do echo "$item" done # Built-in variables: # There are some useful built-in variables, like: echo "Last program's return value: $?" echo "Script's PID: $$" echo "Number of arguments passed to script: $#" echo "All arguments passed to script: $@" echo "Script's arguments separated into different variables: $1 $2..." # Brace Expansion {...} # used to generate arbitrary strings: echo {1..10} # => 1 2 3 4 5 6 7 8 9 10 echo {a..z} # => a b c d e f g h i j k l m n o p q r s t u v w x y z # This will output the range from the start value to the end value. # Note that you can't use variables here: from=1 to=10 echo {$from..$to} # => {$from..$to} # Now that we know how to echo and use variables, # let's learn some of the other basics of Bash! # Our current directory is available through the command `pwd`. # `pwd` stands for "print working directory". # We can also use the built-in variable `$PWD`. # Observe that the following are equivalent: echo "I'm in $(pwd)" # execs `pwd` and interpolates output echo "I'm in $PWD" # interpolates the variable # If you get too much output in your terminal, or from a script, the command # `clear` clears your screen: clear # Ctrl-L also works for clearing output. # Reading a value from input: echo "What's your name?" read name # Note that we didn't need to declare a new variable. echo "Hello, $name!" # We have the usual if structure. # Condition is true if the value of $name is not equal to the current user's login username: if [[ "$name" != "$USER" ]]; then echo "Your name isn't your username" else echo "Your name is your username" fi # To use && and || with if statements, you need multiple pairs of square brackets: read age if [[ "$name" == "Steve" ]] && [[ "$age" -eq 15 ]]; then echo "This will run if $name is Steve AND $age is 15." fi if [[ "$name" == "Daniya" ]] || [[ "$name" == "Zach" ]]; then echo "This will run if $name is Daniya OR Zach." fi # To check if a string is empty or not set use -z and -n to check if it is NOT empty if [[ -z "$name" ]]; then echo "Name is unset" fi # There are other comparison operators for numbers listed below: # -ne - not equal # -lt - less than # -gt - greater than # -le - less than or equal to # -ge - greater than or equal to # There is also the `=~` operator, which tests a string against the Regex pattern: email=me@example.com if [[ "$email" =~ [a-z]+@[a-z]{2,}\.(com|net|org) ]] then echo "Valid email!" fi # There is also conditional execution echo "Always executed" || echo "Only executed if first command fails" # => Always executed echo "Always executed" && echo "Only executed if first command does NOT fail" # => Always executed # => Only executed if first command does NOT fail # A single ampersand & after a command runs it in the background. A background command's # output is printed to the terminal, but it cannot read from the input. sleep 30 & # List background jobs jobs # => [1]+ Running sleep 30 & # Bring the background job to the foreground fg # Ctrl-C to kill the process, or Ctrl-Z to pause it # Resume a background process after it has been paused with Ctrl-Z bg # Kill job number 2 kill %2 # %1, %2, etc. can be used for fg and bg as well # Redefine command `ping` as alias to send only 5 packets alias ping='ping -c 5' # Escape the alias and use command with this name instead \ping 192.168.1.1 # Print all aliases alias -p # Expressions are denoted with the following format: echo $(( 10 + 5 )) # => 15 # Unlike other programming languages, bash is a shell so it works in the context # of a current directory. You can list files and directories in the current # directory with the ls command: ls # Lists the files and subdirectories contained in the current directory # This command has options that control its execution: ls -l # Lists every file and directory on a separate line ls -t # Sorts the directory contents by last-modified date (descending) ls -R # Recursively `ls` this directory and all of its subdirectories # Results (stdout) of the previous command can be passed as input (stdin) to the next command # using a pipe |. Commands chained in this way are called a "pipeline", and are run concurrently. # The `grep` command filters the input with provided patterns. # That's how we can list .txt files in the current directory: ls -l | grep "\.txt" # Use `cat` to print files to stdout: cat file.txt # We can also read the file using `cat`: Contents=$(cat file.txt) # "\n" prints a new line character # "-e" to interpret the newline escape characters as escape characters echo -e "START OF FILE\n$Contents\nEND OF FILE" # => START OF FILE # => [contents of file.txt] # => END OF FILE # Use `cp` to copy files or directories from one place to another. # `cp` creates NEW versions of the sources, # so editing the copy won't affect the original (and vice versa). # Note that it will overwrite the destination if it already exists. cp srcFile.txt clone.txt cp -r srcDirectory/ dst/ # recursively copy # Look into `scp` or `sftp` if you plan on exchanging files between computers. # `scp` behaves very similarly to `cp`. # `sftp` is more interactive. # Use `mv` to move files or directories from one place to another. # `mv` is similar to `cp`, but it deletes the source. # `mv` is also useful for renaming files! mv s0urc3.txt dst.txt # sorry, l33t hackers... # Since bash works in the context of a current directory, you might want to # run your command in some other directory. We have cd for changing location: cd ~ # change to home directory cd # also goes to home directory cd .. # go up one directory # (^^say, from /home/username/Downloads to /home/username) cd /home/username/Documents # change to specified directory cd ~/Documents/.. # now in home directory (if ~/Documents exists) cd - # change to last directory # => /home/username/Documents # Use subshells to work across directories (echo "First, I'm here: $PWD") && (cd someDir; echo "Then, I'm here: $PWD") pwd # still in first directory # Use `mkdir` to create new directories. mkdir myNewDir # The `-p` flag causes new intermediate directories to be created as necessary. mkdir -p myNewDir/with/intermediate/directories # if the intermediate directories didn't already exist, running the above # command without the `-p` flag would return an error # You can redirect command input and output (stdin, stdout, and stderr) # using "redirection operators". Unlike a pipe, which passes output to a command, # a redirection operator has a command's input come from a file or stream, or # sends its output to a file or stream. # Read from stdin until ^EOF$ and overwrite hello.py with the lines # between "EOF" (which are called a "here document"): cat > hello.py << EOF #!/usr/bin/env python from __future__ import print_function import sys print("#stdout", file=sys.stdout) print("#stderr", file=sys.stderr) for line in sys.stdin: print(line, file=sys.stdout) EOF # Variables will be expanded if the first "EOF" is not quoted # Run the hello.py Python script with various stdin, stdout, and # stderr redirections: python hello.py < "input.in" # pass input.in as input to the script python hello.py > "output.out" # redirect output from the script to output.out python hello.py 2> "error.err" # redirect error output to error.err python hello.py > "output-and-error.log" 2>&1 # redirect both output and errors to output-and-error.log # &1 means file descriptor 1 (stdout), so 2>&1 redirects stderr (2) to the current # destination of stdout (1), which has been redirected to output-and-error.log. python hello.py > /dev/null 2>&1 # redirect all output and errors to the black hole, /dev/null, i.e., no output # The output error will overwrite the file if it exists, # if you want to append instead, use ">>": python hello.py >> "output.out" 2>> "error.err" # Overwrite output.out, append to error.err, and count lines: info bash 'Basic Shell Features' 'Redirections' > output.out 2>> error.err wc -l output.out error.err # Run a command and print its file descriptor (e.g. /dev/fd/123) # see: man fd echo <(echo "#helloworld") # Overwrite output.out with "#helloworld": cat > output.out <(echo "#helloworld") echo "#helloworld" > output.out echo "#helloworld" | cat > output.out echo "#helloworld" | tee output.out >/dev/null # Cleanup temporary files verbosely (add '-i' for interactive) # WARNING: `rm` commands cannot be undone rm -v output.out error.err output-and-error.log rm -r tempDir/ # recursively delete # You can install the `trash-cli` Python package to have `trash` # which puts files in the system trash and doesn't delete them directly # see https://pypi.org/project/trash-cli/ if you want to be careful # Commands can be substituted within other commands using $( ): # The following command displays the number of files and directories in the # current directory. echo "There are $(ls | wc -l) items here." # The same can be done using backticks `` but they can't be nested - # the preferred way is to use $( ). echo "There are `ls | wc -l` items here." # Bash uses a `case` statement that works similarly to switch in Java and C++: case "$Variable" in # List patterns for the conditions you want to meet 0) echo "There is a zero.";; 1) echo "There is a one.";; *) echo "It is not null.";; # match everything esac # `for` loops iterate for as many arguments given: # The contents of $Variable is printed three times. for Variable in {1..3} do echo "$Variable" done # => 1 # => 2 # => 3 # Or write it the "traditional for loop" way: for ((a=1; a <= 3; a++)) do echo $a done # => 1 # => 2 # => 3 # They can also be used to act on files.. # This will run the command `cat` on file1 and file2 for Variable in file1 file2 do cat "$Variable" done # ..or the output from a command # This will `cat` the output from `ls`. for Output in $(ls) do cat "$Output" done # Bash can also accept patterns, like this to `cat` # all the Markdown files in current directory for Output in ./*.markdown do cat "$Output" done # while loop: while [ true ] do echo "loop body here..." break done # => loop body here... # You can also define functions # Definition: function foo () { echo "Arguments work just like script arguments: $@" echo "And: $1 $2..." echo "This is a function" returnValue=0 # Variable values can be returned return $returnValue } # Call the function `foo` with two arguments, arg1 and arg2: foo arg1 arg2 # => Arguments work just like script arguments: arg1 arg2 # => And: arg1 arg2... # => This is a function # Return values can be obtained with $? resultValue=$? # More than 9 arguments are also possible by using braces, e.g. ${10}, ${11}, ... # or simply bar () { echo "Another way to declare functions!" return 0 } # Call the function `bar` with no arguments: bar # => Another way to declare functions! # Calling your function foo "My name is" $Name # There are a lot of useful commands you should learn: # prints last 10 lines of file.txt tail -n 10 file.txt # prints first 10 lines of file.txt head -n 10 file.txt # print file.txt's lines in sorted order sort file.txt # report or omit repeated lines, with -d it reports them uniq -d file.txt # prints only the first column before the ',' character cut -d ',' -f 1 file.txt # replaces every occurrence of 'okay' with 'great' in file.txt # (regex compatible) sed -i 's/okay/great/g' file.txt # be aware that this -i flag means that file.txt will be changed # -i or --in-place erase the input file (use --in-place=.backup to keep a back-up) # print to stdout all lines of file.txt which match some regex # The example prints lines which begin with "foo" and end in "bar" grep "^foo.*bar$" file.txt # pass the option "-c" to instead print the number of lines matching the regex grep -c "^foo.*bar$" file.txt # Other useful options are: grep -r "^foo.*bar$" someDir/ # recursively `grep` grep -n "^foo.*bar$" file.txt # give line numbers grep -rI "^foo.*bar$" someDir/ # recursively `grep`, but ignore binary files # perform the same initial search, but filter out the lines containing "baz" grep "^foo.*bar$" file.txt | grep -v "baz" # if you literally want to search for the string, # and not the regex, use `fgrep` (or `grep -F`) fgrep "foobar" file.txt # The `trap` command allows you to execute a command whenever your script # receives a signal. Here, `trap` will execute `rm` if it receives any of the # three listed signals. trap "rm $TEMP_FILE; exit" SIGHUP SIGINT SIGTERM # `sudo` is used to perform commands as the superuser # usually it will ask interactively the password of superuser NAME1=$(whoami) NAME2=$(sudo whoami) echo "Was $NAME1, then became more powerful $NAME2" # Read Bash shell built-ins documentation with the bash `help` built-in: help help help help for help return help source help . # Read Bash manpage documentation with `man` apropos bash man 1 bash man bash # Read info documentation with `info` (`?` for help) apropos info | grep '^info.*(' man info info info info 5 info # Read bash info documentation: info bash info bash 'Bash Features' info bash 6 info --apropos bash ``` For more, see the [Bash documentation](https://www.gnu.org/software/bash/manual/bashref.html). ================================================ FILE: bc.md ================================================ --- name: bc contributors: - ["Btup"] filename: learnbc.bc --- ```bc /*This is a multi- line comment.*/ # This is also a (one-line) comment! (in GNU bc). /*1. Variables and control structures*/ num = 45 /*All variables save only doubles, and you cannot save string constants directly.*/ num = 45; /*You can choose to add a semicolon after every statement. This is optional.*/ /*Blocks are denoted using the {} operators(similar to C):*/ while(num < 50) { num += 1 /*equivalent to num=num+1. a = a op b is equivalent to a op= b.*/ } /*And there are ++(increment) and --(decrement) operators.*/ /*There are 3 special variables: scale: defines the scale of the double numbers. ibase: defines the base of input. obase: defines the base of output.*/ /*If clauses:*/ hour = read() /*Input a number*/ if(hour < 12) { /*Operators are exactly like C.*/ print "Good morning\n" /*"print" outputs strings or variables separated by commas.*/ } else if(hour == 12) { print "Hello\n" /*Escaping sequences start with a \ in a string. In order to make the escaping sequences clearer, here is a simplified list of them that will work in bc: \b: backspace \c: carriage return \n: newline \t: tab \\: backslash*/ } else { print "Good afternoon\n" } /*Like C, only 0 is falsy.*/ num = 0 if(!num) {print "false\n"} /*Unlike C, bc does not have the ?: operators. For example, this block of code will cause an error: a = (num) ? 1 : 0 However, you can simulate one:*/ a = (num) && (1) || (0) /*&& is and, || is or*/ /*For loops*/ num = 0 for(i = 1; i <= 100; i++) {/*Similar to the C for loop.*/ num += i } /*2.Functions and Arrays*/ define fac(n) { /*define a function using define.*/ if(n == 1 || n == 0) { return 1 /*return a value*/ } return n * fac(n - 1) /*recursion is possible*/ } /*Closures and anonymous functions are impossible.*/ num = fac(4) /*24*/ /*This is an example of local variables:*/ define x(n) { auto x x = 1 return n + x } x(3) /*4*/ print x /*It turns out that x is not accessible out of the function.*/ /*Arrays are equivalent to the C array.*/ for(i = 0; i <= 3; i++) { a[i] = 1 } /*Access it like this:*/ print a[0], " ", a[1], " ", a[2], " ", a[3], "\n" quit /*Add this line of code to make sure that your program exits. This line of code is optional.*/ ``` Enjoy this simple calculator! (Or this programming language, to be exact.) This whole program is written in GNU bc. To run it, use ```bc learnbc.bc```. ================================================ FILE: be/python.md ================================================ --- contributors: - ["Louie Dinh", "http://pythonpracticeprojects.com"] - ["Steven Basart", "http://github.com/xksteven"] - ["Andre Polykanine", "https://github.com/Oire"] - ["Zachary Ferguson", "http://github.com/zfergus2"] - ["evuez", "http://github.com/evuez"] - ["Rommel Martinez", "https://ebzzry.io"] - ["Roberto Fernandez Diaz", "https://github.com/robertofd1995"] - ["caminsha", "https://github.com/caminsha"] - ["Stanislav Modrak", "https://stanislav.gq"] - ["John Paul Wohlscheid", "https://gitpi.us"] translators: - ["lucii7vel", "https://github.com/lucii7vel"] --- Python быў створаны Гвіда ван Росумам у пачатку 90-х. Цяпер гэта адна з самых папулярных моў праграмавання. Я закахаўся ў Python за яго сінтаксічную празрыстасць. Гэта літаральна выканальны псеўдакод. ```python # Аднарадковыя каментарыі пачынаюцца знакам рашоткі. """ Шматрадковыя каментарыі можна рабіць выкарыстоўваючы тры ", яны часта выкарыстоўваюцца ў якасці дакументацыі. """ #################################################### ## 1. Прымітыўныя тыпы даных і аператары. #################################################### # Лічбы 3 # => 3 # Відавочныя матэматычныя аперацыі 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 # Вынік цэлалікавага дзялення акругляецца ў напрамку мінус бесканечнасці 5 // 3 # => 1 -5 // 3 # => -2 # Працуе таксама на лічбах з плаваючай кропкай. 5.0 // 3.0 # => 1.0 -5.0 // 3.0 # => -2.0 # Вынік дзялення — заўсёды лічба з плаваючай кропкай. 10.0 / 3 # => 3.3333333333333335 # Дзяленне па модулю 7 % 3 # => 1 # У выніку i % j атрымаецца значэнне са знакам j -7 % 3 # => 2 # Узвядзенне ў ступень 2**3 # => 8 # Прыярытэт аперацый праз дужкі 1 + 3 * 2 # => 7 (1 + 3) * 2 # => 8 # Лагічныя значэнні з'яўляюцца прымітывамі # (Звярніце ўвагу на рэгістр) True # => True False # => False # Адмаўленне праз not not True # => False not False # => True # Лагічныя аператары # Звярніце ўвагу, "and" і "or" чуллівыя да рэгістра True and False # => False False or True # => True # True і False на самай справе 1 і 0, толькі з іншымі ключавымі словамі. True + True # => 2 True * 8 # => 8 False - 5 # => -5 # Параўнальныя аператары звяртаюцца да лічбавых значэнняў True і False. 0 == False # => True 2 > True # => True 2 == True # => False -5 != False # => True # None, 0 і пустыя радкі/спісы/слоўнікі/картэжы/мноства адпавядаюць False. # Усе іншыя значэнні адпавядаюць True. bool(0) # => False bool("") # => False bool([]) # => False bool({}) # => False bool(()) # => False bool(set()) # => False bool(4) # => True bool(-6) # => True # Выкарыстоўванне лагічных аператараў на цэлалікавых значэннях ператварае # іх у boolean для вылічэнняў, але вяртае значэнне іх зыходнага тыпу. # Не блытайце з bool(int) і пабітавымі and/or (&, |). bool(0) # => False bool(2) # => True 0 and 2 # => 0 bool(-5) # => True bool(2) # => True -5 or 0 # => -5 # Роўнасць == 1 == 1 # => True 2 == 1 # => False # Няроўнасць != 1 != 1 # => False 2 != 1 # => True # Больш параўнанняў 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # Праверка значэння на ўваход у дыяпазон 1 < 2 and 2 < 3 # => True 2 < 3 and 3 < 2 # => False # Звязванне выглядае прыгажэй 1 < 2 < 3 # => True 2 < 3 < 2 # => False # (is супраць ==) is правярае, ці спасылаюцца дзве пераменныя на адзін і той жа # аб'ект, а == правярае, ці маюць дзве пераменныя аднолькавыя значэнні. a = [1, 2, 3, 4] # a спасылаецца на новы спіс [1, 2, 3, 4] b = a # b спасылаецца туды ж, куды і a b is a # => True, a і b спасылаюцца на адзін і той жа аб'ект b == a # => True, аб'екты a і b аднолькавыя b = [1, 2, 3, 4] # b спасылаецца на новы спіс [1, 2, 3, 4] b is a # => False, a і b спасылаюцца на розныя аб'екты b == a # => True, аб'екты a і b аднолькавыя # Радкі ствараюцца праз " ці ' "Гэта радок." 'Гэта таксама радок.' # Радкі можна складваць "Вітаю, " + "свет!" # => "Вітаю, свет!" # Радковыя літаралы (але не пераменныя) магчыма злучаць без выкарыстоўвання '+' "Вітаю, " "свет!" # => "Вітаю, свет!" # Радок можна ўспрымаць як спіс сімвалаў "Вітаю, свет"[0] # => 'В' # Ёсць магчымасць знайсці даўжыню радка len("Гэта радок") # => 10 # З версіі Python 3.6 магчыма выкарыстоўваць f-радкі # або фарматаваныя радковыя літаралы. name = "Рэйко" f"Яна сказала, што яе завуць {name}." # => "Яна сказала, што яе завуць Рэйко" # Любы дзейны Python-выраз унутры гэтых дужак вяртаецца ў радок. f"Даўжыня {name} — {len(name)} сімвалаў." # => "Даўжыня Рэйко — 5 сімвалаў." # None — гэта аб'ект None # => None # Не выкарыстоўвайце знак роўнасці '==' для параўнання аб'ектаў з None. # Замест гэтага карыстайцеся 'is'. Ён правярае аб'екты на ідэнтычнасць. "etc" is None # => False None is None # => True #################################################### ## 2. Пераменныя і калекцыі #################################################### # У Python ёсць функцыя print print("Я Python. Рады бачыць!") # => Я Python. Рады бачыць! # Па змаўчанні print таксама пераводзіць на новы радок у канцы. # Выкарыстоўвайце апцыянальны аргумент end каб змяніць канцоўку радка. print("Вітаю, свет", end="!") # => Вітаю, свет! # Просты спосаб атрымаць уваходныя даныя з кансолі input_string_var = input("Увядзіце даныя: ") # Вяртае даныя ў якасці радка # Ніякіх аб'яўленняў, толькі прызначэнні пераменных. # Пераменныя заведзена называць у стылі snake_case. some_var = 5 some_var # => 5 # Звяртанне да непрызначаннай пераменнай прыводзіць да выключэння. # Падрабязнасці пра апрацоўку выключэнняў у раздзеле "Паток кіравання". some_unknown_var # Выкідвае NameError # if можа быць выкарыстаны ў якасці выражэння # Эквівалент цернарнага аператара '?:' з C "Так!" if 0 > 1 else "Не!" # => "Не!" # Спісы захоўваюць паслядоўнасці li = [] # Вы можаце стварыць запоўнены спіс other_li = [4, 5, 6] # Дадаць нешта ў канец спіса праз append li.append(1) # li цяпер [1] li.append(2) # li цяпер [1, 2] li.append(4) # li цяпер [1, 2, 4] li.append(3) # li цяпер [1, 2, 4, 3] # Выдаліць з канца праз pop li.pop() # => 3 li цяпер [1, 2, 4] # Пакладзём назад li.append(3) # li цяпер зноў [1, 2, 4, 3] # Звяртайцеся да спіса як да звычайнага масіву li[0] # => 1 # Зварот да апошняга элемента li[-1] # => 3 # Зварот за межы спіса выкідвае IndexError li[4] # выклідвае IndexError # Магчыма звяртацца да дыяпазонаў праз адсячэнні. # Пачатковы індэкс уключаецца ў дыяпазон, а канчатковы не # (матэматыкі сярод вас ведаюць гэта як напаўадкрыты адцінак). li[1:3] # Вярнуць спіс з індэкса 1 па 3 => [2, 4] li[2:] # Вярнуць спіс з індэкса 2 => [4, 3] li[:3] # Вярнуць спіс да індэкса 3 => [1, 2, 4] li[::2] # Вярнуць спіс, абіраючы элементы з крокам 2 => [1, 4] li[::-1] # Вярнуць спіс у адваротным парадку => [3, 4, 2, 1] # Выкарыстоўвайце іх у рознай камбінацыі, каб ствараць лепшыя адсячэнні # li[пачатак:канец:крок] # Зрабіць копію глыбінёй у адзін слой выкарыстоўваючы адсячэнні li2 = li[:] # => li2 = [1, 2, 4, 3] але (li2 is li) верне false. # Выдаліць элемент са спіса па пазіцыі праз "del" del li[2] # li цяпер [1, 2, 3] # Выдаліць першае знойдзенае значэнне li.remove(2) # li цяпер [1, 3] li.remove(2) # Выкідвае ValueError, бо ў спісе няма элемента са значэннем 2 # Уставіць элемент па дадзенаму індэксу li.insert(1, 2) # li цяпер зноў [1, 2, 3] # Атрымаць індэкс першага элемента з дадзеным значэннем li.index(2) # => 1 li.index(4) # Выкідвае ValueError, бо ў спісе няма элемента са значэннем 4 # Магчыма складваць спісы. # Заўвага: значэнні li і other_li не змяняюцца. li + other_li # => [1, 2, 3, 4, 5, 6] # Аб'яднанне спісаў праз "extend()" li.extend(other_li) # li цяпер [1, 2, 3, 4, 5, 6] # Праверка на наяўнасць элемента ў спісе праз "in" 1 in li # => True # Атрымаць даўжыню спіса праз "len()" len(li) # => 6 # Картэжы падобныя на спісы, але не змяняюцца tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # Выкідвае TypeError # Звярніце ўвагу, што картэжы даўжыні 1 павінны мець коску пасля # апошняга элемента, але картэжы іншай даўжыні, нават 0, не. type((1)) # => type((1,)) # => type(()) # => # Большасць аперацый для спісаў працуюць таксама на картэжах len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True # Вы можаце распакоўваць картэжы (або спісы) у пераменныя a, b, c = (1, 2, 3) # a цяпер 1, b цяпер 2 і c цяпер 3 # Таксама ёсць пашыраная распакоўка a, *b, c = (1, 2, 3, 4) # a цяпер 1, b цяпер [2, 3] і c цяпер 4 # Картэжы ствараюцца па змаўчанні, калі апусціць дужкі d, e, f = 4, 5, 6 # картэж 4, 5, 6 распакоўваецца ў d, e, f, # адпаведна, d = 4, e = 5 і f = 6. # Цяпер паглядзіце, як лёгка абмяняць значэнні дзвюх пераменных e, d = d, e # d цяпер 5, e цяпер 4 # Слоўнікі змяшчаюць пары ключ/значэнне empty_dict = {} # Так выглядае папярэдне запоўнены слоўнік filled_dict = {"адзін": 1, "два": 2, "тры": 3} # Звярніце ўвагу, што ключы ў слоўніках павінны быць нязменных тыпаў. Гэта для # таго, каб пераканацца, што ключ заўсёды створыць аднолькавы хэш для пошуку. # У нязменныя тыпы ўваходзяць цэлалікавыя значэнні, # значэнні з плаваючай кропкай, радкі і картэжы. invalid_dict = {[1,2,3]: "123"} # => Вікідвае TypeError: unhashable type: 'list' valid_dict = {(1,2,3):[1,2,3]} # Значэнні, аднак, могуць быць любых тыпаў. # Пошук значэнняў праз [] filled_dict["адзін"] # => 1 # Атрымаць усе ключы ў якасці itterable-аб'екта праз "keys()". Нам трэба # абгарнуць вызаў у list(), каб ператварыць вынік у спіс. Паразмаўляем аб # гэтым пазней. Заўвага, для версій Python, ніжэйшых за 3.7, парадак ключоў # слоўніка не гарантуецца, вашыя вынікі могуць не адпавядаць прыкладам ніжэй. # Аднак, з версіі Python 3.7, элементы слоўніка захоўваюць парадак, у якім яны # былі ўстаўлены. list(filled_dict.keys()) # => ["тры", "два", "адзін"] для Python <3.7> list(filled_dict.keys()) # => ["адзін", "два", "тры"] для Python 3.7+ # Атрымаць усе значэнні ў якасці itterable-аб'екта праз "values()". Зноў жа, # нам трэба абгарнуць вызаў у list(), каб атрымаць спіс. Тая ж заўвага пра # парадак, што і вышэй. list(filled_dict.values()) # => [3, 2, 1] для Python <3.7 list(filled_dict.values()) # => [1, 2, 3] для Python 3.7+ # Праверка на наяўнасць ключа ў слоўніку праз "in" "адзін" in filled_dict # => True 1 in filled_dict # => False # Пошук неіснуючага ключа выкідвае KeyError filled_dict["чатыры"] # KeyError # Выкарыстоўвайце метад "get()", каб пазбегнуць KeyError filled_dict.get("адзін") # => 1 filled_dict.get("чатыры") # => None # get() падтрымлівае прадвызначаны аргумент, калі значэнне адсутнічае ў слоўніку filled_dict.get("адзін", 4) # => 1 filled_dict.get("чатыры", 4) # => 4 # "setdefault()" устаўляе ў слоўнік толькі калі дадзенага ключа не існуе filled_dict.setdefault("пяць", 5) # filled_dict["пяць"] цяпер 5 filled_dict.setdefault("пяць", 6) # filled_dict["пяць"] усё яшчэ 5 # Дадаванне ў слоўнік filled_dict.update({"чатыры":4}) # => {"адзін": 1, "два": 2, "тры": 3, "чатыры": 4} filled_dict["чатыры"] = 4 # іншы спосаб дадаць у слоўнік # Выдаленне ключоў са слоўніка праз del del filled_dict["адзін"] # выдаляе ключ "адзін" з запоўненага слоўніка # З версіі Python 3.5 таксама існуюць дадатковыя спосабы распакоўкі {'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} {'a': 1, **{'a': 2}} # => {'a': 2} # Мноства змяшчаюць... Ну, мноства empty_set = set() # Ініцыялізваць мноства з кучы значэнняў some_set = {1, 1, 2, 2, 3, 4} # some_set цяпер {1, 2, 3, 4} # Адпаведна ключам слоўніка, элементы мноства павінны быць нязменнымі invalid_set = {[1], 1} # => Выкідвае TypeError: unhashable type: 'list' valid_set = {(1,), 1} # Дадаць яшчэ адзін элемент у мноства filled_set = some_set filled_set.add(5) # filled_set цяпер {1, 2, 3, 4, 5} # Мноства не змяшчаюць паўторных элементаў filled_set.add(5) # застаецца ранейшым {1, 2, 3, 4, 5} # Перасячэнне мностваў праз & other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} # Аб'яднанне мностваў праз | filled_set | other_set # => {1, 2, 3, 4, 5, 6} # Рознасць мностваў праз - {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # Сіметрычная рознасць мностваў праз ^ {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} # Праверыць, ці з'яўляецца мноства злева надмноствам мноства справа {1, 2} >= {1, 2, 3} # => False # Праверыць, ці з'яўляецца мноства злева падмноствам мноства справа {1, 2} <= {1, 2, 3} # => True # Праверка на наяўнасць у мностве праз in 2 in filled_set # => True 10 in filled_set # => False # Зрабіць копію глыбінёй у адзін слой filled_set = some_set.copy() # filled_set цяпер {1, 2, 3, 4, 5} filled_set is some_set # => False #################################################### ## 3. Паток кіравання і ітэрабельныя аб'екты #################################################### # Давайце зробім пераменную some_var = 5 # Так выглядае інструкцыя if. Водступы маюць значэнне ў Python! # Заведзена выкарыстоўваць чатыры прабелы, не табуляцыю. # Гэта выводзіць "some_var меньшая за 10" if some_var > 10: print("some_var цалкам большая за 10.") elif some_var < 10: # гэты elif неабавязковы. print("some_var меньшая за 10.") else: # гэта таксама неабавязкова. print("some_var насамрэч 10.") """ Ітэраванне спісаў праз цыкл for выводзіць: сабакі — млекакормячыя каты — млекакормячыя мышы — млекакормячыя """ for animal in ["сабакі", "каты", "мышы"]: # Вы можаце выкарыстоўваць format() для ўводу фарматаваных радкоў print("{} — млекакормячыя".format(animal)) """ "range(number)" вяртае ітэрабельны аб'ект з лічбаў ад 0 да дадзенай лічбы (не ўключна) выводзіць: 0 1 2 3 """ for i in range(4): print(i) """ "range(lower, upper)" вяртае ітэрабельны аб'ект з лічбаў ад ніжэйшай(lower) да вышэйшай(upper) лічбы выводзіць: 4 5 6 7 """ for i in range(4, 8): print(i) """ "range(lower, upper, step)" вяртае ітэрабельны аб'ект з лічбаў ад ніжэйшай да вышэйшай лічбы з дадзеным крокам. Калі крок не вызначаны, прадвызначаным значэннем з'яўляецца 1 выводзіць: 4 6 """ for i in range(4, 8, 2): print(i) """ Прайсці цыклам праз спіс, каб атрымаць індэкс і значэнне кожнага элемента: 0 сабака 1 кот 2 мыш """ animals = ["сабака", "кот", "мыш"] for i, value in enumerate(animals): print(i, value) """ Цыклы while працуюць пакуль умова не парушана prints: 0 1 2 3 """ x = 0 while x < 4: print(x) x += 1 # Скарачэнне x = x + 1 # Апрацоўка выключэнняў праз блок try/except try: # Выкарыстоўвайце "raise" каб выкінуць памылку raise IndexError("Гэта памылка індэкса") except IndexError as e: pass # Не рабіце так, забяспечце аднаўленне. except (TypeError, NameError): pass # Некалькі выключэнняў можна апрацоўваць сумесна. else: # Неабавязковая частка блока try/except. Павінна быць # пасля ўсіх блокаў except. print("Усё добра!") # Выконваецца толькі калі код унутры try не выкідвае # выключэнняў finally: # Выконваецца пры ўсіх абставінах. print("Тут можна пачысціць рэсурсы") # Замест try/finally для ачысткі рэсурсаў магчыма выкарыстоўваць with with open("myfile.txt") as f: for line in f: print(line) # Запіс у файл contents = {"aa": 12, "bb": 21} with open("myfile1.txt", "w") as file: file.write(str(contents)) # запісвае радок у файл import json with open("myfile2.txt", "w") as file: file.write(json.dumps(contents)) # запісвае аб'ект у файл # Reading from a file with open('myfile1.txt', "r") as file: contents = file.read() # чытае радок з файла print(contents) # выводзіць: {"aa": 12, "bb": 21} with open('myfile2.txt', "r") as file: contents = json.load(file) # чытае json аб'ект з файла print(contents) # выводзіць: {"aa": 12, "bb": 21} # Python прапануе фундаментальную абстракцыю # пад назвай Iterable ("ітэрабельны аб'ект" далей). # Ітэрабельны аб'ект — гэта аб'ект, які можна разглядаць як паслядоўнасць. # Аб'ект, які вяртаецца функцыяй range, з'яўляецца ітэрабельным. filled_dict = {"адзін": 1, "два": 2, "тры": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['адзін', 'два', 'тры']). Гэта аб'ект, # які рэалізуе інтэрфейс Iterable. # Мы можам прайсці па яму цыклам for i in our_iterable: print(i) # Выводзіць адзін, два, тры # Аднак, да элементаў нельга звяртацца па індэксу our_iterable[1] # Выкідвае TypeError # Ітэрабельны аб'ект ведае, як стварыць ітэратар our_iterator = iter(our_iterable) # Наш ітэратар з'яўляецца аб'ектам, які можа запамінаць # стан падчас нашага праходу праз яго. # Мы можам атрымаць наступны аб'ект з дапамогаю "next()" next(our_iterator) # => "адзін" # Ён утрымлівае стан, пакуль мы ітэруем next(our_iterator) # => "два" next(our_iterator) # => "тры" # Калі ітэратар вярнуў усе дадзеныя, ён выкідвае выключэнне StopIteration next(our_iterator) # Выкідвае StopIteration # Мы таксама можам прайсці па яму цыклам, # насамрэч, "for" ускосна гэта і робіць our_iterator = iter(our_iterable) for i in our_iterator: print(i) # Выводзіць адзін, два, тры # Вы можаце захапіць усе элементы ітэрабельнага аб'екта або ітэратара # праз вызаў list() list(our_iterable) # => Вяртае ["адзін", "два", "тры"] list(our_iterator) # => Вяртае [], бо стан захоўваецца #################################################### ## 4. Функцыі #################################################### # Выкарыстоўвайце "def" для стварэння новых функцый def add(x, y): print("x = {}, а y - {}".format(x, y)) return x + y # Вяртайце значэнні праз return # Вызаў функцый з параметрамі add(5, 6) # => выводзіць "x = 5, а y = 6" і вяртае 11 # Таксама магчыма вызываць функцыі з найменнымі аргументамі add(y=6, x=5) # Найменныя аргументы можна выкарыстоўваць у любым парадку # Вы можаце вызначыць функцыю, якая прымае зменлівую колькасць # пазіцыйных аргументаў def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) # Таксама, вы можаце вызначаць функцыі, якія прымаюць зменлівую колькасць # найменных аргументаў def keyword_args(**kwargs): return kwargs # Давайце вызавем яе і паглядзім, што будзе keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} # Вы можаце выкарыстоўваць два спосабы адначасова, калі хочаце def all_the_args(*args, **kwargs): print(args) print(kwargs) """ all_the_args(1, 2, a=3, b=4) выводзіць: (1, 2) {"a": 3, "b": 4} """ # Вызываючы функцыі, вы можаце зрабіць адваротнае args/kwargs! # Выкарыстоўвайце * для разгортвання пазіцыйных аргументаў (картэжаў) # і ** для разгортвання найменных аргументаў (слоўнікаў) args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # адпавядае: all_the_args(1, 2, 3, 4) all_the_args(**kwargs) # адпавядае: all_the_args(a=3, b=4) all_the_args(*args, **kwargs) # адпавядае: all_the_args(1, 2, 3, 4, a=3, b=4) # Вяртанне некалькіх значэнняў (з прызначэннем картэжаў) def swap(x, y): return y, x # Вяртае некалькі значэнняў у выглядзе картэжу без дужак. # (Заўвага: дужкі апускаюцца, але могуць выкарыстоўвацца) x = 1 y = 2 x, y = swap(x, y) # => x = 2, y = 1 # (x, y) = swap(x,y) # Зноў жа, выкарыстоўваць дужкі неабавязкова # глабальная вобласць x = 5 def set_x(num): # лакальная вобласць пачынаецца тут # лакальная пераменная x адрозніваецца ад глабальнай x = num # => 43 print(x) # => 43 def set_global_x(num): # global пазначае, што пераменная знаходзіцца ў глабальнай вобласці global x print(x) # => 5 x = num # глабальная пераменная x цяпер 6 print(x) # => 6 set_x(43) set_global_x(6) """ выводзіць: 43 5 6 """ # Python падтрымлівае функцыі першага класа def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 # Замыканні ва ўкладзеных функцыях: # Мы можам выкарыстоўваць ключавое слова nonlocal для працы з пераменнымі # ўнутры ўкладзенай вобласці, якія не павінны быць аб'яўлены ва ўнутраных # функцыях. def create_avg(): total = 0 count = 0 def avg(n): nonlocal total, count total += n count += 1 return total/count return avg avg = create_avg() avg(3) # => 3.0 avg(5) # (3+5)/2 => 4.0 avg(7) # (8+7)/3 => 5.0 # Таксама існуюць ананімныя функцыі (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 # Існуюць убудаваныя функцыі вышэйшага парадку list(map(add_10, [1, 2, 3])) # => [11, 12, 13] list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] # Для прыгажосці, замест map і filter мы можам выкарыстоўваць спісачныя выразы # Спісачныя выразы захоўваюць вынік у выглядзе спіса (які сам па сабе можа # быць укладзеным). [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # Таксама вы можаце стварыць адпаведныя выразы для мностваў і слоўнікаў {x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### ## 5. Модулі #################################################### # Вы можаце імпартаваць модулі import math print(math.sqrt(16)) # => 4.0 # Вы можаце ўзяць дакладныя функцыі з модуля from math import ceil, floor print(ceil(3.7)) # => 4 print(floor(3.7)) # => 3 # Вы можаце імпартаваць усе функцыі з модуля. # Заўвага: не рэкамендуецца так рабіць. from math import * # Вы можаце скарачаць імёны модуляў import math as m math.sqrt(16) == m.sqrt(16) # => True # Модулі ў Python з'яўляюцца звычайнымі Python файламі. Вы можаце напісаць # свае і імпартаваць іх. Імя модуля адпавядае імені файла. # Вы можаце даведацца, якія функцыі і атрыбуты вызначаны ў модулі import math dir(math) # Калі ў вас ёсць Python-скрыпт з назвай math.py у той жа папцы, # што і бягучы скрыпт, файл math.py будзе загружаны замест убудаванага # Python-модуля. Гэта адбываецца таму, што лакальная папка мае большы # прыярытэт, чым убудаваныя Python-бібліятэкі. #################################################### ## 6. Класы #################################################### # Мы выкарыстоўваем інструкцыю "class" для стварэння класаў class Human: # Атрыбут класа. Яго першапачатковае значэнне пашыраецца # паміж усімі экзэмплярамі класа. species = "H. sapiens" # Базавы канструктар, вызываецца пры стварэнні экзэмпляраў класа. # Звярніце ўвагу, што двайное падкрэсліванне абазначае аб'екты або # атрыбуты, якія выкарыстоўвае Python, але яны існуюць у прасторах назваў, # якія кантралюе карыстальнік. Метады(або аб'екты ці атрыбуты), такія як # __init__, __str__, __repr__ і г.д., называюцца спецыяльнымі метадамі, # або магічнымі метадамі. Вам не варта ствараць такія імёны самастойна. def __init__(self, name): # Прызначэнне аргумента атрыбуту name экзэмпляра класа self.name = name # Ініцыялізацыя ўласцівасці self._age = 0 # папярэдняе падкрэсліванне абазначае, што ўласцівасць # "age" створана для ўнутранага выкарыстання, # але гэта ніяк не кантралюецца, а з'яўляецца # звычайнай падказкай для іншых распрацоўшчыкаў. # Метад экзэмпляра. Усе метады прымаюць "self" у якасці першага аргумента. def say(self, msg): print("{name}: {message}".format(name=self.name, message=msg)) # Іншы метад экзэмпляра def sing(self): return 'ёў... ёў... праверка мікрафона... раз два... раз два...' # Метад класа пашыраецца паміж усімі экзэмплярамі. # Яны вызываюцца з указаннем вызываючага класа ў якасці першага аргумента. @classmethod def get_species(cls): return cls.species # Статычны метад вызываецца без спасылкі на клас або экзэмпляр @staticmethod def grunt(): return "*рохкае*" # property зусім як гетэр # гэты дэкаратар ператварае метад age() у аднайменны атрыбут, # даступны толькі для чытання. # У Python не трэба пісаць трывіяльныя гетэры і сэтэры, дарэчы. @property def age(self): return self._age # Гэта дазваляе ўстанавіць уласцівасць @age.setter def age(self, age): self._age = age # Гэта дазваляе выдаліць уласцівасць @age.deleter def age(self): del self._age # Калі інтэрпрэтатар Python чытае зыходны файл, ён выконвае ўвесь код. # З дапамогай гэтай праверкі, блок кода выконваецца толькі калі модуль # з'яўляецца асноўнай праграмай. if __name__ == '__main__': # Стварэнне экзэмпляра класа i = Human(name="Ігар") i.say("вітан") # "Ігар: вітан" j = Human("Янка") j.say("вітаю") # "Янка: вітаю" # i з j з'яўляюцца экзэмплярамі тыпу Human, г.з., яны аб'екты Human # Вызаў метаду класа i.say(i.get_species()) # "Ігар: H. sapiens" # Змена агульнага атрыбута Human.species = "H. neanderthalensis" i.say(i.get_species()) # => "Ігар: H. neanderthalensis" j.say(j.get_species()) # => "Янка: H. neanderthalensis" # Вызаў статычнага метаду print(Human.grunt()) # => "*рохкае*" # Статычны метад магчыма вызваць таксама з экзэмпляра print(i.grunt()) # => "*рохкае*" # Абнавіць уласцівасць для гэтага экзэмпляра i.age = 42 # Атрымаць уласцівасць i.say(i.age) # => "Ігар: 42" j.say(j.age) # => "Янка: 0" # Выдаліць уласцівасць del i.age # i.age # => гэта выкіне AttributeError #################################################### ## 6.1 Наследаванне #################################################### # Наследаванне дазваляе вызначаць новыя вытворныя класы, якія наследуюць # метады і пераменныя сваіх базавых класаў. # Выкарыстоўваючы клас Human, вызначаны раней, у якасці базавага або # класа-папярэдніка, мы можам вызначыць вытворны клас Superhero, які наследуе # пераменныя класа(species, name, age) і метады(sing, grunt) з класа Human, # але таксама мае свае ўнікальныя ўласцівасці. # Каб выкарыстаць перавагі файлавай модульнасці, вы можаце змясціць класы # ў асобныя файлы, напрыклад, human.py # Каб імпартаваць функцыі з іншых файлаў, выкарыстоўвайце наступны фармат # from "імя-файла-без-пашырэння" import "функцыя-або-клас" from human import Human # Пазначце клас-папярэднік у якасці параметра ў вызначэнні вытворнага класа class Superhero(Human): # Калі вытворнаму класу трэба толькі ўнаследаваць усе вызначэнні # класа-папярэдніка без мадыфікацый, вы можаце выкарыстаць ключавое # слова "pass" (і нічога больш), але ў гэтым выпадку яно закаментавана, # каб мець магчымасць стварыць унікальны клас # pass # Вытворныя класы могуць перавызначыць атрыбуты папярэднікаў species = 'Суперчалавек' # Вытворныя класы аўтаматычна наследуюць канструктары папярэднікаў разам # з аргументамі, але таксама могуць вызначаць дадатковыя аргументы або # вызначэнні, і перавызначаць метады, такія як канструктар класа. # Гэты канструктар наследуе аргумент name з Human # і дадае superpowers і movie: def __init__(self, name, movie=False, superpowers=["суперсіла", "куленепрабівальнасць"]): # дадаць дадатковыя атрыбуты класа: self.fictional = True self.movie = movie # сцеражыцеся прадвызначаных значэнняў зменных тыпаў, # паколькі яны абагульняюцца self.superpowers = superpowers # Функцыя "super" дазваляе атрымаць доступ да метадаў папярэдніка, # якія былі перавызначаны ў вытворным класе, у гэтым выпадку # да метаду __init__. # Вызаў канструктара класа-папярэдніка: super().__init__(name) # перавызначыць метад sing def sing(self): return 'Шчучыншчына!' # дадаць дадатковы метад экзэмпляра def boast(self): for power in self.superpowers: print("Я маю такую моц, як {pow}!".format(pow=power)) if __name__ == '__main__': sup = Superhero(name="Клешч") # Праверка тыпу экзэмпляра if isinstance(sup, Human): print('Я — чалавек') if type(sup) is Superhero: print('Я — супергерой') # Атрымаць "Парадак Вырашэння Метаду"(Method Resolution Order), які # выкарыстоўваюць getattr() і super() # (парадак, у якім адбываецца пошук атрыбутаў або метадаў у класе). # Гэты атрыбут дынамічны і можа абнаўляцца. print(Superhero.__mro__) # => (, # => , ) # Вызывае метад папярэдніка, але выкарыстоўвае ўласны атрыбут класа print(sup.get_species()) # => Суперчалавек # Вызывае перавызначаны метад print(sup.sing()) # => Шчучыншчына! # Вызывае метад з Human sup.say('Лыжка') # => Клешч: Лыжка # Вызывае метад, які існуе толькі ўнутры Superhero sup.boast() # => Я маю такую моц, як суперсіла! # => Я маю такую моц, як куленепрабівальнасць! # Унаследаваны атрыбут класа sup.age = 31 print(sup.age) # => 31 # Атрыбут, які існуе толькі ўнутры Superhero print('Я магу атрымаць Оскар? ' + str(sup.movie)) #################################################### ## 6.2 Множнае наследаванне #################################################### # Вызначэнне іншага класа # bat.py class Bat: species = 'рукакрылачка' def __init__(self, can_fly=True): self.fly = can_fly # У гэтым класе таксама ёсць метад say def say(self, msg): msg = '... ... ...' return msg # І свой уласны метад таксама def sonar(self): return '))) ... (((' if __name__ == '__main__': b = Bat() print(b.say('вітаю')) print(b.fly) # І вызначэнне яшчэ аднаго класа, які наследуецца ад Superhero і Bat # superhero.py from superhero import Superhero from bat import Bat # Вызначыць Batman у якасці вытворнага класа, # які наследуецца ад Superhero і Bat. class Batman(Superhero, Bat): def __init__(self, *args, **kwargs): # Звычайна, каб унаследаваць атрыбуты, вам трэба вызваць super: # super(Batman, self).__init__(*args, **kwargs) # Аднак, мы маем справу з множным наследаваннем, а super() працуе # толькі з наступным базавым класам у спісе MRO. # Таму, замест гэтага мы напрамую вызываем __init__ # для кожнага з папярэднікаў. # Выкарыстанне *args і **kwargs дазваляе ахайна перадаць аргументы, # якія папярэднікі будуць разбіраць слой за слоем. Superhero.__init__(self, 'ананім', movie=True, superpowers=['Багаты'], *args, **kwargs) Bat.__init__(self, *args, can_fly=False, **kwargs) # перавызначэнне значэння атрыбута name self.name = 'Сум Афлек' def sing(self): return 'шчу шчу шчу шчу Шчучыншчына!' if __name__ == '__main__': sup = Batman() # Парадак Вырашэння Метаду(MRO) print(Batman.__mro__) # => (, # => , # => , # => , ) # Вызывае метад папярэдніка, але выкарыстоўвае ўласныя атрыбуты print(sup.get_species()) # => Суперчалавек # Вызывае перавызначаны метад print(sup.sing()) # => шчу шчу шчу шчу Шчучыншчына! # Вызывае метад з Human, бо парадак наследавання мае значэнне sup.say('згодны') # => Сум Афлек: згодны # Вызывае метад, які існуе толькі ў другім папярэдніку print(sup.sonar()) # => ))) ... ((( # Унаследаваны атрыбут класа sup.age = 100 print(sup.age) # => 100 # Унаследаваны атрыбут другога папярэдніка, прадвызначаныя значэнні # якога былі пераназначаны print('Я ўмею лятаць? ' + str(sup.fly)) # => Я ўмею лятаць? False #################################################### ## 7. Дадаткова #################################################### # Генератары дапамагаюць пісаць лянівы код def double_numbers(iterable): for i in iterable: yield i + i # Генератары эфектыўна выкарыстоўваюць памяць, таму што загружаюць толькі # даныя, патрэбныя для апрацоўкі наступнага кроку ітэрацыі. Гэта дазваляе # ім выконваць аперацыі з вялікімі дыяпазонамі даных, якія ў іншых выпадках # былі б недапушчальнымі. # Заўвага: `range` замяняе `xrange` у Python 3. for i in double_numbers(range(1, 900000000)): # `range` гэта генератар. print(i) if i >= 30: break # Адпаведна спісачным выразам, магчыма таксама ствараць генератарныя выразы. values = (-x for x in [1,2,3,4,5]) for x in values: print(x) # выводзіць -1 -2 -3 -4 -5 у кансоль/тэрмінал # Таксама вы можаце ператварыць генератарны выраз прама ў спісак. values = (-x for x in [1,2,3,4,5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] # Дэкаратары з'яўляюцца формай сінтаксічнага цукру. # Нягледзячы на дзіўны сінтаксіс, яны робяць код лягчэйшым для прачытання. # Абгорткі — адзін з відаў дэкаратараў. # З іх дапамогай вельмі зручна дадаваць лагіраванне ў існуючыя функцыі без # неабходнасці іх мадыфікаваць. def log_function(func): def wrapper(*args, **kwargs): print("Уваход у функцыю", func.__name__) result = func(*args, **kwargs) print("Выхад з функцыі", func.__name__) return result return wrapper @log_function # адпаведнік: def my_function(x,y): # def my_function(x,y): return x+y # return x+y # my_function = log_function(my_function) # Дэкаратар @log_function кажа, што падчас прачытання вызначэння функцыі # my_function, яна будзе абгорнута ў log_function. # Калі вызначэнні функцый доўгія, можа быць цяжка апрацаваць неабгорнутыя # прызначэнні ў канцы вызначэнняў. my_function(1,2) # => "Уваход у функцыю my_function" # => "3" # => "Выхад з функцыі my_function" # Але ёсць праблема. # Што калі мы паспрабуем атрымаць якую-небудзь інфармацыю пра my_function? print(my_function.__name__) # => 'wrapper' print(my_function.__code__.co_argcount) # => 0. argcount у выніку 0 таму, што абодва аргументы ў сігнатуры wrapper() з'яўляюцца апцыянальнымі. # Таму, што наш дэкаратар адпавядае my_function = log_function(my_function), # мы замянілі інфармацыю аб my_function інфармацыяй з абгорткі. # Выправіць гэта праз functools from functools import wraps def log_function(func): @wraps(func) # Гэта гарантуе, што дакументацыйны радок (docstring), імя # функцыі, спіс аргументаў і інш., капіруюцца ў выніковую # функцыю замест іх замены інфармацыяй з абгорткі. def wrapper(*args, **kwargs): print("Уваход у функцыю ", func.__name__) result = func(*args, **kwargs) print("Выхад з функцыі ", func.__name__) return result return wrapper @log_function def my_function(x,y): return x+y my_function(1,2) # => "Уваход у функцыю my_function" # => "3" # => "Выхад з функцыі my_function" print(my_function.__name__) # => 'my_function' print(my_function.__code__.co_argcount) # => 2 ``` ### Бясплатныя анлайн-рэсурсы * [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) * [The Official Docs](https://docs.python.org/3/) * [Hitchhiker's Guide to Python](https://docs.python-guide.org/en/latest/) * [Python Course](https://www.python-course.eu) * [Free Interactive Python Course](http://www.Kikodo.io) * [First Steps With Python](https://realpython.com/learn/python-first-steps/) * [A curated list of awesome Python frameworks, libraries and software](https://github.com/vinta/awesome-python) * [30 Python Language Features and Tricks You May Not Know About](https://sahandsaba.com/thirty-python-language-features-and-tricks-you-may-not-know.html) * [Official Style Guide for Python](https://www.python.org/dev/peps/pep-0008/) * [Python 3 Computer Science Circles](https://cscircles.cemc.uwaterloo.ca/) * [Dive Into Python 3](https://www.diveintopython3.net/index.html) * [A Crash Course in Python for Scientists](https://nbviewer.jupyter.org/gist/anonymous/5924718) * [Python Tutorial for Intermediates](https://pythonbasics.org/) * [Build a Desktop App with Python](https://pythonpyqt.com/) ================================================ FILE: be/r.md ================================================ --- name: R contributors: - ["e99n09", "http://github.com/e99n09"] - ["isomorphismes", "http://twitter.com/isomorphisms"] - ["kalinn", "http://github.com/kalinn"] - ["mribeirodantas", "http://github.com/mribeirodantas"] translators: - ["lucii7vel", "https://github.com/lucii7vel"] filename: learnr.r --- R - гэта статыстычная мова праграмавання. Яна мае шмат бібліятэк для загрузкі і ачысткі даных, запуску статыстычных працэдур і стварэння графікаў. Вы таксама можаце запускаць каманды `R` унутры LaTeX дакумента. ```r # Каментарыі пачынаюцца са знака рашоткі, таксама вядомага як знак нумара (#). # Вы не можаце рабіць шматрадковыя каментарыі, # але можаце стагаваць некалькі каментарыяў такім чынам. # на Windows вы можаце выкарыстоўваць CTRL-ENTER каб выканаць радок. # на Mac гэта COMMAND-ENTER ############################################################################# # Рэчы, якія вы можаце рабіць не разумеючы нічога пра праграмаванне ############################################################################# # У гэтай секцыі мы пакажам некаторыя выдатныя рэчы, якія вы можаце # рабіць у R не разумеючы нічога пра праграмаванне. Не хвалюйцеся, # калі не разумееце штосьці з таго, што робіць код. Атрымлівайце асалоду! data() # агляд падрыхтаваных датасэтаў data(rivers) # агляд наступнага: "Даўжыня галоўных рэк Паўночнай Амерыкі" ls() # заўважце, што ў працоўнай прасторы цяпер ёсць "rivers" head(rivers) # заглянуць у датасэт # 735 320 325 392 524 450 length(rivers) # колькі рэк было вымерана? # 141 summary(rivers) # якая зводная статыстыка? # Min. 1st Qu. Median Mean 3rd Qu. Max. # 135.0 310.0 425.0 591.2 680.0 3710.0 # зрабіць графік "сцябло і лісце" (прадстаўленне даных у якасці гістаграмы) stem(rivers) # Дзесятковая кропка - 2 лічбы справа ад | # # 0 | 4 # 2 | 011223334555566667778888899900001111223333344455555666688888999 # 4 | 111222333445566779001233344567 # 6 | 000112233578012234468 # 8 | 045790018 # 10 | 04507 # 12 | 1471 # 14 | 56 # 16 | 7 # 18 | 9 # 20 | # 22 | 25 # 24 | 3 # 26 | # 28 | # 30 | # 32 | # 34 | # 36 | 1 stem(log(rivers)) # Заўважце, што даныя размеркаваны ані нармальна, ані логнармальна! # З'ешце, прыхільнікі званавіднай крывой. # Дзесятковая кропка - 1 лічба злева ад | # # 48 | 1 # 50 | # 52 | 15578 # 54 | 44571222466689 # 56 | 023334677000124455789 # 58 | 00122366666999933445777 # 60 | 122445567800133459 # 62 | 112666799035 # 64 | 00011334581257889 # 66 | 003683579 # 68 | 0019156 # 70 | 079357 # 72 | 89 # 74 | 84 # 76 | 56 # 78 | 4 # 80 | # 82 | 2 # зрабіць гістаграму: hist(rivers, col = "#333333", border = "white", breaks = 25) hist(log(rivers), col = "#333333", border = "white", breaks = 25) # пагуляйцеся з параметрамі, зробіце больш графікаў пазней # Вось іншы элегантны датасэт, адзін з падрыхтаваных. У R такіх шмат. data(discoveries) plot(discoveries, col = "#333333", lwd = 3, xlab = "Year", main="Number of important discoveries per year") plot(discoveries, col = "#333333", lwd = 3, type = "h", xlab = "Year", main="Number of important discoveries per year") # Замест таго, каб пакідаць стандартную сарціроўку (па году), мы можам таксама # выкарыстаць сарціроўку, каб пабачыць, што для яго характэрна: sort(discoveries) # [1] 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 # [26] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 # [51] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 # [76] 4 4 4 4 5 5 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 8 9 10 12 stem(discoveries, scale = 2) # # Дзесятковая кропка на | # # 0 | 000000000 # 1 | 000000000000 # 2 | 00000000000000000000000000 # 3 | 00000000000000000000 # 4 | 000000000000 # 5 | 0000000 # 6 | 000000 # 7 | 0000 # 8 | 0 # 9 | 0 # 10 | 0 # 11 | # 12 | 0 max(discoveries) # 12 summary(discoveries) # Min. 1st Qu. Median Mean 3rd Qu. Max. # 0.0 2.0 3.0 3.1 4.0 12.0 # Кінуць косць пару разоў round(runif(7, min = .5, max = 6.5)) # 1 4 6 1 4 6 4 # Вашыя нумары будуць адрознівацца ад маіх, хіба што мы не # ўкажам аднолькавы random.seed(31337) # Выцягнуць значэнне з нармальнага размеркавання 9 разоў rnorm(9) # [1] 0.07528471 1.03499859 1.34809556 -0.82356087 0.61638975 -1.88757271 # [7] -0.59975593 0.57629164 1.08455362 ################################################## # Тыпы даных і базавая арыфметыка ################################################## # Цяпер да арыентаванай на праграмавання часткі туторыяла. # У гэтай секцыі вы пазнаёміцеся з важнымі тыпамі даных у R: # цэлалікавыя, лічбавыя, сімвальныя, лагічныя і фактары. # Ёсць і іншыя, але гэтыя - мінімум, які трэба ведаць, каб пачаць. # ЦЭЛАЛІКАВЫЯ # Доўгія цэлалікавыя пішуцца з літарай L 5L # 5 class(5L) # "integer" # (Паспрабуйце ?class каб атрымаць больш інфармацыі пра функцыю class().) # У R кожнае значэнне, як 5L, лічыцца вектарам даўжыні 1 length(5L) # 1 # Вы можаце зрабіць цэлалікавы вектар з даўжынёй больш за 1, таксама: c(4L, 5L, 8L, 3L) # 4 5 8 3 length(c(4L, 5L, 8L, 3L)) # 4 class(c(4L, 5L, 8L, 3L)) # "integer" # ЛІЧБАВЫЯ # "numeric" - гэта лічба падвоенай дакладнасці з плаваючай кропкай 5 # 5 class(5) # "numeric" # Зноў жа, усё ў R ёсць вектарам; # вы можаце зрабіць лічбавы вектар з больш чым адным элементам c(3, 3, 3, 2, 2, 1) # 3 3 3 2 2 1 # Вы таксама можаце выкарыстоўваць навуковы запіс 5e4 # 50000 6.02e23 # пастаянная Авагадра 1.6e-35 # Планкаўская даўжыня # Таксама ёсць бясконца вялікія і маленькія лікі class(Inf) # "numeric" class(-Inf) # "numeric" # Вы можаце выкарыстоўваць "Inf", напрыклад, у integrate(dnorm, 3, Inf); # пазбаўляе ад неабходнасці ў табліцах нармальнага размеркавання. # БАЗАВАЯ АРЫФМЕТЫКА # Вы можаце рабіць арыфметычныя аперацыі з лічбамі # Арыфметычныя аперацыі на сумесі цэлалікавых і лічбавых тыпаў даюць лічбавы 10L + 66L # 76 # цэлалікавы плюс цэлалікавы дае цэлалікавы 53.2 - 4 # 49.2 # лічбавы мінус лічбавы дае лічбавы 2.0 * 2L # 4 # лічбавы памножыць на цэлалікавы дае лічбавы 3L / 4 # 0.75 # цэлалікавы падзяліць на лічбавы дае лічбавы 3 %% 2 # 1 # рэшта ад двух лічбавых - таксама лічбавы # Нядзеючыя арыфметычныя аперацыі даюць "not-a-number": 0 / 0 # NaN class(NaN) # "numeric" # Вы можаце рабіць арыфметычныя аперацыі з двума вектарамі з даўжынёй, # большай за 1, да тых пор, пакуль даўжыня большага вектара # кратная даўжыні меншага c(1, 2, 3) + c(1, 2, 3) # 2 4 6 # Паколькі асобная лічба - гэта вектар даўжыні адзін, скаляры прымяняюцца # паэлементна да вектара (4 * c(1, 2, 3) - 2) / 2 # 1 3 5 # Калі гэта не скаляр, будзьце асцярожнымі праводзячы арыфметычныя аперацыі # з вектарамі рознай даўжыні. Хаця гэта і магчыма, c(1, 2, 3, 1, 2, 3) * c(1, 2) # 1 4 3 2 2 6 # Адпаведныя даўжыні з'яўляюцца лепшай практыкай і палягчаюць чытанне # у большасці выпадкаў c(1, 2, 3, 1, 2, 3) * c(1, 2, 1, 2, 1, 2) # 1 4 3 2 2 6 # СІМВАЛЬНЫЯ # У R няма розніцы паміж радкамі і сімваламі "Horatio" # "Horatio" class("Horatio") # "character" class("H") # "character" # Гэта ўсё сімвальныя вектары даўжыні 1 # Вось даўжэйшы: c("alef", "bet", "gimmel", "dalet", "he") # => "alef" "bet" "gimmel" "dalet" "he" length(c("Call","me","Ishmael")) # 3 # Вы можаце прымяняць regex аперацыі на сімвальных вектарах: substr("Fortuna multis dat nimis, nulli satis.", 9, 15) # "multis " gsub('u', 'ø', "Fortuna multis dat nimis, nulli satis.") # "Fortøna møltis dat nimis, nølli satis." # У R ёсць некалькі падрыхтаваных сімвальных вектараў: letters # => # [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" # [20] "t" "u" "v" "w" "x" "y" "z" month.abb # "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec" # ЛАГІЧНЫЯ # У R лагічным тыпам ёсць "logical" class(TRUE) # "logical" class(FALSE) # "logical" # Яны паводзяць сябе звычайна TRUE == TRUE # TRUE TRUE == FALSE # FALSE FALSE != FALSE # FALSE FALSE != TRUE # TRUE # Адсутныя даныя (NA) таксама лагічнага тыпу class(NA) # "logical" # Выкарыстоўвайце | і & для лагічных аперацый. # АБО TRUE | FALSE # TRUE # І TRUE & FALSE # FALSE # Выкарыстоўванне | і & на вектарах павяртае паэлементныя лагічныя аперацыі c(TRUE, FALSE, FALSE) | c(FALSE, TRUE, FALSE) # TRUE TRUE FALSE c(TRUE, FALSE, TRUE) & c(FALSE, TRUE, TRUE) # FALSE FALSE TRUE # Вы можаце праверыць, ці x TRUE isTRUE(TRUE) # TRUE # Тут мы атрымоўваем лагічны вектар з некалькімі элементамі: c("Z", "o", "r", "r", "o") == "Zorro" # FALSE FALSE FALSE FALSE FALSE c("Z", "o", "r", "r", "o") == "Z" # TRUE FALSE FALSE FALSE FALSE # ФАКТАРЫ # Фактар выкарыстоўваецца для катэгарычных даных # Фактары могуць быць упарадкаванымі (як адзнакі) # або неўпарадкаванымі (як колеры) factor(c("blue", "blue", "green", NA, "blue")) # blue blue green blue # Levels: blue green # "levels" - гэта значэнні, якія могуць прыймаць катэгарычныя даныя # Заўважце, што адсутныя даныя не ўваходзяць ва ўзроўні levels(factor(c("green", "green", "blue", NA, "blue"))) # "blue" "green" # Калі вектар фактараў мае даўжыню 1, яго ўзроўні будуць таксама мець даўжыню 1 length(factor("green")) # 1 length(levels(factor("green"))) # 1 # Фактары звычайна можна пабачыць у фрэймах даных, структуры даных, # з якою мы разбяромся пазней data(infert) # "Infertility after Spontaneous and Induced Abortion" levels(infert$education) # "0-5yrs" "6-11yrs" "12+ yrs" # NULL # "NULL" дзіўны, выкарыстоўвайце яго каб "абнуляць" вектары class(NULL) # NULL parakeet = c("beak", "feathers", "wings", "eyes") parakeet # "beak" "feathers" "wings" "eyes" parakeet <- NULL parakeet # NULL # ПРЫВЯДЗЕННЕ ДАНЫХ # Прывядзенне даных - гэта калі вы прымушаеце значэнне прыняць іншы тып as.character(c(6, 8)) # "6" "8" as.logical(c(1,0,1,1)) # TRUE FALSE TRUE TRUE # Калі вы пакладзяце элементы розных тыпаў у вектар, # адбудзецца дзіўнае прывядзенне: c(TRUE, 4) # 1 4 c("dog", TRUE, 4) # "dog" "TRUE" "4" as.numeric("Bilbo") # => # [1] NA # Warning message: # NAs introduced by coercion # Майце на ўвазе: гэта былі толькі базавыя тыпы даных # Існуе нашмат болей тыпаў даных, такіх як даты, часавыя рады і іншыя. ################################################## # Пераменныя, цыклы, if/else ################################################## # Пераменныя як скрыні, у якіх захоўваюцца значэнні для пазнейшага выкарыстання. # Мы называем гэта "прызначэннем" значэння пераменнай. # Наяўнасць пераменных дае нам магчымасць выкарыстоўваць цыклы, # функцыі і інструкцыю if/else # ПЕРАМЕННЫЯ # Ёсць шмат спосабаў прызначыць нешта: x = 5 # гэта магчыма y <- "1" # гэта традыцыйна прынята TRUE -> z # гэта працуе, але выглядае дзіўна # Звярніцеся да Інтэрнэту, каб даведацца пра іх працу і перавагі. # ЦЫКЛЫ # Для цыклаў ёсць for (i in 1:4) { print(i) } # Ёсць цыклы while a <- 10 while (a > 4) { cat(a, "...", sep = "") a <- a - 1 } # Майце на ўвазе, што цыклы for і while працуюць павольна ў R # Аперацыі на цэлых вектарах (г.з на цэлых радках, цэлых калонках) # або функцыі накшталт apply() (абмяркуем гэта пазней) маюць перавагу # IF/ELSE # Зноў жа, усё даволі стандартна if (4 > 3) { print("4 болей за 3") } else { print("4 не болей за 3") } # => # [1] "4 болей за 3" # ФУНКЦЫІ # Аб'яўляюцца так: jiggle <- function(x) { x = x + rnorm(1, sd=.1) # дадаць крыху (кантралюемага) шуму return(x) } # Выклікаюцца як і любыя іншыя функцыі R: jiggle(5) # 5±ε. Пасля set.seed(2716057), jiggle(5)==5.005043 ########################################################################### # Структуры даных: вектары, матрыцы, фрэймы даных і масівы ########################################################################### # АДНАМЕРНЫЯ # Пачнём з самага пачатку, і з нечага, што вы ўжо ведаеце: вектараў. vec <- c(8, 9, 10, 11) vec # 8 9 10 11 # Мы запытваем дакладны элемент, пазначаючы падмноства квадратнымі дужкамі # (Заўважце, што адлік у R пачынаецца з 1) vec[1] # 8 letters[18] # "r" LETTERS[13] # "M" month.name[9] # "September" c(6, 8, 7, 5, 3, 0, 9)[3] # 7 # Мы таксама можам шукаць індэксы дакладных кампанентаў, which(vec %% 2 == 0) # 1 3 # узяць толькі першыя або астатнія некалькі запісаў вектара, head(vec, 1) # 8 tail(vec, 2) # 10 11 # або даведацца, ці ёсць дакладнае значэнне ў вектары any(vec == 10) # TRUE # Калі індэкс "пераваліць", вы атрымаеце NA: vec[6] # NA # Вы можаце знайсці даўжыню свайго вектара з length() length(vec) # 4 # Вы можаце праводзіць аперацыі над цэлымі вектарамі або часткамі вектараў vec * 4 # 32 36 40 44 vec[2:3] * 5 # 45 50 any(vec[2:3] == 8) # FALSE # і R мае шмат убудаваных функцый для падсумоўвання вектараў mean(vec) # 9.5 var(vec) # 1.666667 sd(vec) # 1.290994 max(vec) # 11 min(vec) # 8 sum(vec) # 38 # Больш прыемных убудаванак: 5:15 # 5 6 7 8 9 10 11 12 13 14 15 seq(from = 0, to = 31337, by = 1337) # => # [1] 0 1337 2674 4011 5348 6685 8022 9359 10696 12033 13370 14707 # [13] 16044 17381 18718 20055 21392 22729 24066 25403 26740 28077 29414 30751 # ДВУМЕРНЫЯ (УСЕ АДНАГО КЛАСУ) # Вы можаце зрабіць матрыцу з запісаў аднолькавага тыпу вось так: mat <- matrix(nrow = 3, ncol = 2, c(1, 2, 3, 4, 5, 6)) mat # => # [,1] [,2] # [1,] 1 4 # [2,] 2 5 # [3,] 3 6 # У адрозненні ад вектара, класам матрыцы ёсць "matrix", што б у ёй не было class(mat) # "matrix" "array" # Запытаць першы радок mat[1, ] # 1 4 # Perform operation on the first column 3 * mat[, 1] # 3 6 9 # Правесці аперацыю над першай калонкай mat[3, 2] # 6 # Транспанаваць усю матрыцу t(mat) # => # [,1] [,2] [,3] # [1,] 1 2 3 # [2,] 4 5 6 # Памнажэнне матрыц mat %*% t(mat) # => # [,1] [,2] [,3] # [1,] 17 22 27 # [2,] 22 29 36 # [3,] 27 36 45 # cbind() склейвае вектары па калонках каб зрабіць матрыцу mat2 <- cbind(1:4, c("dog", "cat", "bird", "dog")) mat2 # => # [,1] [,2] # [1,] "1" "dog" # [2,] "2" "cat" # [3,] "3" "bird" # [4,] "4" "dog" class(mat2) # matrix # Зноў жа, заўважце, што здарылася! # Таму што матрыца павінна змяшчаць у сабе запісы аднолькавага тыпу, # усё павінна быць ператворана ў сімвальны клас c(class(mat2[, 1]), class(mat2[, 2])) # rbind() склейвае вектары па радках каб стварыць матрыцу mat3 <- rbind(c(1, 2, 4, 5), c(6, 7, 0, 4)) mat3 # => # [,1] [,2] [,3] [,4] # [1,] 1 2 4 5 # [2,] 6 7 0 4 # Ах, усё аднаго класу. Ніякага прывядзення. Нашмат лепей. # ДВУМЕРНЫЯ (РОЗНЫХ КЛАСАЎ) # Для калонак розных тыпаў выкарыстоўвайце фрэймы даных # Гэтая структура даных дужа карысная для статыстычнага праграмавання, # яе версія была дададзена ў Python у пакеце "pandas". students <- data.frame(c("Cedric", "Fred", "George", "Cho", "Draco", "Ginny"), c( 3, 2, 2, 1, 0, -1), c( "H", "G", "G", "R", "S", "G")) names(students) <- c("name", "year", "house") # даць імёны калонкам class(students) # "data.frame" students # => # name year house # 1 Cedric 3 H # 2 Fred 2 G # 3 George 2 G # 4 Cho 1 R # 5 Draco 0 S # 6 Ginny -1 G class(students$year) # "numeric" class(students[,3]) # "factor" # find the dimensions nrow(students) # 6 ncol(students) # 3 dim(students) # 6 3 # Функцыя data.frame() аўтаматычна ператварала сімвальныя вектары # ў фактарныя вектары; Гэта змянілася ў R 4.0.0. Калі ваша версія # R старэйшая, адключыце гэта ўстанавіўшы stringsAsFactors = FALSE # калі ствараеце data.frame ?data.frame # Існуе шмат звілістых спосабаў стварыць падмноства фрэйма даных, # усе па-свойму розныя students$year # 3 2 2 1 0 -1 students[, 2] # 3 2 2 1 0 -1 students[, "year"] # 3 2 2 1 0 -1 # Павялічаная версія структуры data.frame - гэта data.table # Калі працуеце з вялізнымі або панэльнымі данымі, або маеце патрэбу # аб'яднаць некалькі набораў даных, data.table можа быць добрым выбарам. # Вось хуткі тур: install.packages("data.table") # сцягнуць пакет з CRAN require(data.table) # загрузіць яго students <- as.data.table(students) students # заўважце крыху іншы вывад # => # name year house # 1: Cedric 3 H # 2: Fred 2 G # 3: George 2 G # 4: Cho 1 R # 5: Draco 0 S # 6: Ginny -1 G students[name == "Ginny"] # атрымаць радкі, дзе "Ginny" # => # name year house # 1: Ginny -1 G students[year == 2] # атрымаць радкі, дзе year == 2 # => # name year house # 1: Fred 2 G # 2: George 2 G # data.table дазваляе лёгка аб'яднаць два наборы даных # давайце зробім іншую data.table каб аб'яднаць яе з students founders <- data.table(house = c("G" , "H" , "R" , "S"), founder = c("Godric", "Helga", "Rowena", "Salazar")) founders # => # house founder # 1: G Godric # 2: H Helga # 3: R Rowena # 4: S Salazar setkey(students, house) setkey(founders, house) students <- founders[students] # аб'яднаць два наборы даных з адпаведнымі "house" setnames(students, c("house", "houseFounderName", "studentName", "year")) students[, order(c("name", "year", "house", "houseFounderName")), with = F] # => # studentName year house houseFounderName # 1: Fred 2 G Godric # 2: George 2 G Godric # 3: Ginny -1 G Godric # 4: Cedric 3 H Helga # 5: Cho 1 R Rowena # 6: Draco 0 S Salazar # data.table робіць падсумоўванне табліц простым students[, sum(year), by = house] # => # house V1 # 1: G 3 # 2: H 3 # 3: R 1 # 4: S 0 # Каб выключыць калонку з data.frame ці data.table, # прызначце ёй значэнне NULL students$houseFounderName <- NULL students # => # studentName year house # 1: Fred 2 G # 2: George 2 G # 3: Ginny -1 G # 4: Cedric 3 H # 5: Cho 1 R # 6: Draco 0 S # Выключыць радок праз падмноства # Выкарыстоўваючы data.table: students[studentName != "Draco"] # => # house studentName year # 1: G Fred 2 # 2: G George 2 # 3: G Ginny -1 # 4: H Cedric 3 # 5: R Cho 1 # Выкарыстоўваючы data.frame: students <- as.data.frame(students) students[students$house != "G", ] # => # house houseFounderName studentName year # 4 H Helga Cedric 3 # 5 R Rowena Cho 1 # 6 S Salazar Draco 0 # ШМАТМЕРНЫЯ (УСЕ ЭЛЕМЕНТЫ АДНАГО ТЫПУ) # Масівы ствараюць n-мерныя табліцы # Усе элементы павінны быць аднаго тыпу # Вы можаце стварыць двухмерную табліцу (нешта накшталт матрыцы) array(c(c(1, 2, 4, 5), c(8, 9, 3, 6)), dim = c(2, 4)) # => # [,1] [,2] [,3] [,4] # [1,] 1 4 8 3 # [2,] 2 5 9 6 # Вы можаце выкарыстоўваць масівы, каб таксама зрабіць трохмерныя матрыцы array(c(c(c(2, 300, 4), c(8, 9, 0)), c(c(5, 60, 0), c(66, 7, 847))), dim = c(3, 2, 2)) # => # , , 1 # # [,1] [,2] # [1,] 2 8 # [2,] 300 9 # [3,] 4 0 # # , , 2 # # [,1] [,2] # [1,] 5 66 # [2,] 60 7 # [3,] 0 847 # СПІСЫ(ШМАТМЕРНЫЯ, МАГЧЫМА НЯРОЎНЫЯ, З РОЗНЫХ ТЫПАМІ) # Нарэшце, у R ёсць спісы (вектараў) list1 <- list(time = 1:40) list1$price = c(rnorm(40, .5*list1$time, 4)) # рандом list1 # Вы можаце атрымаць элементы спіса наступным чынам list1$time # адзін спосаб list1[["time"]] # іншы спосаб list1[[1]] # яшчэ іншы спосаб # => # [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # [34] 34 35 36 37 38 39 40 # Вы можаце вылучаць падмноства спісаў як і любых іншых вектараў list1$price[4] # Спісы не найэфектыўнейшая структура даных для працы ў R; # пакуль у вас няма вельмі добрай прычыны, лепей аддаваць перавагу data.frames # Спісы звычайна павяртаюцца функцыямі, якія выконваюць лінейныя рэгрэсіі ################################################## # Сямейства функцый apply() ################################################## # Памятаеце mat? mat # => # [,1] [,2] # [1,] 1 4 # [2,] 2 5 # [3,] 3 6 # Выкарыстоўвайце apply(X, MARGIN, FUN) каб прымяніць функцыю FUN на матрыцы X # для радкоў (MAR = 1) або калонак (MAR = 2) # Усё так, R выконвае FUN на кожным радку (або калонцы) X нашмат хутчэй # за цыклы for і while apply(mat, MAR = 2, jiggle) # => # [,1] [,2] # [1,] 3 15 # [2,] 7 19 # [3,] 11 23 # іншыя функцыі: ?lapply, ?sapply # Не бойцеся, кожны згодны, што гэта даволі заблытана # Пакет plyr накіраваны на замену (і паляпшэнне) сямейства *apply(). install.packages("plyr") require(plyr) ?plyr ######################### # Загрузка даных ######################### # "pets.csv" - файл з інтэрнэту # (але гэта таксама можа быць файл на вашым уласным камп'ютары) require(RCurl) pets <- read.csv(textConnection(getURL("https://learnxinyminutes.com/pets.csv"))) pets head(pets, 2) # першыя два радкі tail(pets, 1) # апошні радок # Каб захаваць фрэйм даных або матрыцу ў .csv файл write.csv(pets, "pets2.csv") # зрабіць новы .csv файл # устанаўлівайце працоўную дырэкторыю з setwd(), дазнавайцеся яе з getwd() # Глядзіце ?read.csv і ?write.csv каб атрымаць больш інфармацыі ######################### # Статыстычны Аналіз ######################### # Лінейная рэгрэсія! linearModel <- lm(price ~ time, data = list1) linearModel # выводзіць рэзультаты рэгрэсіі # => # Call: # lm(formula = price ~ time, data = list1) # # Coefficients: # (Intercept) time # 0.1453 0.4943 summary(linearModel) # больш падрабязны вывад з рэгрэсіі # => # Call: # lm(formula = price ~ time, data = list1) # # Residuals: # Min 1Q Median 3Q Max # -8.3134 -3.0131 -0.3606 2.8016 10.3992 # # Coefficients: # Estimate Std. Error t value Pr(>|t|) # (Intercept) 0.14527 1.50084 0.097 0.923 # time 0.49435 0.06379 7.749 2.44e-09 *** # --- # Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 # # Residual standard error: 4.657 on 38 degrees of freedom # Multiple R-squared: 0.6124, Adjusted R-squared: 0.6022 # F-statistic: 60.05 on 1 and 38 DF, p-value: 2.44e-09 coef(linearModel) # выцягнуць чаканыя параметры # => # (Intercept) time # 0.1452662 0.4943490 summary(linearModel)$coefficients # іншы спосаб выцягнуць рэзультаты # => # Estimate Std. Error t value Pr(>|t|) # (Intercept) 0.1452662 1.50084246 0.09678975 9.234021e-01 # time 0.4943490 0.06379348 7.74920901 2.440008e-09 summary(linearModel)$coefficients[, 4] # p-значэнні # => # (Intercept) time # 9.234021e-01 2.440008e-09 # АГУЛЬНЫЯ ЛІНЕЙНЫЯ МАДЭЛІ # Лагістычная рэгрэсія set.seed(1) list1$success = rbinom(length(list1$time), 1, .5) # выпадковае бінарнае значэнне glModel <- glm(success ~ time, data = list1, family=binomial(link="logit")) glModel # выводзіць рэзультат лагістычнай рэгрэсіі # => # Call: glm(formula = success ~ time, # family = binomial(link = "logit"), data = list1) # # Каэфіцыенты: # (Intercept) time # 0.17018 -0.01321 # # Degrees of Freedom: 39 Total (i.e. Null); 38 Residual # Null Deviance: 55.35 # Residual Deviance: 55.12 AIC: 59.12 summary(glModel) # больш падрабязны вывад з рэгрэсіі # => # Call: # glm( # formula = success ~ time, # family = binomial(link = "logit"), # data = list1) # Deviance Residuals: # Min 1Q Median 3Q Max # -1.245 -1.118 -1.035 1.202 1.327 # # Coefficients: # Estimate Std. Error z value Pr(>|z|) # (Intercept) 0.17018 0.64621 0.263 0.792 # time -0.01321 0.02757 -0.479 0.632 # # (Dispersion parameter for binomial family taken to be 1) # # Null deviance: 55.352 on 39 degrees of freedom # Residual deviance: 55.121 on 38 degrees of freedom # AIC: 59.121 # # Number of Fisher Scoring iterations: 3 ######################### # Графікі ######################### # УБУДАВАНЫЯ ФУНКЦЫІ ДЛЯ ГРАФІКАЎ # Кропкавыя дыяграмы! plot(list1$time, list1$price, main = "fake data") # Намаляваць лінію рэгрэсіі на існуючай дыяграме abline(linearModel, col = "red") # Трымайце шэраг прыемных дыягностык plot(linearModel) # Гістаграмы! hist(rpois(n = 10000, lambda = 5), col = "thistle") # Слупкаватыя дыяграмы! barplot(c(1, 4, 5, 1, 2), names.arg = c("red", "blue", "purple", "green", "yellow")) # GGPLOT2 # І гэта нават не найпрыгажэйшыя з графікаў R # Паспрабуйце пакет ggplot2, у якім больш лепшых графікаў install.packages("ggplot2") require(ggplot2) ?ggplot2 pp <- ggplot(students, aes(x = house)) pp + geom_bar() ll <- as.data.table(list1) pp <- ggplot(ll, aes(x = time, price)) pp + geom_point() # ggplot2 has excellent documentation (available http://docs.ggplot2.org/current/) ``` ## Дзе ўзяць R? * Сцягніце R і R GUI з [http://www.r-project.org/](http://www.r-project.org/) * [RStudio](http://www.rstudio.com/ide/) іншы GUI ================================================ FILE: bf.md ================================================ --- name: BF where_x_eq_name: brainfuck filename: bf.bf contributors: - ["Prajit Ramachandran", "http://prajitr.github.io/"] - ["Mathias Bynens", "http://mathiasbynens.be/"] - ["rilysh", "https://github.com/rilysh"] --- Brainfuck (not capitalized except at the start of a sentence) is an extremely minimal Turing-complete programming language with just 8 commands. You can try brainfuck on your browser with [brainfuck-online](https://copy.sh/brainfuck/). ```bf Any character not "><+-.,[]" (excluding quotation marks) is ignored. Brainfuck is represented by an array with 30,000 cells initialized to zero and a data pointer pointing at the current cell. There are eight commands: + : Increments the value at the current cell by one. - : Decrements the value at the current cell by one. > : Moves the data pointer to the next cell (cell on the right). < : Moves the data pointer to the previous cell (cell on the left). . : Prints the ASCII value at the current cell (i.e. 65 = 'A'). , : Reads a single input character into the current cell. [ : If the value at the current cell is zero, skips to the corresponding ] . Otherwise, move to the next instruction. ] : If the value at the current cell is zero, move to the next instruction. Otherwise, move backwards in the instructions to the corresponding [ . [ and ] form a while loop. Obviously, they must be balanced. Let's look at some basic brainfuck programs. ++++++ [ > ++++++++++ < - ] > +++++ . This program prints out the letter 'A'. First, it increments cell #1 to 6. Cell #1 will be used for looping. Then, it enters the loop ([) and moves to cell #2. It increments cell #2 10 times, moves back to cell #1, and decrements cell #1. This loop happens 6 times (it takes 6 decrements for cell #1 to reach 0, at which point it skips to the corresponding ] and continues on). At this point, we're on cell #1, which has a value of 0, while cell #2 has a value of 60. We move on cell #2, increment 5 times, for a value of 65, and then print cell #2's value. 65 is 'A' in ASCII, so 'A' is printed to the terminal. , [ > + < - ] > . This program reads a character from the user input and copies the character into cell #1. Then we start a loop. Move to cell #2, increment the value at cell #2, move back to cell #1, and decrement the value at cell #1. This continues on until cell #1 is 0, and cell #2 holds cell #1's old value. Because we're on cell #1 at the end of the loop, move to cell #2, and then print out the value in ASCII. Also keep in mind that the spaces are purely for readability purposes. You could just as easily write it as: ,[>+<-]>. Try and figure out what this program does: ,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> This program takes two numbers for input, and multiplies them. The gist is it first reads in two inputs. Then it starts the outer loop, conditioned on cell #1. Then it moves to cell #2, and starts the inner loop conditioned on cell #2, incrementing cell #3. However, there comes a problem: At the end of the inner loop, cell #2 is zero. In that case, inner loop won't work anymore since next time. To solve this problem, we also increment cell #4, and then recopy cell #4 into cell #2. Then cell #3 is the result. ``` And that's brainfuck. Not that hard, eh? For fun, you can write your own brainfuck programs, or you can write a brainfuck interpreter in another language. The interpreter is fairly simple to implement, but if you're a masochist, try writing a brainfuck interpreter… in brainfuck. ## Further Reading * [esolang-wiki](https://esolangs.org/wiki/Brainfuck) * [learn brainfuck](http://cydathria.com/bf/brainfuck.html) * [other resources](http://www.muppetlabs.com/~breadbox/bf/) ================================================ FILE: bg/logtalk.md ================================================ --- contributors: - ["Paulo Moura", "http://github.com/pmoura"] translators: - ["vsraptor", "https://github.com/vsraptor"] --- Logtalk е обектно-ориентиран (ОО) модерен логически език за програмиране, които разширява Prolog с възможности за капсулиране (еncapsulation) и многократно използване на кода без да компрометира декларативните възможности на езика. Logtalk е имплементиран така че да може да бъде адапртиран към всеки стандартен Prolog като back-end компилатор, тоест е напълно прозрачен за нормална Prolog програма. Допълнително, Logtalk също може да интерпретира Prolog модули, като Logtalk обекти. Основната структурна единица за изграждане на програмни със Logtalk е чрез използване на обекти. Logtalk поддържа както стандартния начин за изграждане на иерархий от класове познати ни от езици като Java, същто така и prototype-OOP познат ни от езици като JavaScript. Запомнете че всичко стартира с дефинирането и създаването на обект. ## Syntax (Синтакс) Logtalk използва стандартен Prolog синтакс, с минимум допълнителни оператори и директиви. Важно последствие от това е че кода лесно се капсулира с много малко промени спрямо оригинален код. Операторите които Logtalk добавя към Prolog са : * `::/2` - изпраща саобщение до обект (аналогично на метод в стандартните ООП езици) * `::/1` - изпраща саобщение до себе си (*self*) (тоест до обекта който е получил съобщението което обработваме в момента) * `^^/1` - *super* call (изпраща саобщение до наследен или импортиран предикат(predicate)) ## Entities and roles (Субекти и роли) Logtalk предоставя обекти, портоколи и категории като първокласни-субекти (first-class entities). Връзката между тях описва ролята която субектите изпалняват. Обектите могат да играят различни роли в зависимост от как ги дефинираме тоест какви директиви използваме при дефиницията. Например когато използваме обект А за да създадем нов обект Б, обект Б играе ролята на "инстанция", а обект А играе ролята на клас. Ако използваме "extends"-дефиниция единия от обектите играе ролята на протоип(prototype) за другия. ## Defining an object (Дефиниране на обект) Чрез дефинирането на обект ние капсулираме дефиницията на "предикатите". Обекти могат да се създадат динамично или дефинират статично във код-файла. Ето как дефинираме примерен обект : ```logtalk :- object(list). :- public(member/2). member(Head, [Head| _]). member(Head, [_| Tail]) :- member(Head, Tail). :- end_object. ``` ## Compiling source files (Компилиран) Ако предположим че кода е записан във файл с име list.lgt, можем да го компилираме чрез logtalk_load/1 предиката или съкратения вариант {}/1. ```logtalk ?- {list}. yes ``` ## Sending a message to an object (Изпращане на събщение до обект) Както казахме ::/2 infix оператор се използва за изпращане на съобщение до обекта. Както в Prolog, ние можем да backtrack-нем за алтернативни решения, понеже метода е просто стандартен предикат : ```logtalk ?- list::member(X, [1,2,3]). X = 1 ; X = 2 ; X = 3 yes ?- write_canonical(list::member(X, [1,2,3])). ::(list,member(_,[1,2,3])) ``` Кагато декларирме обект автоматично предикатите са капсулирани (еncapsulation), тоест извън обекта те са невидими за останалата част от програмата. Естествено има опции да променим това поведение чрез public, protected, или private предикати. ```logtalk :- object(scopes). :- private(bar/0). bar. local. :- end_object. ``` Ако кода е записан в scopes.lgt фаил и се опитаме да изпратим саобщтение до частен(private) или локален предикат ще получим грешка: ```logtalk ?- {scopes}. yes ?- catch(scopes::bar, Error, true). Error = error( permission_error(access, private_predicate, bar/0), logtalk(scopes::bar, user) ) yes ?- catch(scopes::local, Error, true). Error = error( existence_error(predicate_declaration, local/0), logtalk(scopes::local, user) ) yes ``` Когато предиката е непознат за обекта това също генерира грешка. Например : ```logtalk ?- catch(scopes::unknown, Error, true). Error = error( existence_error(predicate_declaration, unknown/0), logtalk(scopes::unknown, user) ) yes ``` ## Протоколи (Defining and implementing a protocol) За тези от вас свикнали със стандартно ООП, Protocols наподобяват Interfaces в Java. Протоколите съдържат предикати които могат да бъдат в последствие имплементирани в обекти и категории : ```logtalk :- protocol(listp). :- public(member/2). :- end_protocol. :- object(list, implements(listp)). member(Head, [Head| _]). member(Head, [_| Tail]) :- member(Head, Tail). :- end_object. ``` Обхвата(scope) на предикатите в протокола могат да бъде ограничени чрез protected или private клаузи. Например: ```logtalk :- object(stack, implements(private::listp)). :- end_object. ``` Всички субекти(entity) релации могат да бъдат пре-дефинирани с public, protected или private, подбно на начина показан по горе. ## Прототипи (Prototypes) Всеки обект без instantiation или specialization спецификация с друг обект, играе ролята на прототип. Прототип-обект може да предефинира и разщири протоипа-родител. ```logtalk % clyde, our prototypical elephant :- object(clyde). :- public(color/1). color(grey). :- public(number_of_legs/1). number_of_legs(4). :- end_object. % fred, another elephant, is like clyde, except that he's white :- object(fred, extends(clyde)). color(white). :- end_object. ``` Когато системата отговаря на съобщение изпратено до обект който играе ролята на прототип, тя търси отговор първо в прототипа и ако не намери предикат делегира отговора на прототипа-родител-обект : ```logtalk ?- fred::number_of_legs(N). N = 4 yes ?- fred::color(C). C = white yes ``` Съобщението е валидно но няма да генерира грещка, ако предиката е дефиниран но не е деклариран/имплементиран. Това е така наречения closed-world assumption. Например : ```logtalk :- object(foo). :- public(bar/0). :- end_object. ``` Ако заредим файла и се опитаме да извикаме bar/0, няма да получим отговор, както може да очакваме. Ако обаче предиката не е дори дефиниран, ще получим гращка : ```logtalk ?- {foo}. yes ?- foo::bar. no ?- catch(foo::baz, Error, true). Error = error( existence_error(predicate_declaration, baz/0), logtalk(foo::baz, user) ) yes ``` ## Класове и инстанции (Classes and instances) За да саздадем обекти които играят ролята на класове и/или инстанции, трябва да използваме поне instantiation или specialization дефиниция с друг обект. Обектите които играят роля на мета-класове могат да се използват ако е нужно още за саздаване на инстанции на класа. Следващия пример ще илюстрира как можем динамично да саздадаваме обекти : ```logtalk % a simple, generic, metaclass defining a new/2 predicate for its instances :- object(metaclass, instantiates(metaclass)). :- public(new/2). new(Instance, Clauses) :- self(Class), create_object(Instance, [instantiates(Class)], [], Clauses). :- end_object. % a simple class defining age/1 and name/1 predicate for its instances :- object(person, instantiates(metaclass)). :- public([ age/1, name/1 ]). % a default value for age/1 age(42). :- end_object. % a static instance of the class person :- object(john, instantiates(person)). name(john). age(12). :- end_object. ``` Когато отговаряме на съобщение изпратено до обект който играе ролята на инстанция, системата валидира съобщението първо в текущия клас, след това класа-родител ако е необходимо. Ако съобщението е валидно тогава проверяваме инстанцията : ```logtalk ?- person::new(Instance, [name(paulo)]). Instance = o1 yes ?- o1::name(Name). Name = paulo yes ?- o1::age(Age). Age = 42 yes ?- john::age(Age). Age = 12 yes ``` ## Категории (Categories) Категорията е капсулран код който може да се рециклира (reuse) в различни обекти. Докато Протокола е само дефиниции Категорията е сащо и декларация/имплементация на предикатите които сме дефинирали. В следващия пример ще дефинираме категории представящи автомобилни двигатели след което ще ги импортираме в автомобил-обекти : ```logtalk % a protocol describing engine characteristics :- protocol(carenginep). :- public([ reference/1, capacity/1, cylinders/1, horsepower_rpm/2, bore_stroke/2, fuel/1 ]). :- end_protocol. % a typical engine defined as a category :- category(classic, implements(carenginep)). reference('M180.940'). capacity(2195). cylinders(6). horsepower_rpm(94, 4800). bore_stroke(80, 72.8). fuel(gasoline). :- end_category. % a souped up version of the previous engine :- category(sport, extends(classic)). reference('M180.941'). horsepower_rpm(HP, RPM) :- ^^horsepower_rpm(ClassicHP, ClassicRPM), % "super" call HP is truncate(ClassicHP*1.23), RPM is truncate(ClassicRPM*0.762). :- end_category. % with engines (and other components), we may start "assembling" some cars :- object(sedan, imports(classic)). :- end_object. :- object(coupe, imports(sport)). :- end_object. ``` Категориите се компилират отделно и разрешават импортираните обекти да бъдат обновени като просто обновим категориите без да е необходимо да прекомпилираме обекта: ```logtalk ?- sedan::current_predicate(Predicate). Predicate = reference/1 ; Predicate = capacity/1 ; Predicate = cylinders/1 ; Predicate = horsepower_rpm/2 ; Predicate = bore_stroke/2 ; Predicate = fuel/1 yes ``` ## Hot patching Категориите още могат да се използват за промяна на обекти "в движение", след като вече са били инстанциирани. Например : ```logtalk :- object(buggy). :- public(p/0). p :- write(foo). :- end_object. ``` Да предположим че обекта изпечатва грешното съобщение p/0 : ```logtalk ?- {buggy}. yes ?- buggy::p. foo yes ``` Ако кода който описва този обект не е наличен и трябва да коригираме приложението, ние можем просто да създадем категория която да коригира необходимия предикат : ```logtalk :- category(patch, complements(buggy)). % fixed p/0 def p :- write(bar). :- end_category. ``` След компилиране и зареждане на категорията ще получим : ```logtalk ?- {patch}. yes ?- buggy::p. bar yes ``` ## Parametric objects and categories Обектите и категориите могат да се параметризират ако използваме за индентификатор комплексен-термин вместо атом. Параметрите са логически променливи достъпни за всички капсулирани предикати. Пример с геометрични кръгове : ```logtalk :- object(circle(_Radius, _Color)). :- public([ area/1, perimeter/1 ]). area(Area) :- parameter(1, Radius), Area is pi*Radius*Radius. perimeter(Perimeter) :- parameter(1, Radius), Perimeter is 2*pi*Radius. :- end_object. ``` Параметричните-обекти се използват като всеки друг обект, обикновенно осигуряваики стойности за параметрите когато изпращаме съобщение. ```logtalk ?- circle(1.23, blue)::area(Area). Area = 4.75291 yes ``` Параметричните-обекти още осигуряват лесен начин за ассоцииране на различни предикати със нормални Prolog предикати. Prolog факти могат да бъдат интерпретирани като посредници (proxies). Например следните клаузи на circle/2 предикат : ```logtalk circle(1.23, blue). circle(3.71, yellow). circle(0.39, green). circle(5.74, black). circle(8.32, cyan). ``` можем лесно да изчислим площа на всички кръгове : ```logtalk ?- findall(Area, {circle(_, _)}::area(Area), Areas). Areas = [4.75291, 43.2412, 0.477836, 103.508, 217.468] yes ``` {Goal}::Message формата доказва(proves) Goal и изпраща съобщение до генерирания термин. ## Събития и мониторинг (Events and monitors) Logtalk поддържа event-driven програмиране чрез дефинирането на събития и монитори за тези събития. Събитие е просто изпращане на съобщение към обект. При обработването на съобщение системата разпознава before-събитие и after-събитие. Мониторите дефинират предикати които ще прихаванат тези събития (before/3 и after/3). Нампример следния монитор ще прихаване съобщенията изпратени чрез ::/2 : ```logtalk :- object(tracer, implements(monitoring)). % built-in protocol for event handlers :- initialization(define_events(_, _, _, _, tracer)). before(Object, Message, Sender) :- write('call: '), writeq(Object), write(' <-- '), writeq(Message), write(' from '), writeq(Sender), nl. after(Object, Message, Sender) :- write('exit: '), writeq(Object), write(' <-- '), writeq(Message), write(' from '), writeq(Sender), nl. :- end_object. ``` Ето как можем да проследим реакцията на изпращане на съобщение : ```logtalk ?- list::member(X, [1,2,3]). call: list <-- member(X, [1,2,3]) from user exit: list <-- member(1, [1,2,3]) from user X = 1 ; exit: list <-- member(2, [1,2,3]) from user X = 2 ; exit: list <-- member(3, [1,2,3]) from user X = 3 yes ``` Събития могат да се изтрият динамично чрез define_events/5 и abolish_events/5 предикати. ## Lambda expressions Logtalk поддържа lambda expressions. Lambda параметрите се предават чрез списък към (>>)/2 infix оператор свързвайки ги с lambda. Ето няколко примера : ```logtalk ?- {library(metapredicates_loader)}. yes ?- meta::map([X,Y]>>(Y is 2*X), [1,2,3], Ys). Ys = [2,4,6] yes ``` Currying се поддържа : ```logtalk ?- meta::map([X]>>([Y]>>(Y is 2*X)), [1,2,3], Ys). Ys = [2,4,6] yes ``` Lambda free variables can be expressed using the extended syntax {Free1, ...}/[Parameter1, ...]>>Lambda. ## Макроси (Macros) Термини и Цели могат да бъдат пре-интерпретирани (expanded) по време на компилация ако специфицираме hook-обект който дефинира прецедурите на пре-интерпретиране. Нека следният обект е записан във фаил source.lgt : ```logtalk :- object(source). :- public(bar/1). bar(X) :- foo(X). foo(a). foo(b). foo(c). :- end_object. ``` и следния hooк-обект е записан в my_macros.lgt, който пре-интерпретира foo/1 предиката : ```logtalk :- object(my_macros, implements(expanding)). % built-in protocol for expanding predicates term_expansion(foo(Char), baz(Code)) :- char_code(Char, Code). % standard built-in predicate goal_expansion(foo(X), baz(X)). :- end_object. ``` След зареждането на файла с макроси ние можем да пре-интерпретираме ползайки hook-флаг за компилатора : ```logtalk ?- logtalk_load(my_macros), logtalk_load(source, [hook(my_macros)]). yes ?- source::bar(X). X = 97 ; X = 98 ; X = 99 true ``` ## Допълнителна информация (Further information) Посетете сайта на [Logtalk website](http://logtalk.org) за повече информация. ================================================ FILE: bg/perl.md ================================================ --- contributors: - ["Korjavin Ivan", "http://github.com/korjavin"] - ["Dan Book", "http://github.com/Grinnz"] translators: - ["Красимир Беров", "https://github.com/kberov"] --- Perl е изключително мощен език за програмиране с широка област на приложение и над 25 годишна история. Perl работи на повече от 100 операционни системи от мини до супер-компютри и е подходящ както за бърза разработка на скриптове така и за огромни приложения. ```perl # Едноредовите коментари започват със знака диез. #### Стриктен режим и предупреждения use strict; use warnings; # Силно препоръчително е всички скриптове и модули да включват тези редове. # strict спира компилацията в случай на необявени предварително променливи. # warnings показва предупредителни съобщения в случай на често допускани грешки, # например използване на променливи без стойност в низове. #### Типове променливи в Perl # Променливите започват със съответен знак (sigil - от латински sigillum ), # който представлява символ, указващ типа на променливата. Името на самата # променлива започва с буква или знак за подчертаване (_), следван от какъвто и # да е брой букви, цифри или знаци за подчертаване. Забележете, че ако напишете # 'use utf8;' (без кавичките), можете да използвате всякакви букви за имена на # променливите, включително и български. ### Perl има три главни типа променливи: $scalar (скалар), @array (масив), and %hash (хеш). ## Скалари # Скаларът представлява единична стойност: my $animal = "camel"; my $answer = 42; use utf8; my $животно = 'камила'; # Стойностите на скаларите могат да бъдат низове, цели числа или числа с # плаваща запетая (десетични дроби). Perl автоматично ги ползва и превръща от # един тип стойност в друга, според както е необходимо. ## Масиви # Масивът представлява списък от стойности: my @animals = ("камила", "llama", "owl"); my @numbers = (23, 42, 69); my @mixed = ("camel", 42, 1.23); # Елементите на масива се достъпват като се използват квадратни скоби и $, # който указва каква стойност ще бъде върната (скалар). my $second = $animals[1]; ## Хешове # Хешът представлява набор от двойки ключ/стойност: my %fruit_color = ("ябълка", "червена", "banana", "yellow"); # Може да използвате празно пространство и оператора "=>" (тлъста запетая), # за да ги изложите по-прегледно: %fruit_color = ( ябълка => "червена", banana => "yellow", ); # Елементите (стойностите) от хеша се достъпват чрез използване на ключовете. # Ключовете се ограждат с фигурни скоби и се поставя $ пред името на хеша. my $color = $fruit_color{ябълка}; # Скаларите, масивите и хешовете са документирани по-пълно в perldata. # На командния ред напишете (без кавичките) 'perldoc perldata'. #### Указатели (Референции) # По-сложни типове данни могат да бъдат създавани чрез използване на указатели, # които ви позволяват да изграждате масиви и хешове в други масиви и хешове. my $array_ref = \@array; my $hash_ref = \%hash; my @array_of_arrays = (\@array1, \@array2, \@array3); # Също така можете да създавате безименни масиви и хешове, към които сочат само # указатели. my $fruits = ["apple", "banana"]; my $colors = {apple => "red", banana => "yellow"}; # Можете да достигате до безименните структури като поставяте отпред съответния # знак на структурата, която искате да достъпите (дереферирате). my @fruits_array = @$fruits; my %colors_hash = %$colors; # Можете да използвате оператора стрелка (->), за да достигнете до отделна # скаларна стойност. my $first = $array_ref->[0]; my $value = $hash_ref->{banana}; # Вижте perlreftut и perlref, където ще намерите по-задълбочена документация за # указателите (референциите). #### Условни изрази и цикли # В Perl ще срещнете повечето от обичайните изрази за условия и обхождане (цикли). if ($var) { ... } elsif ($var eq 'bar') { ... } else { ... } unless (условие) { ... } # Това е друг, по-четим вариант на "if (!условие)" # Perl-овския начин след-условие print "Yow!" if $zippy; print "Нямаме банани" unless $bananas; # докато while (условие) { ... } # цикли for и повторение for (my $i = 0; $i < $max; $i++) { print "index is $i"; } for (my $i = 0; $i < @elements; $i++) { print "Current element is " . $elements[$i]; } for my $element (@elements) { print $element; } # мълчаливо - използва се подразбиращата се променлива $_. for (@elements) { print; } # Отново Perl-овския начин след- print for @elements; # отпечатване на стойностите чрез обхождане ключовете на указател към хеш print $hash_ref->{$_} for keys %$hash_ref; #### Регулярни (обикновени) изрази # Поддръжката на регулярни изрази е залеганала дълбоко в Perl. Задълбочена # документация ще намерите в perlrequick, perlretut и на други места. # Но ето накратко: # Просто съвпадение if (/foo/) { ... } # истина ако $_ съдържа "foo" if ($x =~ /foo/) { ... } # истина ако $x съдържа "foo" # Просто заместване $x =~ s/foo/bar/; # замества foo с bar в $x $x =~ s/foo/bar/g; # Замества ВСИЧКИ ПОЯВИ на foo с bar в $x #### Файлове и Вход/Изход (I/O) # Можете да отворите файл за въвеждане на данни в него или за извеждане на # данни от него като използвате функцията "open()". open(my $in, "<", "input.txt") or die "Не мога да отворя input.txt: $!"; open(my $out, ">", "output.txt") or die "Can't open output.txt: $!"; open(my $log, ">>", "my.log") or die "Can't open my.log: $!"; # Можете да четете от отворен файлов манипулатор като използвате оператора # "<>". В скаларен контекст той чете по един ред от файла наведнъж, а в списъчен # контекст изчита всички редове от файла наведнъж като присвоява всеки ред на # масива: my $line = <$in>; my @lines = <$in>; #### Подпрограми (функции) # Да се пишат подпрограми е лесно: sub logger { my $logmessage = shift; open my $logfile, ">>", "my.log" or die "Could not open my.log: $!"; print $logfile $logmessage; } # Сега можем да ползваме подпрограмата като всяка друга вградена функция: logger("Имаме подпрограма, която пише във файл-отчет!"); #### Модули # Модулът е набор от програмен код на Perl, обикновено подпрограми, който може # да бъде използван в друг програмен код на Perl. Обикновено се съхранява във # файл с разширение .pm, така че perl (програмата) да може лесно да го разпознае. # В MyModule.pm package MyModule; use strict; use warnings; sub trim { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } 1; # От другаде: use MyModule; MyModule::trim($string); # Чрез модула Exporter може да направите функциите си износни, така че други # програми да могат да ги внасят (импортират). # Такива функции се използват така: use MyModule 'trim'; trim($string); # Много Perl-модули могат да се свалят от CPAN (http://www.cpan.org/). Те # притежават редица полезни свойства, които ще ви помогнат да си свършите работа # без да откривате колелото. Голям брой известни модули като Exporter са включени # в дистрибуцията на самия Perl. Вижте perlmod за повече подробности, свързани с # модулите в Perl. #### Обекти # Обектите в Perl са просто референции, които знаят на кой клас (пакет) # принадлежат. По този начин методите (подпрограми), които се извикват срещу # тях могат да бъдат намерени в съответния клас. За да се случи това, в # конструкторите (обикновено new) се използва вградената функция # bless. Ако използвате обаче модули като Moose или Moo, няма да ви се налага # сами да извиквате bless (ще видите малко по-долу). package MyCounter; use strict; use warnings; sub new { my $class = shift; my $self = {count => 0}; return bless $self, $class; } sub count { my $self = shift; return $self->{count}; } sub increment { my $self = shift; $self->{count}++; } 1; # Методите могат да се извикват на клас или на обект като се използва оператора # стрелка (->). use MyCounter; my $counter = MyCounter->new; print $counter->count, "\n"; # 0 $counter->increment; print $counter->count, "\n"; # 1 # Модулите Moose и Moo от CPAN ви помагат леснот да създавате класове. Те # предоставят готов конструктор (new) и прост синтаксис за деклариране на # свойства на обектите (attributes). Този клас може да се използва по същия начин # като предишния по-горе. package MyCounter; use Moo; # внася strict и warnings has 'count' => (is => 'rwp', default => 0, init_arg => undef); sub increment { my $self = shift; $self->_set_count($self->count + 1); } 1; # Обектно-ориентираното програмиране е разгледано по-задълбочено в perlootut, # а изпълнението му на ниско ниво в Perl е обяснено в perlobj. ``` #### Често задавани въпроси (FAQ) # perlfaq съдържа въпроси и отговори, отнасящи се до много общи задачи и предлага # за ползване добри модлули от CPAN, подходящи за решаване на различни проблеми. #### Повече за четене - [Въведение в Perl](http://www.slideshare.net/kberov/01-intro-bg) - [PERL - Курс на МГУ "Св.Иван Рилски" (13 ЧАСТИ)](http://www.mgu.bg/drugi/ebooks/belchevski/perl.html) - [perl-tutorial](http://perl-tutorial.org/) - [Learn at www.perl.com](http://www.perl.org/learn.html) - [perldoc](http://perldoc.perl.org/) - и идващото с perl: `perldoc perlintro` ================================================ FILE: bqn.md ================================================ --- name: BQN filename: learnbqn.bqn contributors: - ["Raghu Ranganathan", "https://github.com/razetime"] --- BQN is a modern array language (similar to APL) that aims to eliminate burdensome aspects of the APL tradition. It is recommended to try these code examples out in a REPL. The [online REPL](https://mlochbaum.github.io/BQN/try.html) is recommended for quick start, since it comes with keyboard and easy to access help. You can try building [CBQN](https://github.com/dzaima/CBQN) for a local install, but it will need keyboard setup. ```bqn # This is a comment. # The characters ',' and `⋄` are statement separators. ################## # Main datatypes # ################## # Numbers 1,2,3,4 ¯1,¯2,¯3 # Negative numbers are written with a high minus π,∞,¯π,¯∞ # Pi and Infinity are defined constants 1_234_456 # You can add underscores in between numbers # This does not change their value 1.3E4 # Scientific notation is supported # Characters 'a','⥊' ' ' # Yes, you can put *any* character in a character literal @ # Null character ('\0' in C) # Arrays 1‿2‿3 # Stranding, good for simple lists ⟨1,2,3⟩ # General list notation ⟨1‿2,2‿3⟩ # Both can be mixed [1‿2,2‿3] # Array notation # An array is multidimensional, as opposed to containing sublists. # It must be rectangular in shape (a grid structure rather than a tree structure) [1‿2‿3,4‿5] # This is hence invalid # May be familiar coming from Numpy, MATLAB and similar languages. "asdf" # Character array (String) "newline separated" # Allows newlines "quo""tes" # Escape a double quote by typing it twice # Functions 1{𝕨+𝕩}3 # All functions are infix # 𝕨 is left argument, 𝕩 is right argument {-𝕩}5 # 𝕨 can be omitted 1+3 # Same as the above {𝕊𝕩} # 𝕊 is a recursive call # (this function will loop forever) {𝕨 𝕊 𝕩: 𝕨+𝕩} # Functions can have headers (too many cases to discuss here) # Headers can define arity {𝕊 a‿b: a}1‿2 # and also do basic pattern matching # (returns 1) # Modifiers (higher order functions) {𝕗,𝔽,𝕘,𝔾} # 𝔽 and 𝔾 are the operands as callable functions # 𝕗 and 𝕘 are the operands as values {𝔽𝕩} # 1-modifiers use 𝔽/𝕗 ONLY ˜,˘,¨,⁼,⌜ # primitive 1-modifiers are superscripts {𝕨𝔽𝔾𝕩} # 2-modifiers MUST use both 𝔽/𝕗 and 𝔾/𝕘 in body or header ⊸,∘,○,⟜ # primitive 2-modifiers all have circles +{⟨𝕗⟩} # returns ⟨ + ⟩ 1-{𝔽 𝕨 𝔾 𝕩 }×2 # returns ¯2 (operators are *also* infix) # (same as 1 -○× 2) # Trains (Special form of function composition) (+´÷≠) # Average (but how?) # The above train is an F G H train, where # (F G H) 𝕩 → (F 𝕩) G (H 𝕩) # F ← +´, G ← ÷, H ← ≠ # In explicit form, this is {(+´𝕩)÷≠𝕩} # The second pattern is (f g) 𝕩 → f g 𝕩. # longer trains are complex arrangements of these patterns, involving constants and Nothing (·). # Read more about trains at https://mlochbaum.github.io/BQN/doc/train.html # Evaluation order: # BQN evaluates functions right to left with no precedence rules governing *functions*. Functions are what # one would call operators in a mainstream language. 1÷2+3 # 1÷(2+3) = 0.2 (1÷2)+3 # ((1÷2)+3) = 1.5 # Modifiers: # Modifiers are higher order functions, and bind tighter than functions. Modifiers execute left to right. # Modifiers can take non-function arguments e.g. Constant (`˙`) + 1+˜2+○-∘×3 # 1(+˜)(2((+○-)∘×)3) # Variables # Since the case of a variable matters to determine what it means, BQN variables are *case insensitive* # The case that a variable is written in can change the way it is interpreted by BQN. # Eg. `F` refers to a value as a callable function, whereas `f` refers to the same variable as just a value. # Variable assignment is done with `←`. Variables have naming conventions based on their value: subject ← 1‿2‿3 # Arrays, single values, namespaces come under this # name must start with with a lowercase letter Function ← {𝕨+𝕩} # Primitive and user defined functions come under this, both monadic and dyadic # Starts with an uppercase letter _1modifier ← {𝕨𝔽𝕩} # Starts with an underscore _2modifier_ ← {𝔽𝕨𝔾𝕩} # Starts and ends with an underscore # Variable modification is done with `↩`. An existing name cannot be reassigned with `←`. Func ↩ {"Hello"∾𝕩} array_or_atom +↩ 2 # You can use a dyadic function for modification #≡ 3‿4‿5 array_or_atom -↩ # Or a monadic function. #≡ ¯3‿¯4‿¯5 # Due to all functions being infix, you can use your own functions for modification as well: array_or_atom {2⋆𝕩}↩ #≡ ⟨ 0.125, 0.0625, 0.03125 ⟩ ################## # BQN Primitives # ################## # All of BQN's base primitives are a single character long. Refer to https://mlochbaum.github.io/BQN/help/index.html for # examples. # Here we will look at a few primitives from each section. You will want to consult the docs for detailed explanations. # Primitive Functions # All BQN functions are variadic, and can take one or two arguments. The base functions have both monadic and dyadic overloads. # Usually the two overloads for a function are related. ## Arithmetic Functions +, -, ×, ÷ # Add, Subtract, Signum/Multiply, Reciprocal/Divide , '*' does NOT do multiplication # ⌊∘÷ does floor division √, ⋆ # Square root/Nth root, e^x/Power # All Arithmetic functions vectorize: 1 + 2‿3‿4 #≡ 3‿4‿5 1‿2‿3 + 2‿3‿4 #≡ 3‿5‿7 # Character arithmetic(+ and - only): "abc"+3 #≡ "def" 'a'-'d' #≡ ¯3 ## Logic Functions ∧, ∨, ¬ # For Booleans, return 1 or 0 ≤, <, >, ≥, = # Vectorizing comparisons ≡, ≢ # Nonvectorizing comparisons ## Array manipulation Functions ↕ # Make a range ∾, ≍, ⋈ # Joining arrays together a←1‿2‿3,b←4‿5 # Let us take a and b. a∾b #≡ 1‿2‿3‿4‿5 a≍b # Same as previous, since a and b are not multidimensional # Adds an extra dimension, similar to a ⋈ for multidimensional arrays. a⋈b #≡ ⟨1‿2‿3, 4‿5⟩ ⊑, ⊏ # Indexing 1⊑1‿2‿3 #≡ 2 (BQN is 0-indexed) 1‿2⊏1‿2‿3 #≡ 2‿3 (for multiple indices) ↑, ↓ # Getting a prefix, suffix of an array. # together they can be used for slicing ⥊ # Reshape/repeat items to create a new array # Primitive 1-Modifiers ## Looping combinators ¨, ˘, ⌜ # Mapping/Zipping ´, ˝ # Fold from right ` # Scan from left ## General combinators ˜ # duplicate argument/swap args - Very useful! ˙ # Create constant function 1 -˜ 2 #≡ 2 - 1 +˜ 2 #≡ 2 + 2 # Primitive 2-modifiers ## Control Flow ◶ # Choose from a list of funcs ⍟ # Repeat n times ## General Combinators ⊸, ⟜ # hook, hookf ∘, ○ # simple function composition ########## # Blocks # ########## # Code delimited by {} # Lexically scoped # For more info: https://mlochbaum.github.io/BQN/doc/block.html # Can have headers, which are ways to explicitly define what a block should be. # A block without headers is automatically inferred from its special variables (𝕨, 𝕩, ...). # Function blocks # Implicit variables(Capitals are functions): # - 𝕨, 𝕎 left argument # - 𝕩, 𝕏 right argument # - 𝕤, 𝕊 represent the block itself # Optional: one or more headers that trigger based on # - pattern match (':') o # - condition ('?') (similar to if-then-else) { # A factorial using headers: 𝕊 0: 1; 𝕊 𝕩: 𝕩×𝕊 𝕩-1 } { # Factorial with predicates 𝕩<2 ? 1; # Similar to an if-else pattern. 𝕩×𝕊 𝕩-1 } # Modifier blocks # create 1-modifiers and 2-modifiers, which have separate types # Implicit variables(Capitals are functions): # - has 𝕨 and 𝕩 if needed # - 𝕗, 𝔽 left operand # - 𝕘, 𝔾 right operand (only in 2-modifiers) # - 𝕣 represents the block itself* (requires underscores as per convention) # Same header rules as functions. { 𝕨=0 ? 𝔽 𝕩; 𝔾 𝕩 } # execute 𝔽 or 𝔾 based on whether left argument is 0. # Namespace blocks # Create immutable namespaces with fields # Require exports (`⇐`) for accessible fields. # Use '.' for field access n←{ A←+ b⇐4 } n.b #≡ 4 n.a # ERROR # Immediate Blocks # No arguments taken # Run the code inside and return the last statement # Often responsible for strange errors. # Can be mistaken for other blocks easily # Good for avoiding scoping issues { 1‿2‿3 } {+} # Trick for returning a function as a value #################### # Basic constructs # #################### # Functional programming # `¨` is used for mapping, as discussed before: {𝕩∾2}¨1‿2‿3 #≡ ⟨1‿2,2‿2,3‿2⟩ # ⋈¨ is a plain zip, which produces pairs. # `¨` acts as a zipWith when used with two arguments: 1‿2‿3 {⟨𝕩+2,2⥊𝕨⟩} 4‿5‿6 #≡ ⟨⟨6,1‿1⟩,⟨7,2‿2⟩,⟨8,3‿3⟩⟩ # `/` is replicate, which serves several purposes *including* filtering. # elements in 𝕩 are repeated by the corresponding number in 𝕨. 1‿2‿3‿0/4‿5‿6‿7 #≡ 4‿5‿5‿6‿6‿6 # a simple filter idiom is F⊸/: {2|𝕩}⊸/67‿42‿83 # keep the odd elements #≡ 67‿83 # Conditionals # There are two main ways to define a conditional. ## Predicate headers { 𝕩 > 2: "greater than 2"; 𝕩 < 2: "lesser than 2"; "equal to 2" } ## Choose (function-based) # - 2-modifier # - 𝔾: list of functions that serve as bodies # - 𝔽: condition function that specifies which function from 𝔾 to select # The same conditional as above would be: {⊑/⟨𝕩>2, 𝕩<2, 𝕩=2⟩}◶⟨ {𝕊: "greater than 2"} {𝕊: "lesser than 2"} {𝕊: "equal to 2"} ⟩ ## Some helpers for conditionals If ← {𝕏⍟𝕎@}´ # Used as If ⟨Condition, Block⟩ IfElse ← {c‿T‿F: c◶F‿T@} # Used as IfElse ⟨Condition, Block, ElseBlock⟩ # Looping # The primary form of unbounded looping is recursion (performed with 𝕊). # BQN does not eliminate tail calls, but the while idiom can be used to work around this: While ← {𝕩{𝔽⍟𝔾∘𝔽_𝕣_𝔾∘𝔽⍟𝔾𝕩}𝕨@}´ # While 1‿{... to run forever DoWhile ← {𝕏@ ⋄ While 𝕨‿𝕩}´ # A For loop can be done with ¨, functions need not be pure. ``` ## Ready for more? - [Quickstart guide](https://mlochbaum.github.io/BQN/doc/quick.html) - [Full length, explained documentation](https://mlochbaum.github.io/BQN/doc/index.html) - [Short docs](https://mlochbaum.github.io/BQN/help/index.html) - [BQN community!](https://mlochbaum.github.io/BQN/community/index.html) ================================================ FILE: c++.md ================================================ --- name: C++ filename: learncpp.cpp contributors: - ["Steven Basart", "https://github.com/xksteven"] - ["Matt Kline", "https://github.com/mrkline"] - ["Geoff Liu", "http://geoffliu.me"] - ["Connor Waters", "https://github.com/connorwaters"] - ["Ankush Goyal", "https://github.com/ankushg07"] - ["Jatin Dhankhar", "https://github.com/jatindhankhar"] --- C++ is a systems programming language that, [according to its inventor Bjarne Stroustrup](https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote), was designed to - be a "better C" - support data abstraction - support object-oriented programming - support generic programming Though its syntax can be more difficult or complex than newer languages, it is widely used because it compiles to native instructions that can be directly run by the processor and offers tight control over hardware (like C) while offering high-level features such as generics, exceptions, and classes. This combination of speed and functionality makes C++ one of the most widely-used programming languages. ```c++ ////////////////// // Comparison to C ////////////////// // C++ is almost a superset of C and shares its basic syntax for // variable declarations, primitive types, and functions. // Just like in C, your program's entry point is a function called // main with an integer return type. // This value serves as the program's exit status. // See https://en.wikipedia.org/wiki/Exit_status for more information. int main(int argc, char** argv) { // Command line arguments are passed in by argc and argv in the same way // they are in C. // argc indicates the number of arguments, // and argv is an array of C-style strings (char*) // representing the arguments. // The first argument is the name by which the program was called. // argc and argv can be omitted if you do not care about arguments, // giving the function signature of int main() // An exit status of 0 indicates success. return 0; } // However, C++ varies in some of the following ways: // In C++, character literals are chars, therefore the size is 1 sizeof('c') == sizeof(char) // In C, character literals are ints, therefore the size is 4 sizeof('c') == sizeof(int) // C++ has strict prototyping void func(); // function which accepts no arguments void func(void); // same as earlier // In C void func(); // function which may accept any number of arguments with unknown type void func(void); // function which accepts no arguments // Use nullptr instead of NULL in C++ int* ip = nullptr; // Most C standard headers are available in C++. // C headers generally end with .h, while // C++ headers are prefixed with "c" and have no ".h" suffix. // The C++ standard version: #include // The C standard version: #include int main() { printf("Hello, world!\n"); return 0; } /////////////////////// // Function overloading /////////////////////// // C++ supports function overloading // provided each function takes different parameters. void print(char const* myString) { printf("String %s\n", myString); } void print(int myInt) { printf("My int is %d\n", myInt); } int main() { print("Hello"); // Resolves to void print(const char*) print(15); // Resolves to void print(int) } ///////////////////////////// // Default function arguments ///////////////////////////// // You can provide default arguments for a function // if they are not provided by the caller. void doSomethingWithInts(int a = 1, int b = 4) { // Do something with the ints here } int main() { doSomethingWithInts(); // a = 1, b = 4 doSomethingWithInts(20); // a = 20, b = 4 doSomethingWithInts(20, 5); // a = 20, b = 5 } // Default arguments must be at the end of the arguments list. void invalidDeclaration(int a = 1, int b) // Error! { } ///////////// // Namespaces ///////////// // Namespaces provide separate scopes for variable, function, // and other declarations. // Namespaces can be nested. namespace First { namespace Nested { void foo() { printf("This is First::Nested::foo\n"); } } // end namespace Nested } // end namespace First namespace Second { void foo() { printf("This is Second::foo\n"); } void bar() { printf("This is Second::bar\n"); } } void foo() { printf("This is global foo\n"); } int main() { // Includes all symbols from namespace Second into the current scope. Note // that while bar() works, simply using foo() no longer works, since it is // now ambiguous whether we're calling the foo in namespace Second or the // top level. using namespace Second; bar(); // prints "This is Second::bar" Second::foo(); // prints "This is Second::foo" First::Nested::foo(); // prints "This is First::Nested::foo" ::foo(); // prints "This is global foo" } /////////////// // Input/Output /////////////// // C++ input and output uses streams // cin, cout, and cerr represent stdin, stdout, and stderr. // << is the insertion operator and >> is the extraction operator. #include // Include for I/O streams int main() { int myInt; // Prints to stdout (or terminal/screen) // std::cout referring the access to the std namespace std::cout << "Enter your favorite number:\n"; // Takes in input std::cin >> myInt; // cout can also be formatted std::cout << "Your favorite number is " << myInt << '\n'; // prints "Your favorite number is " std::cerr << "Used for error messages"; // flush string stream buffer with new line std::cout << "I flushed it away" << std::endl; } ////////// // Strings ////////// // Strings in C++ are objects and have many member functions #include std::string myString = "Hello"; std::string myOtherString = " World"; // + is used for concatenation. std::cout << myString + myOtherString; // "Hello World" std::cout << myString + " You"; // "Hello You" // C++ string length can be found from either string::length() or string::size() cout << myString.length() + myOtherString.size(); // Outputs 11 (= 5 + 6). // C++ strings are mutable. myString.append(" Dog"); std::cout << myString; // "Hello Dog" // C++ can handle C-style strings with related functions using cstrings #include char myOldString[10] = "Hello CPP"; cout << myOldString; cout << "Length = " << strlen(myOldString); // Length = 9 ///////////// // References ///////////// // In addition to pointers like the ones in C, // C++ has _references_. // These are pointer types that cannot be reassigned once set // and cannot be null. // They also have the same syntax as the variable itself: // No * is needed for dereferencing and // & (address of) is not used for assignment. std::string foo = "I am foo"; std::string bar = "I am bar"; std::string& fooRef = foo; // This creates a reference to foo. fooRef += ". Hi!"; // Modifies foo through the reference std::cout << fooRef; // Prints "I am foo. Hi!" std::cout << &fooRef << '\n'; // Prints the address of foo // Doesn't reassign "fooRef". This is the same as "foo = bar", and // foo == "I am bar" // after this line. fooRef = bar; std::cout << &fooRef << '\n'; // Still prints the address of foo std::cout << fooRef << '\n'; // Prints "I am bar" // The address of fooRef remains the same, i.e. it is still referring to foo. const std::string& barRef = bar; // Create a const reference to bar. // Like C, const values (and pointers and references) cannot be modified. barRef += ". Hi!"; // Error, const references cannot be modified. // Sidetrack: Before we talk more about references, we must introduce a concept // called a temporary object. Suppose we have the following code: std::string tempObjectFun() { ... } std::string retVal = tempObjectFun(); // What happens in the second line is actually: // - a string object is returned from tempObjectFun // - a new string is constructed with the returned object as argument to the // constructor // - the returned object is destroyed // The returned object is called a temporary object. Temporary objects are // created whenever a function returns an object, and they are destroyed at the // end of the evaluation of the enclosing expression (Well, this is what the // standard says, but compilers are allowed to change this behavior. Look up // "return value optimization" if you're into these kinds of details). So in // this code: foo(bar(tempObjectFun())) // assuming foo and bar exist, the object returned from tempObjectFun is // passed to bar, and it is destroyed before foo is called. // Now back to references. The exception to the "at the end of the enclosing // expression" rule is if a temporary object is bound to a const reference, in // which case its life gets extended to the current scope: void constReferenceTempObjectFun() { // constRef gets the temporary object, and it is valid until the end of this // function. const std::string& constRef = tempObjectFun(); ... } // Another kind of reference introduced in C++11 is specifically for temporary // objects. You cannot have a variable of its type, but it takes precedence in // overload resolution: void someFun(std::string& s) { ... } // Regular reference void someFun(std::string&& s) { ... } // Reference to temporary object std::string foo; someFun(foo); // Calls the version with regular reference someFun(tempObjectFun()); // Calls the version with temporary reference // For example, you will see these two versions of constructors for // std::basic_string: std::basic_string(const basic_string& other); std::basic_string(basic_string&& other); // Idea being if we are constructing a new string from a temporary object (which // is going to be destroyed soon anyway), we can have a more efficient // constructor that "salvages" parts of that temporary string. You will see this // concept referred to as "move semantics". ///////////////////// // Enums ///////////////////// // Enums are a way to assign a value to a constant most commonly used for // easier visualization and reading of code enum ECarTypes { Sedan, Hatchback, SUV, Wagon }; ECarTypes GetPreferredCarType() { return ECarTypes::Hatchback; } // As of C++11 there is an easy way to assign a type to the enum which can be // useful in serialization of data and converting enums back-and-forth between // the desired type and their respective constants enum ECarTypes : uint8_t { Sedan, // 0 Hatchback, // 1 SUV = 254, // 254 Hybrid // 255 }; void WriteByteToFile(uint8_t InputValue) { // Serialize the InputValue to a file } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { // The enum is implicitly converted to a uint8_t due to its declared enum type WriteByteToFile(InputCarType); } // On the other hand you may not want enums to be accidentally cast to an integer // type or to other enums so it is instead possible to create an enum class which // won't be implicitly converted enum class ECarTypes : uint8_t { Sedan, // 0 Hatchback, // 1 SUV = 254, // 254 Hybrid // 255 }; void WriteByteToFile(uint8_t InputValue) { // Serialize the InputValue to a file } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { // Won't compile even though ECarTypes is a uint8_t due to the enum // being declared as an "enum class"! WriteByteToFile(InputCarType); } ////////////////////////////////////////// // Classes and object-oriented programming ////////////////////////////////////////// // First example of classes #include // Declare a class. // Classes are usually declared in header (.h or .hpp) files. class Dog { // Member variables and functions are private by default. std::string name; int weight; // All members following this are public // until "private:" or "protected:" is found. public: // Default constructor Dog(); // Member function declarations (implementations to follow) // Note that we use std::string here instead of placing // using namespace std; // above. // Never put a "using namespace" statement in a header. void setName(const std::string& dogsName); void setWeight(int dogsWeight); // Functions that do not modify the state of the object // should be marked as const. // This allows you to call them if given a const reference to the object. // Also note the functions must be explicitly declared as _virtual_ // in order to be overridden in derived classes. // Functions are not virtual by default for performance reasons. virtual void print() const; // Functions can also be defined inside the class body. // Functions defined as such are automatically inlined. void bark() const { std::cout << name << " barks!\n"; } // Along with constructors, C++ provides destructors. // These are called when an object is deleted or falls out of scope. // This enables powerful paradigms such as RAII // (see below) // The destructor should be virtual if a class is to be derived from; // if it is not virtual, then the derived class' destructor will // not be called if the object is destroyed through a base-class reference // or pointer. virtual ~Dog(); }; // A semicolon must follow the class definition. // Class member functions are usually implemented in .cpp files. Dog::Dog() { std::cout << "A dog has been constructed\n"; } // Objects (such as strings) should be passed by reference // if you are modifying them or const reference if you are not. void Dog::setName(const std::string& dogsName) { name = dogsName; } void Dog::setWeight(int dogsWeight) { weight = dogsWeight; } // Notice that "virtual" is only needed in the declaration, not the definition. void Dog::print() const { std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; } Dog::~Dog() { std::cout << "Goodbye " << name << '\n'; } int main() { Dog myDog; // prints "A dog has been constructed" myDog.setName("Barkley"); myDog.setWeight(10); myDog.print(); // prints "Dog is Barkley and weighs 10 kg" return 0; } // prints "Goodbye Barkley" // Inheritance: // This class inherits everything public and protected from the Dog class // as well as private but may not directly access private members/methods // without a public or protected method for doing so class OwnedDog : public Dog { public: void setOwner(const std::string& dogsOwner); // Override the behavior of the print function for all OwnedDogs. See // https://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping // for a more general introduction if you are unfamiliar with // subtype polymorphism. // The override keyword is optional but makes sure you are actually // overriding the method in a base class. void print() const override; private: std::string owner; }; // Meanwhile, in the corresponding .cpp file: void OwnedDog::setOwner(const std::string& dogsOwner) { owner = dogsOwner; } void OwnedDog::print() const { Dog::print(); // Call the print function in the base Dog class std::cout << "Dog is owned by " << owner << '\n'; // Prints "Dog is and weights " // "Dog is owned by " } ////////////////////////////////////////// // Initialization and Operator Overloading ////////////////////////////////////////// // In C++ you can overload the behavior of operators such as +, -, *, /, etc. // This is done by defining a function which is called // whenever the operator is used. #include using namespace std; class Point { public: // Member variables can be given default values in this manner. double x = 0; double y = 0; // Define a default constructor which does nothing // but initialize the Point to the default value (0, 0) Point() { }; // The following syntax is known as an initialization list // and is the proper way to initialize class member values Point (double a, double b) : x(a), y(b) { /* Do nothing except initialize the values */ } // Overload the + operator. Point operator+(const Point& rhs) const; // Overload the += operator Point& operator+=(const Point& rhs); // It would also make sense to add the - and -= operators, // but we will skip those for brevity. }; Point Point::operator+(const Point& rhs) const { // Create a new point that is the sum of this one and rhs. return Point(x + rhs.x, y + rhs.y); } // It's good practice to return a reference to the leftmost variable of // an assignment. `(a += b) == c` will work this way. Point& Point::operator+=(const Point& rhs) { x += rhs.x; y += rhs.y; // `this` is a pointer to the object, on which a method is called. return *this; } int main () { Point up (0,1); Point right (1,0); // This calls the Point + operator // Point up calls the + (function) with right as its parameter Point result = up + right; // Prints "Result is upright (1,1)" std::cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; return 0; } ///////////////////// // Templates ///////////////////// // Templates in C++ are mostly used for generic programming, though they are // much more powerful than generic constructs in other languages. They also // support explicit and partial specialization and functional-style type // classes; in fact, they are a Turing-complete functional language embedded // in C++! // We start with the kind of generic programming you might be familiar with. To // define a class or function that takes a type parameter: template class Box { public: // In this class, T can be used as any other type. void insert(const T&) { ... } }; // During compilation, the compiler actually generates copies of each template // with parameters substituted, so the full definition of the class must be // present at each invocation. This is why you will see template classes defined // entirely in header files. // To instantiate a template class on the stack: Box intBox; // and you can use it as you would expect: intBox.insert(123); // You can, of course, nest templates: Box > boxOfBox; boxOfBox.insert(intBox); // Until C++11, you had to place a space between the two '>'s, otherwise '>>' // would be parsed as the right shift operator. // You will sometimes see // template // instead. The 'class' keyword and 'typename' keywords are _mostly_ // interchangeable in this case. For the full explanation, see // https://en.wikipedia.org/wiki/Typename // (yes, that keyword has its own Wikipedia page). // Similarly, a template function: template void barkThreeTimes(const T& input) { input.bark(); input.bark(); input.bark(); } // Notice that nothing is specified about the type parameters here. The compiler // will generate and then type-check every invocation of the template, so the // above function works with any type 'T' that has a const 'bark' method! Dog fluffy; fluffy.setName("Fluffy") barkThreeTimes(fluffy); // Prints "Fluffy barks" three times. // Template parameters don't have to be classes: template void printMessage() { std::cout << "Learn C++ in " << Y << " minutes!\n"; } // And you can explicitly specialize templates for more efficient code. Of // course, most real-world uses of specialization are not as trivial as this. // Note that you still need to declare the function (or class) as a template // even if you explicitly specified all parameters. template<> void printMessage<10>() { std::cout << "Learn C++ faster in only 10 minutes!\n"; } printMessage<20>(); // Prints "Learn C++ in 20 minutes!" printMessage<10>(); // Prints "Learn C++ faster in only 10 minutes!" ///////////////////// // Exception Handling ///////////////////// // The standard library provides a few exception types // (see https://en.cppreference.com/w/cpp/error/exception) // but any type can be thrown as an exception #include #include // All exceptions thrown inside the _try_ block can be caught by subsequent // _catch_ handlers. try { // Do not allocate exceptions on the heap using _new_. throw std::runtime_error("A problem occurred"); } // Catch exceptions by const reference if they are objects catch (const std::exception& ex) { std::cout << ex.what(); } // Catches any exception not caught by previous _catch_ blocks catch (...) { std::cout << "Unknown exception caught"; throw; // Re-throws the exception } /////// // RAII /////// // RAII stands for "Resource Acquisition Is Initialization". // It is often considered the most powerful paradigm in C++ // and is the simple concept that a constructor for an object // acquires that object's resources and the destructor releases them. // To understand how this is useful, // consider a function that uses a C file handle: void doSomethingWithAFile(const char* filename) { // To begin with, assume nothing can fail. FILE* fh = fopen(filename, "r"); // Open the file in read mode. if (fh == NULL) { // Handle possible error } doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); fclose(fh); // Close the file handle. } // Unfortunately, things are quickly complicated by error handling. // Suppose fopen can fail, and that doSomethingWithTheFile and // doSomethingElseWithIt return error codes if they fail. // (Exceptions are the preferred way of handling failure, // but some programmers, especially those with a C background, // disagree on the utility of exceptions). // We now have to check each call for failure and close the file handle // if a problem occurred. bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Open the file in read mode if (fh == nullptr) // The returned pointer is null on failure. return false; // Report that failure to the caller. // Assume each function returns false if it failed if (!doSomethingWithTheFile(fh)) { fclose(fh); // Close the file handle so it doesn't leak. return false; // Propagate the error. } if (!doSomethingElseWithIt(fh)) { fclose(fh); // Close the file handle so it doesn't leak. return false; // Propagate the error. } fclose(fh); // Close the file handle so it doesn't leak. return true; // Indicate success } // C programmers often clean this up a little bit using goto: bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); if (fh == nullptr) return false; if (!doSomethingWithTheFile(fh)) goto failure; if (!doSomethingElseWithIt(fh)) goto failure; fclose(fh); // Close the file return true; // Indicate success failure: fclose(fh); return false; // Propagate the error } // If the functions indicate errors using exceptions, // things are a little cleaner, but still sub-optimal. void doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Open the file in read mode if (fh == nullptr) throw std::runtime_error("Could not open the file."); try { doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } catch (...) { fclose(fh); // Be sure to close the file if an error occurs. throw; // Then re-throw the exception. } fclose(fh); // Close the file // Everything succeeded } // Compare this to the use of C++'s file stream class (fstream) // fstream uses its destructor to close the file. // Recall from above that destructors are automatically called // whenever an object falls out of scope. void doSomethingWithAFile(const std::string& filename) { // ifstream is short for input file stream std::ifstream fh(filename); // Open the file // Do things with the file doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } // The file is automatically closed here by the destructor // This has _massive_ advantages: // 1. No matter what happens, // the resource (in this case the file handle) will be cleaned up. // Once you write the destructor correctly, // It is _impossible_ to forget to close the handle and leak the resource. // 2. Note that the code is much cleaner. // The destructor handles closing the file behind the scenes // without you having to worry about it. // 3. The code is exception safe. // An exception can be thrown anywhere in the function and cleanup // will still occur. // All idiomatic C++ code uses RAII extensively for all resources. // Additional examples include // - Memory using unique_ptr and shared_ptr // - Containers - the standard library linked list, // vector (i.e. self-resizing array), hash maps, and so on // all automatically destroy their contents when they fall out of scope. // - Mutexes using lock_guard and unique_lock ///////////////////// // Smart Pointer ///////////////////// // Generally a smart pointer is a class which wraps a "raw pointer" (usage of "new" // respectively malloc/calloc in C). The goal is to be able to // manage the lifetime of the object being pointed to without ever needing to explicitly delete // the object. The term itself simply describes a set of pointers with the // mentioned abstraction. // Smart pointers should be preferred over raw pointers, to prevent // risky memory leaks, which happen if you forget to delete an object. // Usage of a raw pointer: Dog* ptr = new Dog(); ptr->bark(); delete ptr; // By using a smart pointer, you don't have to worry about the deletion // of the object anymore. // A smart pointer describes a policy, to count the references to the // pointer. The object gets destroyed when the last // reference to the object gets destroyed. // Usage of "std::shared_ptr": void foo() { // It's no longer necessary to delete the Dog. std::shared_ptr doggo(new Dog()); doggo->bark(); } // Beware of possible circular references!!! // There will be always a reference, so it will be never destroyed! std::shared_ptr doggo_one(new Dog()); std::shared_ptr doggo_two(new Dog()); doggo_one = doggo_two; // p1 references p2 doggo_two = doggo_one; // p2 references p1 // There are several kinds of smart pointers. // The way you have to use them is always the same. // This leads us to the question: when should we use each kind of smart pointer? // std::unique_ptr - use it when you just want to hold one reference to // the object. // std::shared_ptr - use it when you want to hold multiple references to the // same object and want to make sure that it's deallocated // when all references are gone. // std::weak_ptr - use it when you want to access // the underlying object of a std::shared_ptr without causing that object to stay allocated. // Weak pointers are used to prevent circular referencing. ///////////////////// // Containers ///////////////////// // Containers or the Standard Template Library are some predefined templates. // They manage the storage space for its elements and provide // member functions to access and manipulate them. // Few containers are as follows: // Vector (Dynamic array) // Allow us to Define the Array or list of objects at run time #include std::string val; std::vector my_vector; // initialize the vector std::cin >> val; my_vector.push_back(val); // will push the value of 'val' into vector ("array") my_vector my_vector.push_back(val); // will push the value into the vector again (now having two elements) // To iterate through a vector we have 2 choices: // Either classic looping (iterating through the vector from index 0 to its last index): for (int i = 0; i < my_vector.size(); i++) { std::cout << my_vector[i] << '\n'; // for accessing a vector's element we can use the operator [] } // or using an iterator: vector::iterator it; // initialize the iterator for vector for (it = my_vector.begin(); it != my_vector.end(); ++it) { std::cout << *it << '\n'; } // Set // Sets are containers that store unique elements following a specific order. // Set is a very useful container to store unique values in sorted order // without any other functions or code. #include std::set ST; // Will initialize the set of int data type ST.insert(30); // Will insert the value 30 in set ST ST.insert(10); // Will insert the value 10 in set ST ST.insert(20); // Will insert the value 20 in set ST ST.insert(30); // Will insert the value 30 in set ST // Now elements of sets are as follows // 10 20 30 // To erase an element ST.erase(20); // Will erase element with value 20 // Set ST: 10 30 // To iterate through Set we use iterators std::set::iterator it; for (it = ST.begin(); it != ST.end(); it++) { std::cout << *it << '\n'; } // Output: // 10 // 30 // To clear the complete container we use Container_name.clear() ST.clear(); std::cout << ST.size(); // will print the size of set ST // Output: 0 // NOTE: for duplicate elements we can use multiset // NOTE: For hash sets, use unordered_set. They are more efficient but // do not preserve order. unordered_set is available since C++11 // Map // Maps store elements formed by a combination of a key value // and a mapped value, following a specific order. #include std::map mymap; // Will initialize the map with key as char and value as int mymap.insert(pair('A',1)); // Will insert value 1 for key A mymap.insert(pair('Z',26)); // Will insert value 26 for key Z // To iterate std::map::iterator it; for (it = mymap.begin(); it != mymap.end(); ++it) std::cout << it->first << "->" << it->second << '\n'; // Output: // A->1 // Z->26 // To find the value corresponding to a key it = mymap.find('Z'); std::cout << it->second; // Output: 26 // NOTE: For hash maps, use unordered_map. They are more efficient but do // not preserve order. unordered_map is available since C++11. // Containers with object keys of non-primitive values (custom classes) require // compare function in the object itself or as a function pointer. Primitives // have default comparators, but you can override it. class Foo { public: int j; Foo(int a) : j(a) {} }; struct compareFunction { bool operator()(const Foo& a, const Foo& b) const { return a.j < b.j; } }; // this isn't allowed (although it can vary depending on compiler) // std::map fooMap; std::map fooMap; fooMap[Foo(1)] = 1; fooMap.find(Foo(1)); //true /////////////////////////////////////// // Lambda Expressions (C++11 and above) /////////////////////////////////////// // lambdas are a convenient way of defining an anonymous function // object right at the location where it is invoked or passed as // an argument to a function. // For example, consider sorting a vector of pairs using the second // value of the pair std::vector > tester; tester.push_back(make_pair(3, 6)); tester.push_back(make_pair(1, 9)); tester.push_back(make_pair(5, 0)); // Pass a lambda expression as third argument to the sort function // sort is from the header std::sort(tester.begin(), tester.end(), [](const pair& lhs, const pair& rhs) { return lhs.second < rhs.second; }); // Notice the syntax of the lambda expression, // [] in the lambda is used to "capture" variables // The "Capture List" defines what from the outside of the lambda should be available inside the function body and how. // It can be either: // 1. a value : [x] // 2. a reference : [&x] // 3. any variable currently in scope by reference [&] // 4. same as 3, but by value [=] // Example: std::vector dog_ids; // number_of_dogs = 3; for (int i = 0; i < 3; i++) { dog_ids.push_back(i); } int weight[3] = {30, 50, 10}; // Say you want to sort dog_ids according to the dogs' weights // So dog_ids should in the end become: [2, 0, 1] // Here's where lambda expressions come in handy sort(dog_ids.begin(), dog_ids.end(), [&weight](const int &lhs, const int &rhs) { return weight[lhs] < weight[rhs]; }); // Note we captured "weight" by reference in the above example. // More on Lambdas in C++ : https://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11 /////////////////////////////// // Range For (C++11 and above) /////////////////////////////// // You can use a range for loop to iterate over a container int arr[] = {1, 10, 3}; for (int elem: arr) { cout << elem << endl; } // You can use "auto" and not worry about the type of the elements of the container // For example: for (auto elem: arr) { // Do something with each element of arr } ///////////////////// // Fun stuff ///////////////////// // Aspects of C++ that may be surprising to newcomers (and even some veterans). // This section is, unfortunately, wildly incomplete; C++ is one of the easiest // languages with which to shoot yourself in the foot. // You can override private methods! class Foo { virtual void bar(); }; class FooSub : public Foo { virtual void bar(); // Overrides Foo::bar! }; // 0 == false == NULL (most of the time)! bool* pt = new bool; *pt = 0; // Sets the value points by 'pt' to false. pt = 0; // Sets 'pt' to the null pointer. Both lines compile without warnings. // nullptr is supposed to fix some of that issue: int* pt2 = new int; *pt2 = nullptr; // Doesn't compile pt2 = nullptr; // Sets pt2 to null. // There is an exception made for bools. // This is to allow you to test for null pointers with if(!ptr), // but as a consequence you can assign nullptr to a bool directly! *pt = nullptr; // This still compiles, even though '*pt' is a bool! // '=' != '=' != '='! // Calls Foo::Foo(const Foo&) or some variant (see move semantics) copy // constructor. Foo f2; Foo f1 = f2; // Calls Foo::Foo(const Foo&) or variant, but only copies the 'Foo' part of // 'fooSub'. Any extra members of 'fooSub' are discarded. This sometimes // horrifying behavior is called "object slicing." FooSub fooSub; Foo f1 = fooSub; // Calls Foo::operator=(Foo&) or variant. Foo f1; f1 = f2; /////////////////////////////////////// // Tuples (C++11 and above) /////////////////////////////////////// #include // Conceptually, Tuples are similar to old data structures (C-like structs) // but instead of having named data members, // its elements are accessed by their order in the tuple. // We start with constructing a tuple. // Packing values into tuple auto first = make_tuple(10, 'A'); const int maxN = 1e9; const int maxL = 15; auto second = make_tuple(maxN, maxL); // Printing elements of 'first' tuple std::cout << get<0>(first) << " " << get<1>(first) << '\n'; //prints : 10 A // Printing elements of 'second' tuple std::cout << get<0>(second) << " " << get<1>(second) << '\n'; // prints: 1000000000 15 // Unpacking tuple into variables int first_int; char first_char; tie(first_int, first_char) = first; std::cout << first_int << " " << first_char << '\n'; // prints : 10 A // We can also create tuple like this. tuple third(11, 'A', 3.14141); // tuple_size returns number of elements in a tuple (as a constexpr) std::cout << tuple_size::value << '\n'; // prints: 3 // tuple_cat concatenates the elements of all the tuples in the same order. auto concatenated_tuple = tuple_cat(first, second, third); // concatenated_tuple becomes = (10, 'A', 1e9, 15, 11, 'A', 3.14141) std::cout << get<0>(concatenated_tuple) << '\n'; // prints: 10 std::cout << get<3>(concatenated_tuple) << '\n'; // prints: 15 std::cout << get<5>(concatenated_tuple) << '\n'; // prints: 'A' /////////////////////////////////// // Logical and Bitwise operators ////////////////////////////////// // Most of the operators in C++ are same as in other languages // Logical operators // C++ uses Short-circuit evaluation for boolean expressions, i.e, the second argument is executed or // evaluated only if the first argument does not suffice to determine the value of the expression true && false // Performs **logical and** to yield false true || false // Performs **logical or** to yield true ! true // Performs **logical not** to yield false // Instead of using symbols equivalent keywords can be used true and false // Performs **logical and** to yield false true or false // Performs **logical or** to yield true not true // Performs **logical not** to yield false // Bitwise operators // **<<** Left Shift Operator // << shifts bits to the left 4 << 1 // Shifts bits of 4 to left by 1 to give 8 // x << n can be thought as x * 2^n // **>>** Right Shift Operator // >> shifts bits to the right 4 >> 1 // Shifts bits of 4 to right by 1 to give 2 // x >> n can be thought as x / 2^n ~4 // Performs a bitwise not 4 | 3 // Performs bitwise or 4 & 3 // Performs bitwise and 4 ^ 3 // Performs bitwise xor // Equivalent keywords are compl 4 // Performs a bitwise not 4 bitor 3 // Performs bitwise or 4 bitand 3 // Performs bitwise and 4 xor 3 // Performs bitwise xor ``` ## Further Reading: - An up-to-date language reference can be found at [CPP Reference](http://cppreference.com/w/cpp). - A tutorial for beginners or experts, covering many modern features and good practices: [LearnCpp.com](https://www.learncpp.com/) - A tutorial covering basics of language and setting up coding environment is available at [TheChernoProject - C++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb). - Additional resources may be found at [CPlusPlus](http://cplusplus.com). ================================================ FILE: c.md ================================================ --- name: C filename: learnc.c contributors: - ["Adam Bard", "http://adambard.com/"] - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"] - ["Jakub Trzebiatowski", "http://cbs.stgn.pl"] - ["Marco Scannadinari", "https://marcoms.github.io"] - ["Zachary Ferguson", "https://github.io/zfergus2"] - ["himanshu", "https://github.com/himanshu81494"] - ["Joshua Li", "https://github.com/JoshuaRLi"] - ["Dragos B. Chirila", "https://github.com/dchirila"] - ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"] --- Ah, C. Still **the** language of modern high-performance computing. C is the lowest-level language most programmers will ever use, but it more than makes up for it with raw speed. Just be aware of its manual memory management and C will take you as far as you need to go. ```c // Single-line comments start with // - only available in C99 and later. /* Multi-line comments look like this. They work in C89 as well. */ /* Multi-line comments don't nest /* Be careful */ // comment ends on this line... */ // ...not this one! // Constants: #define // Constants are written in all-caps out of convention, not requirement #define DAYS_IN_YEAR 365 // Enumeration constants are also ways to declare constants. // All statements must end with a semicolon enum days {SUN, MON, TUE, WED, THU, FRI, SAT}; // SUN gets 0, MON gets 1, TUE gets 2, etc. // Enumeration values can also be specified enum days {SUN = 1, MON, TUE, WED = 99, THU, FRI, SAT}; // MON gets 2 automatically, TUE gets 3, etc. // WED gets 99, THU gets 100, FRI gets 101, etc. // Import headers with #include #include #include #include // File names between tell the compiler to look in your system // libraries for the headers. // For your own headers, use double quotes instead of angle brackets, and // provide the path: #include "my_header.h" // local file #include "../my_lib/my_lib_header.h" // relative path // Declare function signatures in advance in a .h file, or at the top of // your .c file. void function_1(); int function_2(void); // At a minimum, you must declare a 'function prototype' before its use in any function. // Normally, prototypes are placed at the top of a file before any function definition. int add_two_ints(int x1, int x2); // function prototype // although `int add_two_ints(int, int);` is also valid (no need to name the args), // it is recommended to name arguments in the prototype as well for easier inspection // Function prototypes are not necessary if the function definition comes before // any other function that calls that function. However, it's standard practice to // always add the function prototype to a header file (*.h) and then #include that // file at the top. This prevents any issues where a function might be called // before the compiler knows of its existence, while also giving the developer a // clean header file to share with the rest of the project. // Your program's entry point is a function called "main". The return type can // be anything, however most operating systems expect a return type of `int` for // error code processing. int main(void) { // your program } // The command line arguments used to run your program are also passed to main // argc being the number of arguments - your program's name counts as 1 // argv is an array of character arrays - containing the arguments themselves // argv[0] = name of your program, argv[1] = first argument, etc. int main (int argc, char** argv) { // print output using printf, for "print formatted" // %d is an integer, \n is a newline printf("%d\n", 0); // => Prints 0 // take input using scanf // '&' is used to define the location // where we want to store the input value int input; scanf("%d", &input); /////////////////////////////////////// // Types /////////////////////////////////////// // Compilers that are not C99-compliant require that variables MUST be // declared at the top of the current block scope. // Compilers that ARE C99-compliant allow declarations near the point where // the value is used. // For the sake of the tutorial, variables are declared dynamically under // C99-compliant standards. // ints are usually 4 bytes (use the `sizeof` operator to check) int x_int = 0; // shorts are usually 2 bytes (use the `sizeof` operator to check) short x_short = 0; // chars are defined as the smallest addressable unit for a processor. // This is usually 1 byte, but for some systems it can be more (ex. for TMS320 from TI it's 2 bytes). char x_char = 0; char y_char = 'y'; // Char literals are quoted with '' // longs are often 4 to 8 bytes; long longs are guaranteed to be at least // 8 bytes long x_long = 0; long long x_long_long = 0; // floats are usually 32-bit floating point numbers float x_float = 0.0f; // 'f' suffix here denotes floating point literal // doubles are usually 64-bit floating-point numbers double x_double = 0.0; // real numbers without any suffix are doubles // integer types may be unsigned (greater than or equal to zero) unsigned short ux_short; unsigned int ux_int; unsigned long long ux_long_long; // chars inside single quotes are integers in machine's character set. '0'; // => 48 in the ASCII character set. 'A'; // => 65 in the ASCII character set. // sizeof(T) gives you the size of a variable with type T in bytes // sizeof(obj) yields the size of the expression (variable, literal, etc.). printf("%zu\n", sizeof(int)); // => 4 (on most machines with 4-byte words) // If the argument of the `sizeof` operator is an expression, then its argument // is not evaluated (except VLAs (see below)). // The value it yields in this case is a compile-time constant. int a = 1; // size_t is an unsigned integer type of at least 2 bytes used to represent // the size of an object. size_t size = sizeof(a++); // a++ is not evaluated printf("sizeof(a++) = %zu where a = %d\n", size, a); // prints "sizeof(a++) = 4 where a = 1" (on a 32-bit architecture) // Arrays must be initialized with a concrete size. char my_char_array[20]; // This array occupies 1 * 20 = 20 bytes int my_int_array[20]; // This array occupies 4 * 20 = 80 bytes // (assuming 4-byte words) // You can initialize an array of twenty ints that all equal 0 thusly: int my_array[20] = {0}; // where the "{0}" part is called an "array initializer". // All elements (if any) past the ones in the initializer are initialized to 0: int my_array[5] = {1, 2}; // So my_array now has five elements, all but the first two of which are 0: // [1, 2, 0, 0, 0] // NOTE that you get away without explicitly declaring the size // of the array IF you initialize the array on the same line: int my_array[] = {0}; // NOTE that, when not declaring the size, the size of the array is the number // of elements in the initializer. With "{0}", my_array is now of size one: [0] // To evaluate the size of the array at run-time, divide its byte size by the // byte size of its element type: size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]); // WARNING You should evaluate the size *before* you begin passing the array // to functions (see later discussion) because arrays get "downgraded" to // raw pointers when they are passed to functions (so the statement above // will produce the wrong result inside the function). // Indexing an array is like other languages -- or, // rather, other languages are like C my_array[0]; // => 0 // Arrays are mutable; it's just memory! my_array[1] = 2; printf("%d\n", my_array[1]); // => 2 // In C99 (and as an optional feature in C11), variable-length arrays (VLAs) // can be declared as well. The size of such an array need not be a compile // time constant: printf("Enter the array size: "); // ask the user for an array size int array_size; fscanf(stdin, "%d", &array_size); int var_length_array[array_size]; // declare the VLA printf("sizeof array = %zu\n", sizeof var_length_array); // Example: // > Enter the array size: 10 // > sizeof array = 40 // Strings are just arrays of chars terminated by a NULL (0x00) byte, // represented in strings as the special character '\0'. // (We don't have to include the NULL byte in string literals; the compiler // inserts it at the end of the array for us.) char a_string[20] = "This is a string"; printf("%s\n", a_string); // %s formats a string printf("%d\n", a_string[16]); // => 0 // i.e., byte #17 is 0 (as are 18, 19, and 20) // If we have characters between single quotes, that's a character literal. // It's of type `int`, and *not* `char` (for historical reasons). int cha = 'a'; // fine char chb = 'a'; // fine too (implicit conversion from int to char) // Multi-dimensional arrays: int multi_array[2][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 0} }; // access elements: int array_int = multi_array[0][2]; // => 3 /////////////////////////////////////// // Operators /////////////////////////////////////// // Shorthands for multiple declarations: int i1 = 1, i2 = 2; float f1 = 1.0, f2 = 2.0; int b, c; b = c = 0; // Arithmetic is straightforward i1 + i2; // => 3 i2 - i1; // => 1 i2 * i1; // => 2 i1 / i2; // => 0 (0.5, but truncated towards 0) // You need to cast at least one integer to float to get a floating-point result (float)i1 / i2; // => 0.5f i1 / (double)i2; // => 0.5 // Same with double f1 / f2; // => 0.5, plus or minus epsilon // Floating-point numbers are defined by IEEE 754, thus cannot store perfectly // exact values. For instance, the following does not produce expected results // because 0.1 might actually be 0.099999999999 inside the computer, and 0.3 // might be stored as 0.300000000001. (0.1 + 0.1 + 0.1) != 0.3; // => 1 (true) // and it is NOT associative due to reasons mentioned above. 1 + (1e123 - 1e123) != (1 + 1e123) - 1e123; // => 1 (true) // this notation is scientific notations for numbers: 1e123 = 1*10^123 // It is important to note that most all systems have used IEEE 754 to // represent floating points. Even python, used for scientific computing, // eventually calls C which uses IEEE 754. It is mentioned this way not to // indicate that this is a poor implementation, but instead as a warning // that when doing floating point comparisons, a little bit of error (epsilon) // needs to be considered. // Modulo is there as well, but be careful if arguments are negative 11 % 3; // => 2 as 11 = 2 + 3*x (x=3) (-11) % 3; // => -2, as one would expect 11 % (-3); // => 2 and not -2, and it's quite counter intuitive // Comparison operators are probably familiar, but // there is no Boolean type in C. We use ints instead. // (C99 introduced the _Bool type provided in stdbool.h) // 0 is false, anything else is true. (The comparison // operators always yield 0 or 1.) 3 == 2; // => 0 (false) 3 != 2; // => 1 (true) 3 > 2; // => 1 3 < 2; // => 0 2 <= 2; // => 1 2 >= 2; // => 1 // C is not Python - comparisons do NOT chain. // Warning: The line below will compile, but it means `(0 < a) < 2`. // This expression is always true, because (0 < a) could be either 1 or 0. // In this case it's 1, because (0 < 1). int between_0_and_2 = 0 < a < 2; // Instead use: int between_0_and_2 = 0 < a && a < 2; // Logic works on ints !3; // => 0 (Logical not) !0; // => 1 1 && 1; // => 1 (Logical and) 0 && 1; // => 0 0 || 1; // => 1 (Logical or) 0 || 0; // => 0 // Conditional ternary expression ( ? : ) int e = 5; int f = 10; int z; z = (e > f) ? e : f; // => 10 "if e > f return e, else return f." // Increment and decrement operators: int j = 0; int s = j++; // Return j THEN increase j. (s = 0, j = 1) s = ++j; // Increase j THEN return j. (s = 2, j = 2) // same with j-- and --j // Bitwise operators! ~0x0F; // => 0xFFFFFFF0 (bitwise negation, "1's complement", example result for 32-bit int) 0x0F & 0xF0; // => 0x00 (bitwise AND) 0x0F | 0xF0; // => 0xFF (bitwise OR) 0x04 ^ 0x0F; // => 0x0B (bitwise XOR) 0x01 << 1; // => 0x02 (bitwise left shift (by 1)) 0x02 >> 1; // => 0x01 (bitwise right shift (by 1)) // Be careful when shifting signed integers - the following are undefined: // - shifting into the sign bit of a signed integer (int a = 1 << 31) // - left-shifting a negative number (int a = -1 << 2) // - shifting by an offset which is >= the width of the type of the LHS: // int a = 1 << 32; // UB if int is 32 bits wide /////////////////////////////////////// // Control Structures /////////////////////////////////////// if (0) { printf("I am never run\n"); } else if (0) { printf("I am also never run\n"); } else { printf("I print\n"); } // While loops exist int ii = 0; while (ii < 10) { // ANY value less than ten is true. printf("%d, ", ii++); // ii++ increments ii AFTER using its current value. } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); int kk = 0; do { printf("%d, ", kk); } while (++kk < 10); // ++kk increments kk BEFORE using its current value. // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // For loops too int jj; for (jj=0; jj < 10; jj++) { printf("%d, ", jj); } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // *****NOTES*****: // Loops and Functions MUST have a body. If no body is needed: int i; for (i = 0; i <= 5; i++) { ; // use semicolon to act as the body (null statement) } // Or for (i = 0; i <= 5; i++); // branching with multiple choices: switch() switch (a) { case 0: // labels need to be integral *constant* expressions (such as enums) printf("Hey, 'a' equals 0!\n"); break; // if you don't break, control flow falls over labels case 1: printf("Huh, 'a' equals 1!\n"); break; // Be careful - without a "break", execution continues until the // next "break" is reached. case 3: case 4: printf("Look at that.. 'a' is either 3, or 4\n"); break; default: // if `some_integral_expression` didn't match any of the labels fputs("Error!\n", stderr); exit(-1); break; } /* Using "goto" in C */ int i, j; for(i=0; i<100; ++i) for(j=0; j<100; ++j) { if((i + j) >= 150) { goto error; // exit both for loops immediately } } printf("No error found. Completed normally.\n"); goto end; error: // this is a label that you can "jump" to with "goto error;" printf("Error occurred at i = %d & j = %d.\n", i, j); end: return 0; /* https://ideone.com/z7nzKJ this will print out "Error occurred at i = 51 & j = 99." */ /* it is generally considered bad practice to do so, except if you really know what you are doing. See https://en.wikipedia.org/wiki/Spaghetti_code#Meaning */ /////////////////////////////////////// // Typecasting /////////////////////////////////////// // Every value in C has a type, but you can cast one value into another type // if you want (with some constraints). int x_hex = 0x01; // You can assign vars with hex literals // binary is not in the standard, but allowed by some // compilers (x_bin = 0b0010010110) // Casting between types will attempt to preserve their numeric values printf("%d\n", x_hex); // => Prints 1 printf("%d\n", (short) x_hex); // => Prints 1 printf("%d\n", (char) x_hex); // => Prints 1 // If you assign a value greater than a types max val, it will rollover // without warning. printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long) // For determining the max value of a `char`, a `signed char` and an `unsigned char`, // respectively, use the CHAR_MAX, SCHAR_MAX and UCHAR_MAX macros from // Integral types can be cast to floating-point types, and vice-versa. printf("%f\n", (double) 100); // %f always formats a double... printf("%f\n", (float) 100); // ...even with a float. printf("%d\n", (char)100.0); /////////////////////////////////////// // Pointers /////////////////////////////////////// // A pointer is a variable declared to store a memory address. Its declaration will // also tell you the type of data it points to. You can retrieve the memory address // of your variables, then mess with them. int x = 0; printf("%p\n", (void *)&x); // Use & to retrieve the address of a variable // (%p formats an object pointer of type void *) // => Prints some address in memory; // Pointers start with * in their declaration int *px, not_a_pointer; // px is a pointer to an int px = &x; // Stores the address of x in px printf("%p\n", (void *)px); // => Prints some address in memory printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); // => Prints "8, 4" on a typical 64-bit system // To retrieve the value at the address a pointer is pointing to, // put * in front to dereference it. // Note: yes, it may be confusing that '*' is used for _both_ declaring a // pointer and dereferencing it. printf("%d\n", *px); // => Prints 0, the value of x // You can also change the value the pointer is pointing to. // We'll have to wrap the dereference in parenthesis because // ++ has a higher precedence than *. (*px)++; // Increment the value px is pointing to by 1 printf("%d\n", *px); // => Prints 1 printf("%d\n", x); // => Prints 1 // Arrays are a good way to allocate a contiguous block of memory int x_array[20]; // declares array of size 20 (cannot change size) int xx; for (xx = 0; xx < 20; xx++) { x_array[xx] = 20 - xx; } // Initialize x_array to 20, 19, 18,... 2, 1 // Declare a pointer of type int and initialize it to point to x_array int* x_ptr = x_array; // x_ptr now points to the first element in the array (the integer 20). // This works because arrays often decay into pointers to their first element. // For example, when an array is passed to a function or is assigned to a pointer, // it decays into (implicitly converted to) a pointer. // Exceptions: when the array is the argument of the `&` (address-of) operator: int arr[10]; int (*ptr_to_arr)[10] = &arr; // &arr is NOT of type `int *`! // It's of type "pointer to array" (of ten `int`s). // or when the array is a string literal used for initializing a char array: char otherarr[] = "foobarbazquirk"; // or when it's the argument of the `sizeof` or `alignof` operator: int arraythethird[10]; int *ptr = arraythethird; // equivalent with int *ptr = &arr[0]; printf("%zu, %zu\n", sizeof(arraythethird), sizeof(ptr)); // probably prints "40, 4" or "40, 8" // Pointers are incremented and decremented based on their type // (this is called pointer arithmetic) printf("%d\n", *(x_ptr + 1)); // => Prints 19 printf("%d\n", x_array[1]); // => Prints 19 // You can also dynamically allocate contiguous blocks of memory with the // standard library function malloc, which takes one argument of type size_t // representing the number of bytes to allocate (usually from the heap, although this // may not be true on e.g. embedded systems - the C standard says nothing about it). int *my_ptr = malloc(sizeof(*my_ptr) * 20); for (xx = 0; xx < 20; xx++) { *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx } // Initialize memory to 20, 19, 18, 17... 2, 1 (as ints) // Be careful passing user-provided values to malloc! If you want // to be safe, you can use calloc instead (which, unlike malloc, also zeros out the memory) int* my_other_ptr = calloc(20, sizeof(int)); // Note that there is no standard way to get the length of a // dynamically allocated array in C. Because of this, if your arrays are // going to be passed around your program a lot, you need another variable // to keep track of the number of elements (size) of an array. See the // functions section for more info. size_t size = 10; int *my_arr = calloc(size, sizeof(int)); // Add an element to the array size++; my_arr = realloc(my_arr, sizeof(int) * size); if (my_arr == NULL) { // Remember to check for realloc failure! return } my_arr[10] = 5; // Dereferencing memory that you haven't allocated gives // "unpredictable results" - the program is said to invoke "undefined behavior" printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what? It may even crash. // When you're done with a malloc'd block of memory, you need to free it, // or else no one else can use it until your program terminates // (this is called a "memory leak"): free(my_ptr); // Strings are arrays of char, but they are usually represented as a // pointer-to-char (which is a pointer to the first element of the array). // It's good practice to use `const char *' when referring to a string literal, // since string literals shall not be modified (i.e. "foo"[0] = 'a' is ILLEGAL.) const char *my_str = "This is my very own string literal"; printf("%c\n", *my_str); // => 'T' // This is not the case if the string is an array // (potentially initialized with a string literal) // that resides in writable memory, as in: char foo[] = "foo"; foo[0] = 'a'; // this is legal, foo now contains "aoo" function_1(); } // end main function /////////////////////////////////////// // Functions /////////////////////////////////////// // Function declaration syntax: // () int add_two_ints(int x1, int x2) { return x1 + x2; // Use return to return a value } /* Functions are call by value. When a function is called, the arguments passed to the function are copies of the original arguments (except arrays). Anything you do to the arguments in the function does not change the value of the original argument where the function was called. Use pointers if you need to edit the original argument values (arrays are always passed in as pointers). Example: in-place string reversal */ // A void function returns no value void str_reverse(char *str_in) { char tmp; size_t ii = 0; size_t len = strlen(str_in); // `strlen()` is part of the c standard library // NOTE: length returned by `strlen` DOESN'T // include the terminating NULL byte ('\0') // in C99 and newer versions, you can directly declare loop control variables // in the loop's parentheses. e.g., `for (size_t ii = 0; ...` for (ii = 0; ii < len / 2; ii++) { tmp = str_in[ii]; str_in[ii] = str_in[len - ii - 1]; // ii-th char from end str_in[len - ii - 1] = tmp; } } // NOTE: string.h header file needs to be included to use strlen() /* char c[] = "This is a test."; str_reverse(c); printf("%s\n", c); // => ".tset a si sihT" */ /* as we can return only one variable to change values of more than one variables we use call by reference */ void swapTwoNumbers(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } /* int first = 10; int second = 20; printf("first: %d\nsecond: %d\n", first, second); swapTwoNumbers(&first, &second); printf("first: %d\nsecond: %d\n", first, second); // values will be swapped */ // Return multiple values. // C does not allow for returning multiple values with the return statement. If // you would like to return multiple values, then the caller must pass in the // variables where they would like the returned values to go. These variables must // be passed in as pointers such that the function can modify them. int return_multiple( int *array_of_3, int *ret1, int *ret2, int *ret3) { if(array_of_3 == NULL) return 0; // return error code (false) // de-reference the pointer so we modify its value *ret1 = array_of_3[0]; *ret2 = array_of_3[1]; *ret3 = array_of_3[2]; return 1; // return error code (true) } /* With regards to arrays, they will always be passed to functions as pointers. Even if you statically allocate an array like `arr[10]`, it still gets passed as a pointer to the first element in any function calls. Again, there is no standard way to get the size of a dynamically allocated array in C. */ // Size must be passed! // Otherwise, this function has no way of knowing how big the array is. void printIntArray(int *arr, size_t size) { int i; for (i = 0; i < size; i++) { printf("arr[%d] is: %d\n", i, arr[i]); } } /* int my_arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int size = 10; printIntArray(my_arr, size); // will print "arr[0] is: 1" etc */ // if referring to external variables outside function, you should use the extern keyword. int i = 0; void testFunc() { extern int i; // i here is now using external variable i } // make external variables private to source file with static: static int j = 0; // other files using testFunc2() cannot access variable j void testFunc2() { extern int j; } // The static keyword makes a variable inaccessible to code outside the // compilation unit. (On almost all systems, a "compilation unit" is a .c // file.) static can apply both to global (to the compilation unit) variables, // functions, and function-local variables. When using static with // function-local variables, the variable is effectively global and retains its // value across function calls, but is only accessible within the function it // is declared in. Additionally, static variables are initialized to 0 if not // declared with some other starting value. // **You may also declare functions as static to make them private** /////////////////////////////////////// // User-defined types and structs /////////////////////////////////////// // Typedefs can be used to create type aliases typedef int my_type; my_type my_type_var = 0; // Structs are just collections of data, the members are allocated sequentially, // in the order they are written: struct rectangle { int width; int height; }; // It's not generally true that // sizeof(struct rectangle) == sizeof(int) + sizeof(int) // due to potential padding between the structure members (this is for alignment // reasons). [1] void function_1() { struct rectangle my_rec = { 1, 2 }; // Fields can be initialized immediately // Access struct members with . my_rec.width = 10; my_rec.height = 20; // You can declare pointers to structs struct rectangle *my_rec_ptr = &my_rec; // Use dereferencing to set struct pointer members... (*my_rec_ptr).width = 30; // ... or even better: prefer the -> shorthand for the sake of readability my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10; } // You can apply a typedef to a struct for convenience typedef struct rectangle rect; int area(rect r) { return r.width * r.height; } // Typedefs can also be defined right during struct definition typedef struct { int width; int height; } rect; // Like before, doing this means one can type rect r; // instead of having to type struct rectangle r; // if you have large structs, you can pass them "by pointer" to avoid copying // the whole struct: int areaptr(const rect *r) { return r->width * r->height; } /////////////////////////////////////// // Function pointers /////////////////////////////////////// /* At run time, functions are located at known memory addresses. Function pointers are much like any other pointer (they just store a memory address), but can be used to invoke functions directly, and to pass handlers (or callback functions) around. However, definition syntax may be initially confusing. Example: use str_reverse from a pointer */ void str_reverse_through_pointer(char *str_in) { // Define a function pointer variable, named f. void (*f)(char *); // Signature should exactly match the target function. f = &str_reverse; // Assign the address for the actual function (determined at run time) // f = str_reverse; would work as well - functions decay into pointers, similar to arrays (*f)(str_in); // Just calling the function through the pointer // f(str_in); // That's an alternative but equally valid syntax for calling it. } /* As long as function signatures match, you can assign any function to the same pointer. Function pointers are usually typedef'd for simplicity and readability, as follows: */ typedef void (*my_fnp_type)(char *); // Then used when declaring the actual pointer variable: // ... // my_fnp_type f; ///////////////////////////// // Printing characters with printf() ///////////////////////////// // Special characters: /* '\a'; // alert (bell) character '\n'; // newline character '\t'; // tab character (left justifies text) '\v'; // vertical tab '\f'; // new page (form feed) '\r'; // carriage return '\b'; // backspace character '\0'; // NULL character. Usually put at end of strings in C. // hello\n\0. \0 used by convention to mark end of string. '\\'; // backslash '\?'; // question mark '\''; // single quote '\"'; // double quote '\xhh'; // hexadecimal number. Example: '\xb' = vertical tab character '\0oo'; // octal number. Example: '\013' = vertical tab character // print formatting: "%d"; // integer "%3d"; // integer with minimum of length 3 digits (right justifies text) "%s"; // string "%f"; // float "%ld"; // long "%3.2f"; // minimum 3 digits left and 2 digits right decimal float "%7.4s"; // (can do with strings too) "%c"; // char "%p"; // pointer. NOTE: need to (void *)-cast the pointer, before passing // it as an argument to `printf`. "%x"; // hexadecimal "%o"; // octal "%%"; // prints % */ /////////////////////////////////////// // Order of Evaluation /////////////////////////////////////// // From top to bottom, top has higher precedence //---------------------------------------------------// // Operators | Associativity // //---------------------------------------------------// // () [] -> . | left to right // // ! ~ ++ -- + - *(type) sizeof | right to left // // * / % | left to right // // + - | left to right // // << >> | left to right // // < <= > >= | left to right // // == != | left to right // // & | left to right // // ^ | left to right // // | | left to right // // && | left to right // // || | left to right // // ?: | right to left // // = += -= *= /= %= &= ^= |= <<= >>= | right to left // // , | left to right // //---------------------------------------------------// /******************************* Header Files ********************************** Header files are an important part of C as they allow for the connection of C source files and can simplify code and definitions by separating them into separate files. Header files are syntactically similar to C source files but reside in ".h" files. They can be included in your C source file by using the preprocessor directive #include "example.h", given that example.h exists in the same directory as the C file. */ /* A safe guard to prevent the header from being defined too many times. This */ /* happens in the case of circle dependency, the contents of the header is */ /* already defined. */ #ifndef EXAMPLE_H /* if EXAMPLE_H is not yet defined. */ #define EXAMPLE_H /* Define the macro EXAMPLE_H. */ /* Other headers can be included in headers and therefore transitively */ /* included into files that include this header. */ #include /* Like for c source files, macros can be defined in headers */ /* and used in files that include this header file. */ #define EXAMPLE_NAME "Dennis Ritchie" /* Function macros can also be defined. */ #define ADD(a, b) ((a) + (b)) /* Notice the parenthesis surrounding the arguments -- this is important to */ /* ensure that a and b don't get expanded in an unexpected way (e.g. consider */ /* MUL(x, y) (x * y); MUL(1 + 2, 3) would expand to (1 + 2 * 3), yielding an */ /* incorrect result) */ /* Structs and typedefs can be used for consistency between files. */ typedef struct Node { int val; struct Node *next; } Node; /* So can enumerations. */ enum traffic_light_state {GREEN, YELLOW, RED}; /* Function prototypes can also be defined here for use in multiple files, */ /* but it is bad practice to define the function in the header. Definitions */ /* should instead be put in a C file. */ Node createLinkedList(int *vals, int len); /* Beyond the above elements, other definitions should be left to a C source */ /* file. Excessive includes or definitions should also not be contained in */ /* a header file but instead put into separate headers or a C file. */ #endif /* End of the if preprocessor directive. */ ``` ## Further Reading Best to find yourself a copy of [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language). It is _the_ book about C, written by Dennis Ritchie, the creator of C, and Brian Kernighan. Be careful, though - it's ancient and it contains some inaccuracies (well, ideas that are not considered good anymore) or now-changed practices. Another good resource is [Learn C The Hard Way](http://learncodethehardway.org/c/) (not free). If you have a question, read the [comp.lang.c Frequently Asked Questions](http://c-faq.com). It's very important to use proper spacing, indentation and to be consistent with your coding style in general. Readable code is better than clever code and fast code. For a good, sane coding style to adopt, see the [Linux kernel coding style](https://www.kernel.org/doc/Documentation/process/coding-style.rst). [1] [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) ================================================ FILE: ca/asciidoc.md ================================================ --- contributors: - ["Ryan Mavilia", "http://unoriginality.rocks/"] translators: - ["Abel Salgado Romero", "https://twitter.com/abelsromero"] --- AsciiDoc és un llenguatge de marques similar a Markdown i que pot ser usat per qualsevol ús, des de llibres fins a blogs. Creat al 2002 per Stuart Rackham, és un llenguatge simple però permet un gran nivell de personalització. Capçalera de document La capçalera és opcional i no pot contenir línies buides. Ha d'estar separada del contingut per com a mínim una línia en blanc. Només títol ``` = Títol del document Primer contingut del document. ``` Títol i autor ``` = Títol del document Nom Cognom(s) Inici d'aquest document. ``` Múltiples autors ``` = Títol del document John Doe ; Jane Doe; Black Beard Inici d'un document amb múltiples autors. ``` Línia de versió (requereix línia d'autor) ``` = Títol del document V1 Potato Man v1.0, 2016-01-13 Aquest article sobre patates fregides serà genial. ``` Paràgraf ``` No necessites res especial per un paràgraf. Insereix una línia buida entre cada paràgraf per separar-los. Per inserir un salt de línia, afegeix només un + i ja ho tens! ``` Donant format al text ``` _guió baix per cursiva_ *asteriscs per negreta* *_combina'ls i veuràs_* `usa cometes invertides per monospace` `*combina per negreta monospace*` ``` Títols de secció ``` = Nivell 0 (usa'l només pel títol del document) == Nivell 1

=== Nivell 2

==== Nivell 3

===== Nivell 4

``` Llistes Per crear una llista sense ordre usa asteriscs. ``` * foo * bar * baz ``` Per crear una llista numerada usa punts. ``` . element 1 . element 2 . element 3 ``` Pots crear fins a 5 subnivells de llista afegint asteriscs o punts. ``` * foo 1 ** foo 2 *** foo 3 **** foo 4 ***** foo 5 . foo 1 .. foo 2 ... foo 3 .... foo 4 ..... foo 5 ``` ## Referències Existeixen dues eines per processar documentació en AsciiDoc: 1. [AsciiDoc](http://asciidoc.org/): implementació original per Python, disponible a las principals distribucions Linux. Versió estable actualment en mode manteniment. 2. [Asciidoctor](http://asciidoctor.org/): implementació alternativa per Ruby, usable també des de Java i JavaScript. Implementació completa en evolució, té com a objectiu ampliar AsciiDoc amb noves funcionalitats i conversors de sortida. Els següents enllaços pertanyen a `Asciidoctor` (documentació en anglès): * [Comparació de sintaxi Markdown - AsciiDoc](http://asciidoctor.org/docs/user-manual/#comparison-by-example): comparativa d'elements comuns entre Markdown i AsciiDoc. * [Primeres pases](http://asciidoctor.org/docs/#get-started-with-asciidoctor): manuals d'instal·lació i inici per convertir documents simples. * [Manual d'usuari d'Asciidoctor](http://asciidoctor.org/docs/user-manual/): referència completa en un únic document, conté exemples, guies d'eines, etc. ================================================ FILE: ca/go.md ================================================ --- contributors: - ["Sonia Keys", "https://github.com/soniakeys"] - ["Christopher Bess", "https://github.com/cbess"] - ["Jesse Johnson", "https://github.com/holocronweaver"] - ["Quint Guvernator", "https://github.com/qguv"] - ["Jose Donizetti", "https://github.com/josedonizetti"] - ["Alexej Friesen", "https://github.com/heyalexej"] - ["Clayton Walker", "https://github.com/cwalk"] - ["Leonid Shevtsov", "https://github.com/leonid-shevtsov"] translators: - ["Xavier Sala", "http://github.com/utrescu"] --- Go es va crear degut a la necessitat de fer la feina ràpidament. No segueix la darrera tendència en informàtica, però és la nova forma i la més ràpida de resoldre problemes reals. Té conceptes familiars de llenguatges imperatius amb tipat estàtic. És ràpid compilant i ràpid al executar, afegeix una forma fàcil d'entedre de concurrència per CPUs de diferents núclis i té característiques que ajuden en la programació a gran escala. Go té una gran llibreria de funcions estàndard i una comunitat d'usuaris entusiasta. ```go // Comentari d'una sola línia /* Comentari multilínia */ // La clausula `package` apareix sempre a sobre de cada fitxer de codi font. // Quan es desenvolupa un executable en comptes d'una llibreria el nom que // s'ha de fer servir de `package` ha de ser 'main'. package main // `import` es fa servir per indicar quins paquets de llibreries fa servir // aquest fitxer. import ( "fmt" // Un paquet de la llibreria estàndard de Go. "io/ioutil" // Les funcions ioutil de io m "math" // La llibreria de matemàtiques que es referenciarà com a m. "net/http" // Si, un servidor web! "os" // funcions per treballar amb el sistema de fitxers "strconv" // Conversions de cadenes ) // La definició d'una funció. `main` és especial. És el punt d'entrada per // l'executable. Tant si t'agrada com si no, Go fa servir corxets. func main() { // Println imprimeix una línia al canal de sortida. // Es qualifica amb el nom del paquet, fmt. fmt.Println("Hola món!") // Crida a una altra funció dins d'aquest paquet. mesEnllaDeHola() } // Els paràmetres de les funcions es posen dins de parèntesis. // Els parèntesis fan falta encara que no hi hagi cap paràmetre. func mesEnllaDeHola() { var x int // Declaració d'una variable. // S'han de declarar abans de fer-les servir. x = 3 // Assignació d'una variable // Hi ha una forma "Curta" amb := // Descobreix el tipus, declara la variable i li assigna valor. y := 4 sum, prod := learnMultiple(x, y) // La funció retorna dos valors. fmt.Println("sum:", sum, "prod:", prod) // Sortida simple. aprenTipus() // < y minuts, aprèn més! } /* <- comentari multilínia Les funcions poden tenir paràmetres i (multiples!) valors de retorn. Aquí `x`, `y` són els argumens i `sum` i `prod` són els valors retornats. Fixa't que `x` i `sum` reben el tipus `int`. */ func learnMultiple(x, y int) (sum, prod int) { return x + y, x * y // Retorna dos valors. } // Alguns tipus incorporats i literals. func aprenTipus() { // Normalment la declaració curta et dóna el que vols. str := "Learn Go!" // tipus string s2 := `Un tipus cadena "normal" pot tenir salts de línia.` // El mateix tipus // literals Non-ASCII literal. El tipus de Go és UTF-8. g := 'Σ' // El tipus rune, és un àlies de int32 conté un caràcter unicode. f := 3.14159 // float64, un número de 64 bits amb coma flotant IEEE-754. c := 3 + 4i // complex128, representat internament amb dos float64. // Sintaxi amb var i inicialitzadors. var u uint = 7 // Sense signe, però depèn de la mida com els int. var pi float32 = 22. / 7 // Conversió de tipus amb declaració curta. n := byte('\n') // byte és un àlies de uint8. // Les taules tenen mida fixa en temps de compilació. var a4 [4]int // Taula de 4 enters inicialitzats a zero. a3 := [...]int{3, 1, 5} // Taula inicialitzada amb tres elements // amb els valors 3, 1, i 5. // Els "Slices" tenen mida dinàmica. Tant les taules com els "slices" // tenen avantatges però és més habitual que es facin servir slices. s3 := []int{4, 5, 9} // Compara amb a3. Aquí no hi ha els tres punts s4 := make([]int, 4) // Crea un slice de 4 enters inicialitzats a zero. var d2 [][]float64 // Només es declara però no hi ha valors. bs := []byte("a slice") // Sintaxi de conversió de tipus. // Com que són dinàmics es poden afegir valors nous als slices. // Per afegir-hi elements es fa servir el mètode append(). // El primer argument és l'slice en el que s'afegeix. // Sovint ell mateix com aquí sota. s := []int{1, 2, 3} // Un slice amb tres elements. s = append(s, 4, 5, 6) // Ara s tindrà tres elements més fmt.Println(s) // El resultat serà [1 2 3 4 5 6] // Per afegir un slice dins d'un altre en comptes de valors atòmics // S'hi pot passar una referència a l'altre slice o un literal acabat // amb tres punts, que vol dir que s'ha de desempaquetar els elements // i afegir-los a "s" s = append(s, []int{7, 8, 9}...) // El segon argument és un slice fmt.Println(s) // El resultat ara és [1 2 3 4 5 6 7 8 9] p, q := aprenMemoria() // Declara p i q com a punters de int. fmt.Println(*p, *q) // * segueix el punter fins a trobar els valors // Els "Mapes" són taules dinàmiques associatives com els hash o els // diccionaris d'altres llenguatges. m := map[string]int{"tres": 3, "quatre": 4} m["un"] = 1 // En Go les variables que no es fan servir generen un error. // El subratllat permet fer servir una variable i descartar-ne el valor. _, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs // És útil per descartar algun dels valors retornats per una funció // Per exemple, es pot ignorar l'error retornat per os.Create amb la idea // de que sempre es crearà. file, _ := os.Create("output.txt") fmt.Fprint(file, "Així es pot escriure en un fitxer") file.Close() // La sortida compta com a ús d'una variable. fmt.Println(s, c, a4, s3, d2, m) aprenControlDeFluxe() // Tornem. } // A diferència d'altres llenguatges les funcions poden retornar valors amb // nom. Assignant un nom al valor retornat en la declaració de la funció // permet retornar valors des de diferents llocs del programa a més de posar // el return sense valors func aprenRetornAmbNoms(x, y int) (z int) { z = x * y return // el retorn de z és implícit perquè ja té valor } // Go té un recollidor de basura. // Té punters però no té aritmetica de punters // Es poden cometre errors amb un punter a nil però no incrementant-lo. func aprenMemoria() (p, q *int) { // Els valors retornats p i q són punters a un enter. p = new(int) // Funció per reservar memòria // A la memòria ja hi ha un 0 per defecte, no és nil. s := make([]int, 20) // Reserva un bloc de memòria de 20 enters. s[3] = 7 // Assigna un valor a un d'ells. r := -2 // Declare una altra variable local. return &s[3], &r // & agafa l'adreça d'un objecte. } func expensiveComputation() float64 { return m.Exp(10) } func aprenControlDeFluxe() { // Els "If" necessiten corxets però no parèntesis. if true { fmt.Println("ja ho hem vist") } // El format del codi està estandaritzat amb la comanda "go fmt." if false { // Pout. } else { // Gloat. } // Si cal encadenar ifs és millor fer servir switch. x := 42.0 switch x { case 0: case 1: case 42: // Els case no "passen a través" no cal "break" per separar-los. /* Per fer-ho hi ha una comanda `fallthrough`, mireu: https://github.com/golang/go/wiki/Switch#fall-through */ case 43: // No hi arriba. default: // La opció "default" és opcional } // El 'for' tampoc necessita parèntesis, com el 'if'. // Les variables dins d'un bloc if o for són local del bloc. for x := 0; x < 3; x++ { // ++ is a statement. fmt.Println("iteració", x) } // x == 42. // L'única forma de fer bucles en Go és el 'for' però té moltes variants. for { // bucle infinit. break // És una broma!. continue // No hi arriba mai. } // Es fa servir "range" per iterar a una taula, un slice, un mapa // o un canal. // range torna un valor (channel) o dos (array, slice, string o map). for key, value := range map[string]int{"un": 1, "dos": 2, "tres": 3} { // Per cada parell del mapa imprimeix la clau i el valor. fmt.Printf("clau=%s, valor=%d\n", key, value) } // Si només cal el valor es pot fer servir _ for _, name := range []string{"Robert", "Bill", "Josep"} { fmt.Printf("Hola, %s\n", name) } // Es pot usar := per declarar i assignar valors i després // comprovar-lo y > x. if y := expensiveComputation(); y > x { x = y } // Les funcions literals són closures xBig := func() bool { return x > 10000 // Referencia a x declarada sobre el switch. } x = 99999 fmt.Println("xBig:", xBig()) // cert x = 1.3e3 // x val 1300 fmt.Println("xBig:", xBig()) // fals. // A més les funcions poden ser definides i cridades com a arguments per // una funció sempre que: // a) La funció es cridi inmediatament (), // b) El tipus del resultat sigui del tipus esperat de l'argument. fmt.Println("Suma i duplica dos números: ", func(a, b int) int { return (a + b) * 2 }(10, 2)) // Es crida amb els arguments 10 i 2 // => Suma i duplica dos números: 24 // Quan el necessitis t'agradarà que hi sigui goto love love: aprenFabricaDeFuncions() // func que retorna func és divertit(3)(3) aprenDefer() // Revisió ràpida d'una paraula clau. aprendreInterficies() // Bon material properament! } func aprenFabricaDeFuncions() { // Les dues seguents són equivalents, però la segona és més pràctica fmt.Println(sentenceFactory("dia")("Un bonic", "d'estiu!")) d := sentenceFactory("dia") fmt.Println(d("Un bonic", "d'estiu!")) fmt.Println(d("Un tranquil", "de primavera!")) } // Els decoradors són habituals en altres llenguatges. // Es pot fer el mateix en Go amb funcions literals que accepten arguments. func sentenceFactory(mystring string) func(before, after string) string { return func(before, after string) string { return fmt.Sprintf("%s %s %s", before, mystring, after) // nou string } } func aprenDefer() (ok bool) { // Les comandes marcades amb defer s'executen després de que la funció // hagi acabat. defer fmt.Println("Les comandes defer s'executen en ordre invers (LIFO).") defer fmt.Println("\nAquesta és la primera línia que s'imprimeix") // Defer es fa servir gairebé sempre per tancar un fitxer, en el moment // en que acaba el mètode. return true } // Defineix Stringer com un tipus interfície amb el mètode String(). type Stringer interface { String() string } // Defineix una estrutura que conté un parell d'enters, x i y. type parell struct { x, y int } // Defineix un mètode de l'estructura parell. Ara parell implementa Stringer. func (p parell) String() string { // p és anomenat el "receptor" // Sprintf és una funció del paquet fmt. // Fa referència als camps de p. return fmt.Sprintf("(%d, %d)", p.x, p.y) } func aprendreInterficies() { // La sintaxi de claus es pot fer servir per inicialitzar un "struct". // Gràcies a := defineix i inicialitza p com un struct 'parell'. p := parell{3, 4} fmt.Println(p.String()) // Es crida al mètode de p. var i Stringer // Declara i de tipus Stringer. i = p // parell implementa Stringer per tant és vàlid. // Es pot cridar el mètode String() igual que abans. fmt.Println(i.String()) // Les funcions de fmt criden a String() per aconseguir una representació // imprimible d'un objecte. fmt.Println(p) // Treu el mateix d'abans. Println crida el mètode String. fmt.Println(i) // Idèntic resultat aprendreParamentesVariables("Aquí", "estem", "aprenent!") } // Les funcions poden tenir paràmetres variables. func aprendreParamentesVariables(myStrings ...interface{}) { // Itera per cada un dels valors dels paràmetres // Ignorant l'índex de la seva posició for _, param := range myStrings { fmt.Println("paràmetre:", param) } // Passa el valor de múltipes variables com a paràmetre. fmt.Println("parametres:", fmt.Sprintln(myStrings...)) aprenControlErrors() } func aprenControlErrors() { // ", ok" Es fa servir per saber si hi és o no. m := map[int]string{3: "tres", 4: "quatre"} if x, ok := m[1]; !ok { // ok serà fals perquè 1 no està en el mapa. fmt.Println("no hi és") } else { fmt.Print(x) // x seria el valor, si no estés en el mapa. } // Un valor d'error donarà més informació sobre l'error. if _, err := strconv.Atoi("no-int"); err != nil { // _ descarta el valor // imprimeix 'strconv.ParseInt: intenta convertir "non-int": // syntaxi invalida' fmt.Println(err) } // Es tornarà a les interfícies més tard. Mentrestant, aprenConcurrencia() } // c és un canal (channel), una forma segura de comunicar objectes. func inc(i int, c chan int) { c <- i + 1 // <- és l'operador "envia" quan un canal està a l'esquerra. } // Es pot fer servir inc per incrementar un número de forma concurrent. func aprenConcurrencia() { // La funció make es pot fer servir per crear slices, mapes i canals. c := make(chan int) // S'inicien tres goroutines. // Els números s'incrementaran de forma concurrent, En paral·lel // si la màquina on s'executa pot fer-ho i està correctament configurada. // Tots tres envien al mateix canal. go inc(0, c) // go és la comanda que inicia una nova goroutine. go inc(10, c) go inc(-805, c) // Llegeix tres resultats del canal i els imprimeix. // No es pot saber en quin ordre arribaran els resultats! fmt.Println(<-c, <-c, <-c) // Canal a la dreta <- és l'operador "rebre" cs := make(chan string) // Un altre canal que processa strings. ccs := make(chan chan string) // Un canal de canals string. go func() { c <- 84 }() // Inicia una goroutine i li envia un valor. go func() { cs <- "paraula" }() // El mateix però amb cs. // Select té una sintaxi semblant a switch però amb canals. // Selecciona un cas aleatòriament dels que poden comunicar-se. select { case i := <-c: // El valor rebit pot ser assignat a una variable, fmt.Printf("és un %T", i) case <-cs: // O es pot descartar fmt.Println("és un string") case <-ccs: // Canal buit, no preparat per la comunicació. fmt.Println("no ha passat.") } // Quan arribi aquí s'haurà agafat un valor de c o bé de cs. Una de les // goroutines iniciades haurà acabat i l'altra romandrà bloquejada. aprenProgramacioWeb() // Go ho fa. Tu vols fer-ho. } // Una funció del paquet http inicia un servidor web. func aprenProgramacioWeb() { // El primer paràmetre de ListenAndServe és l'adreça on escoltar // i el segon és una interfície http.Handler. go func() { err := http.ListenAndServe(":8080", pair{}) fmt.Println(err) // no s'han d'ignorar els errors }() requestServer() } // Es converteix "parell" en un http.Handler només implementant el // mètode ServeHTTP. func (p parell) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Serveix dades en el http.ResponseWriter. w.Write([]byte("Has après Go en Y minuts!")) } func requestServer() { resp, err := http.Get("http://localhost:8080") fmt.Println(err) defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Printf("\nEl servidor diu: `%s`", string(body)) } ``` ## Més informació L'arrel de tot en Go és la web oficial [official Go web site](https://go.dev/). Allà es pot seguir el tutorial, jugar interactivament i llegir molt més del que hem vist aquí.En el "tour", [the docs](https://go.dev/doc/) conté informació sobre com escriure codi net i efectiu en Go, comandes per empaquetar i generar documentació, i història de les versions. És altament recomanable llegir La definició del llenguatge. És fàcil de llegir i sorprenentment curta (com la definició del llenguatge en aquests dies). Es pot jugar amb codi a [Go playground](https://go.dev/play/p/tnWMjr16Mm). Prova de fer canvis en el codi i executar-lo des del navegador! Es pot fer servir [https://go.dev/play/](https://go.dev/play/) com a [REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop) per provar coses i codi en el navegador sense haver d'instal·lar Go. En la llista de lectures pels estudiants de Go hi ha [el codi font de la llibreria estàndard](https://go.dev/src/). Ampliament comentada, que demostra el fàcil que és de llegir i entendre els programes en Go, l'estil de programació, i les formes de treballar-hi. O es pot clicar en un nom de funció en [la documentació](https://go.dev/pkg/) i veure'n el codi! Un altre gran recurs per aprendre Go és [Go by example](https://gobyexample.com/). Go Mobile afegeix suport per plataformes mòbils (Android i iOS). Es poden escriure aplicacions mòbils o escriure llibreries de paquets de Go, que es poden cridar des de Java (android) i Objective-C (iOS). Comproveu la [Go Mobile page](https://go.dev/wiki/Mobile) per més informació. ================================================ FILE: ca/groovy.md ================================================ --- contributors: - ["Roberto Pérez Alcolea", "http://github.com/rpalcolea"] translators: - ["Xavier Sala Pujolar", "http://github.com/utrescu"] --- Groovy - Un llenguatge dinàmic per la plataforma Java [Llegir-ne més](http://www.groovy-lang.org/). ```groovy /* Posa'l en marxa tu mateix: 1) Instal.la SDKMAN - http://sdkman.io/ 2) Instal.la Groovy: sdk install groovy 3) Inicia la consola groovy escrivint: groovyConsole */ // Els comentaris d'una sola línia comencen amb dues barres inverses /* Els comentaris multilínia són com aquest. */ // Hola món println "Hola món!" /* Variables: Es poden assignar valors a les variables per fer-los servir més tard */ def x = 1 println x x = new java.util.Date() println x x = -3.1499392 println x x = false println x x = "Groovy!" println x /* Col.leccions i mapes */ // Crear una llista buida def technologies = [] /*** Afegir elements a la llista ***/ // Com en Java technologies.add("Grails") // El shift a l'esquerra afegeix i retorna la llista technologies << "Groovy" // Afegir múltiples elements technologies.addAll(["Gradle","Griffon"]) /*** Eliminar elements de la llista ***/ // Com en Java technologies.remove("Griffon") // La resta també funciona technologies = technologies - 'Grails' /*** Iterar per les llistes ***/ // Iterar per tots els elements de la llista technologies.each { println "Technology: $it"} technologies.eachWithIndex { it, i -> println "$i: $it"} /*** Comprovar el contingut de la llista ***/ //Comprovar si la llista conté un o més elements (resultat boolea) contained = technologies.contains( 'Groovy' ) // O contained = 'Groovy' in technologies // Comprovar diversos elements technologies.containsAll(['Groovy','Grails']) /*** Ordenar llistes ***/ // Ordenar una llista (canvia la original) technologies.sort() // Per ordenar sense canviar la original es pot fer: sortedTechnologies = technologies.sort( false ) /*** Manipular llistes ***/ //Canvia tots els elements de la llista Collections.replaceAll(technologies, 'Gradle', 'gradle') // Desordena la llista Collections.shuffle(technologies, new Random()) // Buida la llista technologies.clear() // Crear un mapa buit def devMap = [:] // Afegir valors al mapa devMap = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] devMap.put('lastName','Perez') // Iterar per tots els elements del mapa devMap.each { println "$it.key: $it.value" } devMap.eachWithIndex { it, i -> println "$i: $it"} // Comprovar si la clau hi és assert devMap.containsKey('name') // Comprova si el mapa conté un valor concret assert devMap.containsValue('Roberto') // Obtenir les claus del mapa println devMap.keySet() // Obtenir els valors del mapa println devMap.values() /* Groovy Beans Els GroovyBeans són JavaBeans però amb una sintaxi molt més senzilla Quan Groovy es compila a bytecode es fan servir les regles següents. * Si el nom és declarat amb un modificador (public, private o protected) es genera el camp * Un nom declarat sense modificadors genera un camp privat amb un getter i un setter públics (per exemple una propietat) * Si la propietat és declarada final el camp privat es crea i no es genera cap setter. * Es pot declarar una propietat i també declarar un getter i un setter. * Es pot declarar una propietat i un camp amb el mateix nom, la propietat farà servir el camp. * Si es vol una propietat private o protected s'ha de definir el getter i el setter que s'han de declarar private o protected. * Si s'accedeix a una propietat de la classe que està definida en temps de compilació amb un this implícit o explícit (per exemple this.foo, o bé només foo), Groovy accedirà al camp directament en comptes de fer-ho a través del getter i el setter. * Si s'accedeix a una propietat que no existeix tant implícita com explicitament, llavors Groovy accedirà a la propietat a través de la meta classe, que pot fer que falli en temps d'execució. */ class Foo { // Propietat només de lectura final String name = "Roberto" // Propietat de només lectura amb getter públic i un setter protected String language protected void setLanguage(String language) { this.language = language } // Propietat amb el tipus definit dinàmicament def lastName } /* Bucles i estructres de control */ //Groovy té el format tradicional de if -else def x = 3 if(x==1) { println "One" } else if(x==2) { println "Two" } else { println "X greater than Two" } // Groovy també té l'operador ternari def y = 10 def x = (y > 1) ? "worked" : "failed" assert x == "worked" //I també té 'l'Operador Elvis'! //En comptes de fer servir l'operador ternari: displayName = user.name ? user.name : 'Anonymous' // Es pot escriure d'aquesta forma: displayName = user.name ?: 'Anonymous' //Bucle for //Itera en un rang def x = 0 for (i in 0 .. 30) { x += i } //Itera per una llista x = 0 for( i in [5,3,2,1] ) { x += i } //Itera per un array array = (0..20).toArray() x = 0 for (i in array) { x += i } //Itera per un mapa def map = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] x = "" for ( e in map ) { x += e.value x += " " } assert x.equals("Roberto Grails Groovy ") /* Operadors Hi ha una llista d'operadors que poden ser sobreescrits en Groovy: http://www.groovy-lang.org/operators.html#Operator-Overloading Operadors útils de Groovy */ //Spread operator: Invoca una acció en tots els ítems d'un grup d'objectes. def technologies = ['Groovy','Grails','Gradle'] technologies*.toUpperCase() // = a technologies.collect { it?.toUpperCase() } //Safe navigation operator: fet servir per evitar el NullPointerException. def user = User.get(1) def username = user?.username /* Closures Un Closure és com un "bloc de codi" o un punter a un mètode. És un troç de codi que està definit i que s podrà executar més tard. Més informació a: http://www.groovy-lang.org/closures.html */ //Exemple: def clos = { println "Hola món!" } println "Executant el Closure:" clos() // Passar paràmetres a un Closure def sum = { a, b -> println a+b } sum(2,4) //Els Closures poden fer referència a variables que no formen part de la // llista dels seus paràmetres. def x = 5 def multiplyBy = { num -> num * x } println multiplyBy(10) // Si es té un Closure que agafa un element com a argument, se'n pot ignorar // la definició def clos = { print it } clos( "hi" ) /* Groovy pot recordar els resultats dels Closures */ def cl = {a, b -> sleep(3000) // simula un procés llarg a + b } mem = cl.memoize() def callClosure(a, b) { def start = System.currentTimeMillis() mem(a, b) println "(a = $a, b = $b) - en ${System.currentTimeMillis() - start} ms" } callClosure(1, 2) callClosure(1, 2) callClosure(2, 3) callClosure(2, 3) callClosure(3, 4) callClosure(3, 4) callClosure(1, 2) callClosure(2, 3) callClosure(3, 4) /* Expando La classe Expando és un bean dinàmic al que se li poden afegir propietats i closures com a mètodes d'una instància d'aquesta classe. http://mrhaki.blogspot.mx/2009/10/groovy-goodness-expando-as-dynamic-bean.html */ def user = new Expando(name:"Roberto") assert 'Roberto' == user.name user.lastName = 'Pérez' assert 'Pérez' == user.lastName user.showInfo = { out -> out << "Name: $name" out << ", Last name: $lastName" } def sw = new StringWriter() println user.showInfo(sw) /* Metaprogrammació (MOP) */ // Fent servir ExpandoMetaClass per afegir comportament String.metaClass.testAdd = { println "he afegit això" } String x = "test" x?.testAdd() //Intercepting method calls class Test implements GroovyInterceptable { def sum(Integer x, Integer y) { x + y } def invokeMethod(String name, args) { System.out.println "Invoca el mètode $name amb arguments: $args" } } def test = new Test() test?.sum(2,3) test?.multiply(2,3) //Groovy supporta propertyMissing per gestionar la resolució de propietats class Foo { def propertyMissing(String name) { name } } def f = new Foo() assertEquals "boo", f.boo /* TypeChecked i CompileStatic Groovy, by nature, és i sempre serà un llenguatge dinàmic però també té comprovació de tipus i definicions estàtiques More info: http://www.infoq.com/articles/new-groovy-20 */ //TypeChecked import groovy.transform.TypeChecked void testMethod() {} @TypeChecked void test() { testMeethod() def name = "Roberto" println naameee } //Un altre exemple: import groovy.transform.TypeChecked @TypeChecked Integer test() { Integer num = "1" Integer[] numbers = [1,2,3,4] Date date = numbers[1] return "Test" } //exemple de CompileStatic import groovy.transform.CompileStatic @CompileStatic int sum(int x, int y) { x + y } assert sum(2,5) == 7 ``` ## Per aprendre'n més [documentació de Groovy](http://www.groovy-lang.org/documentation.html) [Cònsola de Groovy](http://groovyconsole.appspot.com/) Uneix-te a un [grup d'usuaris Groovy](http://www.groovy-lang.org/usergroups.html) ## Llibres * [Groovy Goodness](https://leanpub.com/groovy-goodness-notebook) * [Groovy in Action](http://manning.com/koenig2/) * [Programming Groovy 2: Dynamic Productivity for the Java Developer](http://shop.oreilly.com/product/9781937785307.do) ================================================ FILE: ca/html.md ================================================ --- contributors: - ["Christophe THOMAS", "https://github.com/WinChris"] translators: - ["Marc Auledas", "https://github.com/Auledas"] --- HTML significa llenguatge de marques d'hipertext (HyperText Markup Language). És un llenguatge que permet escriure pàgines pel sistema web (World Wide Web). És un llenguatge de marques que permet escriure pàgines web fent servir codi per indicar com s'ha de visualitzar el text i les dades. De fet, els fitxers html són simples fitxers de text. Què són les 'marques'? Són un mètode d'organitzar les dades d'una pàgina mitjançant etiquetes d'obertura i tancament. Aquestes marques serveixen per donar significat al text que hi ha entre les etiquetes. Com d'altres llenguatges de marques, hi ha moltes versions de l'HTML. Aquí es desenvoluparà l'HTML5. **NOTA:** Pots provar les diferents etiquetes i elements a mesura que progressis a través del tutorial a pàgines web com [codepen](http://codepen.io/pen/). D'aquesta manera podràs veure'n els efectes, entendre com funcionen i familiaritzar-te amb el llenguatge. Aquest article tracta principalment la sintaxi de l'HTML i alguns consells útils. ```html El meu lloc web

Hola, món!

Fes una ullada a com es veu això.

Això és un paràgraf.

Això és un altre paràgraf.

  • Això és un element d'una llista no enumerada (llista de punts).
  • Això és un altre element.
  • I aquest és l'últim element de la llista.
El meu lloc web

Hola, món!

Fes una ullada a com es veu això.

Això és un paràgraf.

Això és un altre paràgraf.

  • Això és un element d'una llista no enumerada (llista de punts).
  • Això és un altre element.
  • I aquest és l'últim element de la llista.
Primera capçalera Segona capçalera
Primera fila, primera columna Primera fila, segona columna
Segona fila, primera columna Segona fila, segona columna
``` ## Ús Els arxius HTML acaben amb les extensions `.html` o `.htm`. El tipus MIME és `text/html`. **HTML NO és un llenguatge de programació** ## Per aprendre'n més * [Viquipèdia](https://ca.wikipedia.org/wiki/Hyper_Text_Markup_Language) * [Tutorial HTML](https://developer.mozilla.org/ca/docs/Web/HTML) * [W3School](http://www.w3schools.com/html/html_intro.asp) ================================================ FILE: ca/kotlin.md ================================================ --- contributors: - ["S Webber", "https://github.com/s-webber"] translators: - ["Xavier Sala", "https://github.com/utrescu"] --- Kotlin és un llenguatge estàtic tipat per la JVM, Android i el navegador. És interoperable al 100% amb Java. [Llegir-ne més aquí.](https://kotlinlang.org/) ```kotlin // Els comentaris d'una línia comencen amb // /* Els comentaris multilínia són com aquest */ // La paraula clau "package" funciona de la mateixa forma que en Java package com.learnxinyminutes.kotlin /* El punt d'entrada dels programes en Kotlin és una funció anomenada "main". La funció rep un array que té els arguments fets servir al executar-lo. */ fun main(args: Array) { /* La declaració de variables es pot fer tant amb "var" com amb "val". A les declarades amb "val" no se'ls hi pot canviar el valor en canvi a les declarades amb "var" si. */ val fooVal = 10 // no es podrà canviar el valor de fooVal var fooVar = 10 fooVar = 20 // fooVar si que es pot canviar /* Gairebé sempre, Kotlin pot determinar el tipus d'una variable, de manera que no caldrà definir-lo cada vegada. Però es pot definir el tipus d'una variable explícitament d'aquesta forma: */ val foo: Int = 7 /* Els "strings" es poden representar igual que com es fa en Java. Es poden escapar caràcters amb la barra inversa. */ val fooString = "Aquí està la meva cadena!" val barString = "Imprimir en dues línies?\nCap problema!" val bazString = "Es poden posar tabuladors?\tI tant!" println(fooString) println(barString) println(bazString) /* Es poden definir strings literals envoltant-los amb les triples cometes ("""). Dins hi poden haver tant salts de línies com d'altres caràcters. */ val fooRawString = """ fun helloWorld(val name : String) { println("Hola món!") } """ println(fooRawString) /* Els strings poden contenir expressions de plantilla. Les expressions de plantilla comencen amb el símbol ($). */ val fooTemplateString = "$fooString té ${fooString.length} caràcters" println(fooTemplateString) /* Perquè una variable pugui contenir null ha de ser declarada específicament com a nullable afengint-li ? al seu tipus. Es pot accedir a una variable nulable fent servir l'operador ?. L'operador ?: permet especificar un valor alternatiu en cas de que la variable sigui null. */ var fooNullable: String? = "abc" println(fooNullable?.length) // => 3 println(fooNullable?.length ?: -1) // => 3 fooNullable = null println(fooNullable?.length) // => null println(fooNullable?.length ?: -1) // => -1 /* Les funcions es declaren amb la paraula "fun". Els arguments s'especifiquen entre corxets després del nom de la funció. Els arguments poden tenir un valor per defecte. El retorn de les funcions, si cal, es posa després de l'argument. */ fun hello(name: String = "món"): String { return "Hola, $name!" } println(hello("foo")) // => Hola, foo! println(hello(name = "bar")) // => Hola, bar! println(hello()) // => Hola, món! /* Un dels paràmetres d'una funció pot ser marcat amb la paraula clau "vararg" que permet que una funció accepti un número variable d'arguments. */ fun varargExample(vararg names: Int) { println("S'han rebut ${names.size} arguments") } varargExample() // => S'han rebut 0 elements varargExample(1) // => S'ha rebut 1 element varargExample(1, 2, 3) // => S'han rebut 3 elements /* Quan una funció consisteix en una sola expressió no calen els corxets El cos de la funció es posa rere el símbol =. */ fun odd(x: Int): Boolean = x % 2 == 1 println(odd(6)) // => false println(odd(7)) // => true // Si el tipus retornat es pot determinar no cal especificar-lo. fun even(x: Int) = x % 2 == 0 println(even(6)) // => true println(even(7)) // => false // Les funcions poden tenir altres funcions com arguments i // fins i tot retornar-ne. fun not(f: (Int) -> Boolean): (Int) -> Boolean { return {n -> !f.invoke(n)} } // Les funcions amb nom es poden especificar quan fan d'arguments amb :: val notOdd = not(::odd) val notEven = not(::even) // Les expressions lambda es poden posar com arguments. val notZero = not {n -> n == 0} /* Si la lambda només té un paràmetre es pot ometre la seva declaració. El seu valor serà "it". */ val notPositive = not {it > 0} for (i in 0..4) { println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}") } // Les classes es defineixen amb "class". class ExampleClass(val x: Int) { fun memberFunction(y: Int): Int { return x + y } infix fun infixMemberFunction(y: Int): Int { return x * y } } /* Per crear una nova instància es crida al constructor. Tingueu en compte que Kotlin no té l'operador "new". */ val fooExampleClass = ExampleClass(7) // Els mètodes es poden cridar amb la notació . println(fooExampleClass.memberFunction(4)) // => 11 /* Si una funció ha estat marcada amb "infix" es pot cridar amb la notació infix. */ println(fooExampleClass infixMemberFunction 4) // => 28 /* Les classes "data" són classes que només contenen dades. Es creen automàticament els mètodes "hashCode","equals" i "toString" */ data class DataClassExample (val x: Int, val y: Int, val z: Int) val fooData = DataClassExample(1, 2, 4) println(fooData) // => DataClassExample(x=1, y=2, z=4) // Les classes data tenen un mètode "copy". val fooCopy = fooData.copy(y = 100) println(fooCopy) // => DataClassExample(x=1, y=100, z=4) // Els objectes es poden desestructurar amb múltiples variables val (a, b, c) = fooCopy println("$a $b $c") // => 1 100 4 // desestructurat en un bucle "for" for ((a, b, c) in listOf(fooData)) { println("$a $b $c") // => 1 100 4 } val mapData = mapOf("a" to 1, "b" to 2) // Els mapes també for ((key, value) in mapData) { println("$key -> $value") } // La funció "with" és similar a la de JavaScript. data class MutableDataClassExample (var x: Int, var y: Int, var z: Int) val fooMutableData = MutableDataClassExample(7, 4, 9) with (fooMutableData) { x -= 2 y += 2 z-- } println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8) /* Es pot crear una llista amb la funció "listOf". La llista serà immutable - no s'hi poden afegir o treure elements. */ val fooList = listOf("a", "b", "c") println(fooList.size) // => 3 println(fooList.first()) // => a println(fooList.last()) // => c // Es pot accedir als elements a partir del seu índex. println(fooList[1]) // => b // Es poden crear llistes mutables amb la funció "mutableListOf". val fooMutableList = mutableListOf("a", "b", "c") fooMutableList.add("d") println(fooMutableList.last()) // => d println(fooMutableList.size) // => 4 // Es poden crear conjunts amb la funció "setOf". val fooSet = setOf("a", "b", "c") println(fooSet.contains("a")) // => true println(fooSet.contains("z")) // => false // Es poden crear mapes amb la funció "mapOf". val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9) // S'accedeix als valors del mapa a partir del seu índex. println(fooMap["a"]) // => 8 /* Les sequències representen col·leccions evaluades quan fan falta. Podem crear una seqüencia amb la funció "generateSequence". */ val fooSequence = generateSequence(1, { it + 1 }) val x = fooSequence.take(10).toList() println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // Per exemple amb aquesta seqüència es creen els números de Fibonacci: fun fibonacciSequence(): Sequence { var a = 0L var b = 1L fun next(): Long { val result = a + b a = b b = result return a } return generateSequence(::next) } val y = fibonacciSequence().take(10).toList() println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] // Kotlin proporciona funcions de primer ordre per treballar amb // col·leccions. val z = (1..9).map {it * 3} .filter {it < 20} .groupBy {it % 2 == 0} .mapKeys {if (it.key) "parell" else "senar"} println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]} // Es pot fer servir el bucle "for" amb qualsevol cosa que proporcioni // un iterador. for (c in "hello") { println(c) } // els bucles "while" funcionen com en altres llenguatges. var ctr = 0 while (ctr < 5) { println(ctr) ctr++ } do { println(ctr) ctr++ } while (ctr < 10) /* "if" es pot fer servir com una expressió que retorna un valor. Per això no cal l'operador ternari ?: en Kotlin. */ val num = 5 val message = if (num % 2 == 0) "parell" else "senar" println("$num is $message") // => 5 is odd // "when" es pot fer servir com alternativa a les cadenes "if-else if". val i = 10 when { i < 7 -> println("primer bloc") fooString.startsWith("hola") -> println("segon bloc") else -> println("bloc else") } // "when" es pot fer servir amb un argument. when (i) { 0, 21 -> println("0 o 21") in 1..20 -> println("en el rang 1 a 20") else -> println("cap dels anteriors") } // "when" es pot fer servir com una funció que retorna valors. var result = when (i) { 0, 21 -> "0 o 21" in 1..20 -> "en el rang 1 a 20" else -> "cap dels anteriors" } println(result) /* Es pot comprovar el tipus d'un objecte fent servir l'operador "is". Si un objecte passa una comprovació es pot fer servir sense posar-hi cap casting. */ fun smartCastExample(x: Any) : Boolean { if (x is Boolean) { // x es converteix automàticament a Booleà return x } else if (x is Int) { // x es converteix automàticament a int return x > 0 } else if (x is String) { // x es converteix a string automàticament return x.isNotEmpty() } else { return false } } println(smartCastExample("Hola món!")) // => true println(smartCastExample("")) // => false println(smartCastExample(5)) // => true println(smartCastExample(0)) // => false println(smartCastExample(true)) // => true // També es pot cridar smarcast en un bloc when fun smartCastWhenExample(x: Any) = when (x) { is Boolean -> x is Int -> x > 0 is String -> x.isNotEmpty() else -> false } /* Les extensions són una forma d'afegir noves funcionalitats a una classe. És semblant a les extensions de C#. */ fun String.remove(c: Char): String { return this.filter {it != c} } println("Hola món!".remove('l')) // => Hoa, món! println(EnumExample.A) // => A println(ObjectExample.hello()) // => hola } // Les classes enumerades són semblants a les de Java enum class EnumExample { A, B, C } /* El paràmetre "object" es pot fer servir per crear objectes singleton. No es poden instanciar però es pot fer referència a la seva única instància amb el seu nom. Són similars als singletons d'Scala. */ object ObjectExample { fun hello(): String { return "hola" } } fun useObject() { ObjectExample.hello() val someRef: Any = ObjectExample // podem fer servir el nom de l'objecte } ``` ### Per llegir més * [tutorials de Kotlin](https://kotlinlang.org/docs/tutorials/) * [Provar Kotlin en el navegador](http://try.kotlinlang.org/) * [Llista de recursos de Kotlin](http://kotlin.link/) ================================================ FILE: chapel.md ================================================ --- name: Chapel filename: learnchapel.chpl contributors: - ["Ian J. Bertolacci", "https://www.cs.arizona.edu/~ianbertolacci/"] - ["Ben Harshbarger", "https://github.com/benharsh/"] --- You can read all about Chapel at [Cray's official Chapel website](https://chapel-lang.org). In short, Chapel is an open-source, high-productivity, parallel-programming language in development at Cray Inc., and is designed to run on multi-core PCs as well as multi-kilocore supercomputers. More information and support can be found at the bottom of this document. You can refer to the official site for [latest version](https://chapel-lang.org/docs/master/primers/learnChapelInYMinutes.html) of this document. ```chapel /* Learn Chapel in Y Minutes This primer will go over basic syntax and concepts in Chapel. Last sync with official page: Sun, 08 Mar 2020 08:05:53 +0000 */ // Comments are C-family style // one line comment /* multi-line comment */ /* Basic printing */ write("Hello, "); writeln("World!"); // ``write`` and ``writeln`` can take a list of things to print. // Each thing is printed right next to the others, so include your spacing! writeln("There are ", 3, " commas (\",\") in this line of code"); // Different output channels: use IO; // Required for accessing the alternative output channels stdout.writeln("This goes to standard output, just like plain writeln() does"); stderr.writeln("This goes to standard error"); /* Variables */ // Variables don't have to be explicitly typed as long as // the compiler can figure out the type that it will hold. // 10 is an ``int``, so ``myVar`` is implicitly an ``int`` var myVar = 10; myVar = -10; var mySecondVar = myVar; // ``var anError;`` would be a compile-time error. // We can (and should) explicitly type things. var myThirdVar: real; var myFourthVar: real = -1.234; myThirdVar = myFourthVar; /* Types */ // There are a number of basic types. var myInt: int = -1000; // Signed ints var myUint: uint = 1234; // Unsigned ints var myReal: real = 9.876; // Floating point numbers var myImag: imag = 5.0i; // Imaginary numbers var myCplx: complex = 10 + 9i; // Complex numbers myCplx = myInt + myImag; // Another way to form complex numbers var myBool: bool = false; // Booleans var myStr: string = "Some string..."; // Strings var singleQuoteStr = 'Another string...'; // String literal with single quotes // Some types can have sizes. var my8Int: int(8) = 10; // 8 bit (one byte) sized int; var my64Real: real(64) = 1.516; // 64 bit (8 bytes) sized real // Typecasting. var intFromReal = myReal : int; var intFromReal2: int = myReal : int; // Type aliasing. type chroma = int; // Type of a single hue type RGBColor = 3*chroma; // Type representing a full color var black: RGBColor = (0,0,0); var white: RGBColor = (255, 255, 255); /* Constants and Parameters */ // A ``const`` is a constant, and cannot be changed after set in runtime. const almostPi: real = 22.0/7.0; // A ``param`` is a constant whose value must be known statically at // compile-time. param compileTimeConst: int = 16; // The ``config`` modifier allows values to be set at the command line. // Set with ``--varCmdLineArg=Value`` or ``--varCmdLineArg Value`` at runtime. config var varCmdLineArg: int = -123; config const constCmdLineArg: int = 777; // ``config param`` can be set at compile-time. // Set with ``--set paramCmdLineArg=value`` at compile-time. config param paramCmdLineArg: bool = false; writeln(varCmdLineArg, ", ", constCmdLineArg, ", ", paramCmdLineArg); /* References */ // ``ref`` operates much like a reference in C++. In Chapel, a ``ref`` cannot // be made to alias a variable other than the variable it is initialized with. // Here, ``refToActual`` refers to ``actual``. var actual = 10; ref refToActual = actual; writeln(actual, " == ", refToActual); // prints the same value actual = -123; // modify actual (which refToActual refers to) writeln(actual, " == ", refToActual); // prints the same value refToActual = 99999999; // modify what refToActual refers to (which is actual) writeln(actual, " == ", refToActual); // prints the same value /* Operators */ // Math operators: var a: int, thisInt = 1234, thatInt = 5678; a = thisInt + thatInt; // Addition a = thisInt * thatInt; // Multiplication a = thisInt - thatInt; // Subtraction a = thisInt / thatInt; // Division a = thisInt ** thatInt; // Exponentiation a = thisInt % thatInt; // Remainder (modulo) // Logical operators: var b: bool, thisBool = false, thatBool = true; b = thisBool && thatBool; // Logical and b = thisBool || thatBool; // Logical or b = !thisBool; // Logical negation // Relational operators: b = thisInt > thatInt; // Greater-than b = thisInt >= thatInt; // Greater-than-or-equal-to b = thisInt < a && a <= thatInt; // Less-than, and, less-than-or-equal-to b = thisInt != thatInt; // Not-equal-to b = thisInt == thatInt; // Equal-to // Bitwise operators: a = thisInt << 10; // Left-bit-shift by 10 bits; a = thatInt >> 5; // Right-bit-shift by 5 bits; a = ~thisInt; // Bitwise-negation a = thisInt ^ thatInt; // Bitwise exclusive-or // Compound assignment operators: a += thisInt; // Addition-equals (a = a + thisInt;) a *= thatInt; // Times-equals (a = a * thatInt;) b &&= thatBool; // Logical-and-equals (b = b && thatBool;) a <<= 3; // Left-bit-shift-equals (a = a << 10;) // Unlike other C family languages, there are no // pre/post-increment/decrement operators, such as: // // ``++j``, ``--j``, ``j++``, ``j--`` // Swap operator: var old_this = thisInt; var old_that = thatInt; thisInt <=> thatInt; // Swap the values of thisInt and thatInt writeln((old_this == thatInt) && (old_that == thisInt)); // Operator overloads can also be defined, as we'll see with procedures. /* Tuples */ // Tuples can be of the same type or different types. var sameTup: 2*int = (10, -1); var sameTup2 = (11, -6); var diffTup: (int,real,complex) = (5, 1.928, myCplx); var diffTupe2 = (7, 5.64, 6.0+1.5i); // Tuples can be accessed using square brackets or parentheses, and are // 1-indexed. writeln("(", sameTup[1], ",", sameTup(2), ")"); writeln(diffTup); // Tuples can also be written into. diffTup(1) = -1; // Tuple values can be expanded into their own variables. var (tupInt, tupReal, tupCplx) = diffTup; writeln(diffTup == (tupInt, tupReal, tupCplx)); // They are also useful for writing a list of variables, as is common in debugging. writeln((a,b,thisInt,thatInt,thisBool,thatBool)); /* Control Flow */ // ``if`` - ``then`` - ``else`` works just like any other C-family language. if 10 < 100 then writeln("All is well"); if -1 < 1 then writeln("Continuing to believe reality"); else writeln("Send mathematician, something's wrong"); // You can use parentheses if you prefer. if (10 > 100) { writeln("Universe broken. Please reboot universe."); } if a % 2 == 0 { writeln(a, " is even."); } else { writeln(a, " is odd."); } if a % 3 == 0 { writeln(a, " is even divisible by 3."); } else if a % 3 == 1 { writeln(a, " is divided by 3 with a remainder of 1."); } else { writeln(b, " is divided by 3 with a remainder of 2."); } // Ternary: ``if`` - ``then`` - ``else`` in a statement. var maximum = if thisInt < thatInt then thatInt else thisInt; // ``select`` statements are much like switch statements in other languages. // However, ``select`` statements don't cascade like in C or Java. var inputOption = "anOption"; select inputOption { when "anOption" do writeln("Chose 'anOption'"); when "otherOption" { writeln("Chose 'otherOption'"); writeln("Which has a body"); } otherwise { writeln("Any other Input"); writeln("the otherwise case doesn't need a do if the body is one line"); } } // ``while`` and ``do``-``while`` loops also behave like their C counterparts. var j: int = 1; var jSum: int = 0; while (j <= 1000) { jSum += j; j += 1; } writeln(jSum); do { jSum += j; j += 1; } while (j <= 10000); writeln(jSum); // ``for`` loops are much like those in python in that they iterate over a // range. Ranges (like the ``1..10`` expression below) are a first-class object // in Chapel, and as such can be stored in variables. for i in 1..10 do write(i, ", "); writeln(); var iSum: int = 0; for i in 1..1000 { iSum += i; } writeln(iSum); for x in 1..10 { for y in 1..10 { write((x,y), "\t"); } writeln(); } /* Ranges and Domains */ // For-loops and arrays both use ranges and domains to define an index set that // can be iterated over. Ranges are single dimensional integer indices, while // domains can be multi-dimensional and represent indices of different types. // They are first-class citizen types, and can be assigned into variables. var range1to10: range = 1..10; // 1, 2, 3, ..., 10 var range2to11 = 2..11; // 2, 3, 4, ..., 11 var rangeThisToThat: range = thisInt..thatInt; // using variables var rangeEmpty: range = 100..-100; // this is valid but contains no indices // Ranges can be unbounded. var range1toInf: range(boundedType=BoundedRangeType.boundedLow) = 1.. ; // 1, 2, 3, 4, 5, ... var rangeNegInfTo1 = ..1; // ..., -4, -3, -2, -1, 0, 1 // Ranges can be strided (and reversed) using the ``by`` operator. var range2to10by2: range(stridable=true) = 2..10 by 2; // 2, 4, 6, 8, 10 var reverse2to10by2 = 2..10 by -2; // 10, 8, 6, 4, 2 var trapRange = 10..1 by -1; // Do not be fooled, this is still an empty range writeln("Size of range '", trapRange, "' = ", trapRange.size); // Note: ``range(boundedType= ...)`` and ``range(stridable= ...)`` are only // necessary if we explicitly type the variable. // The end point of a range can be computed by specifying the total size // of the range using the count (``#``) operator. var rangeCount: range = -5..#12; // range from -5 to 6 // Operators can be mixed. var rangeCountBy: range(stridable=true) = -5..#12 by 2; // -5, -3, -1, 1, 3, 5 writeln(rangeCountBy); // Properties of the range can be queried. // In this example, printing the first index, last index, number of indices, // stride, and if 2 is include in the range. writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.size, rangeCountBy.stride, rangeCountBy.contains(2))); for i in rangeCountBy { write(i, if i == rangeCountBy.last then "\n" else ", "); } // Rectangular domains are defined using the same range syntax, // but they are required to be bounded (unlike ranges). var domain1to10: domain(1) = {1..10}; // 1D domain from 1..10; var twoDimensions: domain(2) = {-2..2,0..2}; // 2D domain over product of ranges var thirdDim: range = 1..16; var threeDims: domain(3) = {thirdDim, 1..10, 5..10}; // using a range variable // Domains can also be resized var resizedDom = {1..10}; writeln("before, resizedDom = ", resizedDom); resizedDom = {-10..#10}; writeln("after, resizedDom = ", resizedDom); // Indices can be iterated over as tuples. for idx in twoDimensions do write(idx, ", "); writeln(); // These tuples can also be destructured. for (x,y) in twoDimensions { write("(", x, ", ", y, ")", ", "); } writeln(); // Associative domains act like sets. var stringSet: domain(string); // empty set of strings stringSet += "a"; stringSet += "b"; stringSet += "c"; stringSet += "a"; // Redundant add "a" stringSet -= "c"; // Remove "c" writeln(stringSet.sorted()); // Associative domains can also have a literal syntax var intSet = {1, 2, 4, 5, 100}; // Both ranges and domains can be sliced to produce a range or domain with the // intersection of indices. var rangeA = 1.. ; // range from 1 to infinity var rangeB = ..5; // range from negative infinity to 5 var rangeC = rangeA[rangeB]; // resulting range is 1..5 writeln((rangeA, rangeB, rangeC)); var domainA = {1..10, 5..20}; var domainB = {-5..5, 1..10}; var domainC = domainA[domainB]; writeln((domainA, domainB, domainC)); /* Arrays */ // Arrays are similar to those of other languages. // Their sizes are defined using domains that represent their indices. var intArray: [1..10] int; var intArray2: [{1..10}] int; // equivalent // They can be accessed using either brackets or parentheses for i in 1..10 do intArray[i] = -i; writeln(intArray); // We cannot access ``intArray[0]`` because it exists outside // of the index set, ``{1..10}``, we defined it to have. // ``intArray[11]`` is illegal for the same reason. var realDomain: domain(2) = {1..5,1..7}; var realArray: [realDomain] real; var realArray2: [1..5,1..7] real; // equivalent var realArray3: [{1..5,1..7}] real; // equivalent for i in 1..5 { for j in realDomain.dim(2) { // Only use the 2nd dimension of the domain realArray[i,j] = -1.61803 * i + 0.5 * j; // Access using index list var idx: 2*int = (i,j); // Note: 'index' is a keyword realArray[idx] = - realArray[(i,j)]; // Index using tuples } } // Arrays have domains as members, and can be iterated over as normal. for idx in realArray.domain { // Again, idx is a 2*int tuple realArray[idx] = 1 / realArray[idx[1], idx[2]]; // Access by tuple and list } writeln(realArray); // The values of an array can also be iterated directly. var rSum: real = 0; for value in realArray { rSum += value; // Read a value value = rSum; // Write a value } writeln(rSum, "\n", realArray); // Associative arrays (dictionaries) can be created using associative domains. var dictDomain: domain(string) = { "one", "two", "three"}; var dict: [dictDomain] int = ["one" => 1, "two" => 2, "three" => 3]; for key in dictDomain.sorted() do writeln(dict[key]); // Arrays can be assigned to each other in a few different ways. // These arrays will be used in the example. var thisArray : [0..5] int = [0,1,2,3,4,5]; var thatArray : [0..5] int; // First, simply assign one to the other. This copies ``thisArray`` into // ``thatArray``, instead of just creating a reference. Therefore, modifying // ``thisArray`` does not also modify ``thatArray``. thatArray = thisArray; thatArray[1] = -1; writeln((thisArray, thatArray)); // Assign a slice from one array to a slice (of the same size) in the other. thatArray[4..5] = thisArray[1..2]; writeln((thisArray, thatArray)); // Operations can also be promoted to work on arrays. 'thisPlusThat' is also // an array. var thisPlusThat = thisArray + thatArray; writeln(thisPlusThat); // Moving on, arrays and loops can also be expressions, where the loop // body's expression is the result of each iteration. var arrayFromLoop = for i in 1..10 do i; writeln(arrayFromLoop); // An expression can result in nothing, such as when filtering with an if-expression. var evensOrFives = for i in 1..10 do if (i % 2 == 0 || i % 5 == 0) then i; writeln(arrayFromLoop); // Array expressions can also be written with a bracket notation. // Note: this syntax uses the ``forall`` parallel concept discussed later. var evensOrFivesAgain = [i in 1..10] if (i % 2 == 0 || i % 5 == 0) then i; // They can also be written over the values of the array. arrayFromLoop = [value in arrayFromLoop] value + 1; /* Procedures */ // Chapel procedures have similar syntax functions in other languages. proc fibonacci(n : int) : int { if n <= 1 then return n; return fibonacci(n-1) + fibonacci(n-2); } // Input parameters can be untyped to create a generic procedure. proc doublePrint(thing): void { write(thing, " ", thing, "\n"); } // The return type can be inferred, as long as the compiler can figure it out. proc addThree(n) { return n + 3; } doublePrint(addThree(fibonacci(20))); // It is also possible to take a variable number of parameters. proc maxOf(x ...?k) { // x refers to a tuple of one type, with k elements var maximum = x[1]; for i in 2..k do maximum = if maximum < x[i] then x[i] else maximum; return maximum; } writeln(maxOf(1, -10, 189, -9071982, 5, 17, 20001, 42)); // Procedures can have default parameter values, and // the parameters can be named in the call, even out of order. proc defaultsProc(x: int, y: real = 1.2634): (int,real) { return (x,y); } writeln(defaultsProc(10)); writeln(defaultsProc(x=11)); writeln(defaultsProc(x=12, y=5.432)); writeln(defaultsProc(y=9.876, x=13)); // The ``?`` operator is called the query operator, and is used to take // undetermined values like tuple or array sizes and generic types. // For example, taking arrays as parameters. The query operator is used to // determine the domain of ``A``. This is useful for defining the return type, // though it's not required. proc invertArray(A: [?D] int): [D] int{ for a in A do a = -a; return A; } writeln(invertArray(intArray)); // We can query the type of arguments to generic procedures. // Here we define a procedure that takes two arguments of // the same type, yet we don't define what that type is. proc genericProc(arg1 : ?valueType, arg2 : valueType): void { select(valueType) { when int do writeln(arg1, " and ", arg2, " are ints"); when real do writeln(arg1, " and ", arg2, " are reals"); otherwise writeln(arg1, " and ", arg2, " are somethings!"); } } genericProc(1, 2); genericProc(1.2, 2.3); genericProc(1.0+2.0i, 3.0+4.0i); // We can also enforce a form of polymorphism with the ``where`` clause // This allows the compiler to decide which function to use. // Note: That means that all information needs to be known at compile-time. // The param modifier on the arg is used to enforce this constraint. proc whereProc(param N : int): void where (N > 0) { writeln("N is greater than 0"); } proc whereProc(param N : int): void where (N < 0) { writeln("N is less than 0"); } whereProc(10); whereProc(-1); // ``whereProc(0)`` would result in a compiler error because there // are no functions that satisfy the ``where`` clause's condition. // We could have defined a ``whereProc`` without a ``where`` clause // that would then have served as a catch all for all the other cases // (of which there is only one). // ``where`` clauses can also be used to constrain based on argument type. proc whereType(x: ?t) where t == int { writeln("Inside 'int' version of 'whereType': ", x); } proc whereType(x: ?t) { writeln("Inside general version of 'whereType': ", x); } whereType(42); whereType("hello"); /* Intents */ /* Intent modifiers on the arguments convey how those arguments are passed to the procedure. * in: copy arg in, but not out * out: copy arg out, but not in * inout: copy arg in, copy arg out * ref: pass arg by reference */ proc intentsProc(in inarg, out outarg, inout inoutarg, ref refarg) { writeln("Inside Before: ", (inarg, outarg, inoutarg, refarg)); inarg = inarg + 100; outarg = outarg + 100; inoutarg = inoutarg + 100; refarg = refarg + 100; writeln("Inside After: ", (inarg, outarg, inoutarg, refarg)); } var inVar: int = 1; var outVar: int = 2; var inoutVar: int = 3; var refVar: int = 4; writeln("Outside Before: ", (inVar, outVar, inoutVar, refVar)); intentsProc(inVar, outVar, inoutVar, refVar); writeln("Outside After: ", (inVar, outVar, inoutVar, refVar)); // Similarly, we can define intents on the return type. // ``refElement`` returns a reference to an element of array. // This makes more practical sense for class methods where references to // elements in a data-structure are returned via a method or iterator. proc refElement(array : [?D] ?T, idx) ref : T { return array[idx]; } var myChangingArray : [1..5] int = [1,2,3,4,5]; writeln(myChangingArray); ref refToElem = refElement(myChangingArray, 5); // store reference to element in ref variable writeln(refToElem); refToElem = -2; // modify reference which modifies actual value in array writeln(refToElem); writeln(myChangingArray); /* Operator Definitions */ // Chapel allows for operators to be overloaded. // We can define the unary operators: // ``+ - ! ~`` // and the binary operators: // ``+ - * / % ** == <= >= < > << >> & | ˆ by`` // ``+= -= *= /= %= **= &= |= ˆ= <<= >>= <=>`` // Boolean exclusive or operator. proc ^(left : bool, right : bool): bool { return (left || right) && !(left && right); } writeln(true ^ true); writeln(false ^ true); writeln(true ^ false); writeln(false ^ false); // Define a ``*`` operator on any two types that returns a tuple of those types. proc *(left : ?ltype, right : ?rtype): (ltype, rtype) { writeln("\tIn our '*' overload!"); return (left, right); } writeln(1 * "a"); // Uses our ``*`` operator. writeln(1 * 2); // Uses the default ``*`` operator. // Note: You could break everything if you get careless with your overloads. // This here will break everything. Don't do it. /* proc +(left: int, right: int): int { return left - right; } */ /* Iterators */ // Iterators are sisters to the procedure, and almost everything about // procedures also applies to iterators. However, instead of returning a single // value, iterators may yield multiple values to a loop. // // This is useful when a complicated set or order of iterations is needed, as // it allows the code defining the iterations to be separate from the loop // body. iter oddsThenEvens(N: int): int { for i in 1..N by 2 do yield i; // yield values instead of returning. for i in 2..N by 2 do yield i; } for i in oddsThenEvens(10) do write(i, ", "); writeln(); // Iterators can also yield conditionally, the result of which can be nothing iter absolutelyNothing(N): int { for i in 1..N { if N < i { // Always false yield i; // Yield statement never happens } } } for i in absolutelyNothing(10) { writeln("Woa there! absolutelyNothing yielded ", i); } // We can zipper together two or more iterators (who have the same number // of iterations) using ``zip()`` to create a single zipped iterator, where each // iteration of the zipped iterator yields a tuple of one value yielded // from each iterator. for (positive, negative) in zip(1..5, -5..-1) do writeln((positive, negative)); // Zipper iteration is quite important in the assignment of arrays, // slices of arrays, and array/loop expressions. var fromThatArray : [1..#5] int = [1,2,3,4,5]; var toThisArray : [100..#5] int; // Some zipper operations implement other operations. // The first statement and the loop are equivalent. toThisArray = fromThatArray; for (i,j) in zip(toThisArray.domain, fromThatArray.domain) { toThisArray[i] = fromThatArray[j]; } // These two chunks are also equivalent. toThisArray = [j in -100..#5] j; writeln(toThisArray); for (i, j) in zip(toThisArray.domain, -100..#5) { toThisArray[i] = j; } writeln(toThisArray); // This is very important in understanding why this statement exhibits a runtime error. /* var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i; */ // Even though the domain of the array and the loop-expression are // the same size, the body of the expression can be thought of as an iterator. // Because iterators can yield nothing, that iterator yields a different number // of things than the domain of the array or loop, which is not allowed. /* Classes */ // Classes are similar to those in C++ and Java, allocated on the heap. class MyClass { // Member variables var memberInt : int; var memberBool : bool = true; // By default, any class that doesn't define an initializer gets a // compiler-generated initializer, with one argument per field and // the field's initial value as the argument's default value. // Alternatively, the user can define initializers manually as shown // in the following commented-out routine: // /* // proc init(val : real) { // this.memberInt = ceil(val): int; // } */ // Explicitly defined deinitializer. // If we did not write one, we would get the compiler-generated deinitializer, // which has an empty body. proc deinit() { writeln("MyClass deinitializer called ", (this.memberInt, this.memberBool)); } // Class methods. proc setMemberInt(val: int) { this.memberInt = val; } proc setMemberBool(val: bool) { this.memberBool = val; } proc getMemberInt(): int{ return this.memberInt; } proc getMemberBool(): bool { return this.memberBool; } } // end MyClass // Call compiler-generated initializer, using default value for memberBool. { var myObject = new owned MyClass(10); myObject = new owned MyClass(memberInt = 10); // Equivalent writeln(myObject.getMemberInt()); // Same, but provide a memberBool value explicitly. var myDiffObject = new owned MyClass(-1, true); myDiffObject = new owned MyClass(memberInt = -1, memberBool = true); // Equivalent writeln(myDiffObject); // Similar, but rely on the default value of memberInt, passing in memberBool. var myThirdObject = new owned MyClass(memberBool = true); writeln(myThirdObject); // If the user-defined initializer above had been uncommented, we could // make the following calls: // /* // var myOtherObject = new MyClass(1.95); // myOtherObject = new MyClass(val = 1.95); // writeln(myOtherObject.getMemberInt()); */ // We can define an operator on our class as well, but // the definition has to be outside the class definition. proc +(A : MyClass, B : MyClass) : owned MyClass { return new owned MyClass(memberInt = A.getMemberInt() + B.getMemberInt(), memberBool = A.getMemberBool() || B.getMemberBool()); } var plusObject = myObject + myDiffObject; writeln(plusObject); // Destruction of an object: calls the deinit() routine and frees its memory. // ``unmanaged`` variables should have ``delete`` called on them. // ``owned`` variables are destroyed when they go out of scope. } // Classes can inherit from one or more parent classes class MyChildClass : MyClass { var memberComplex: complex; } // Here's an example of generic classes. class GenericClass { type classType; var classDomain: domain(1); var classArray: [classDomain] classType; // Explicit initializer. proc init(type classType, elements : int) { this.classType = classType; this.classDomain = {1..elements}; // all generic and const fields must be initialized in "phase 1" prior // to a call to the superclass initializer. } // Copy-style initializer. // Note: We include a type argument whose default is the type of the first // argument. This lets our initializer copy classes of different // types and cast on the fly. proc init(other : GenericClass(?), type classType = other.classType) { this.classType = classType; this.classDomain = other.classDomain; this.classArray = for o in other do o: classType; // copy and cast } // Define bracket notation on a GenericClass // object so it can behave like a normal array // i.e. ``objVar[i]`` or ``objVar(i)`` proc this(i : int) ref : classType { return this.classArray[i]; } // Define an implicit iterator for the class // to yield values from the array to a loop // i.e. ``for i in objVar do ...`` iter these() ref : classType { for i in this.classDomain do yield this[i]; } } // end GenericClass // Allocate an owned instance of our class var realList = new owned GenericClass(real, 10); // We can assign to the member array of the object using the bracket // notation that we defined. for i in realList.classDomain do realList[i] = i + 1.0; // We can iterate over the values in our list with the iterator // we defined. for value in realList do write(value, ", "); writeln(); // Make a copy of realList using the copy initializer. var copyList = new owned GenericClass(realList); for value in copyList do write(value, ", "); writeln(); // Make a copy of realList and change the type, also using the copy initializer. var copyNewTypeList = new owned GenericClass(realList, int); for value in copyNewTypeList do write(value, ", "); writeln(); /* Modules */ // Modules are Chapel's way of managing name spaces. // The files containing these modules do not need to be named after the modules // (as in Java), but files implicitly name modules. // For example, this file implicitly names the ``learnChapelInYMinutes`` module module OurModule { // We can use modules inside of other modules. // Time is one of the standard modules. use Time; // We'll use this procedure in the parallelism section. proc countdown(seconds: int) { for i in 1..seconds by -1 { writeln(i); sleep(1); } } // It is possible to create arbitrarily deep module nests. // i.e. submodules of OurModule module ChildModule { proc foo() { writeln("ChildModule.foo()"); } } module SiblingModule { proc foo() { writeln("SiblingModule.foo()"); } } } // end OurModule // Using ``OurModule`` also uses all the modules it uses. // Since ``OurModule`` uses ``Time``, we also use ``Time``. use OurModule; // At this point we have not used ``ChildModule`` or ``SiblingModule`` so // their symbols (i.e. ``foo``) are not available to us. However, the module // names are available, and we can explicitly call ``foo()`` through them. SiblingModule.foo(); OurModule.ChildModule.foo(); // Now we use ``ChildModule``, enabling unqualified calls. use ChildModule; foo(); /* Parallelism */ // In other languages, parallelism is typically done with // complicated libraries and strange class structure hierarchies. // Chapel has it baked right into the language. // We can declare a main procedure, but all the code above main still gets // executed. proc main() { // A ``begin`` statement will spin the body of that statement off // into one new task. // A ``sync`` statement will ensure that the progress of the main // task will not progress until the children have synced back up. sync { begin { // Start of new task's body var a = 0; for i in 1..1000 do a += 1; writeln("Done: ", a); } // End of new tasks body writeln("spun off a task!"); } writeln("Back together"); proc printFibb(n: int) { writeln("fibonacci(",n,") = ", fibonacci(n)); } // A ``cobegin`` statement will spin each statement of the body into one new // task. Notice here that the prints from each statement may happen in any // order. cobegin { printFibb(20); // new task printFibb(10); // new task printFibb(5); // new task { // This is a nested statement body and thus is a single statement // to the parent statement, executed by a single task. writeln("this gets"); writeln("executed as"); writeln("a whole"); } } // A ``coforall`` loop will create a new task for EACH iteration. // Again we see that prints happen in any order. // NOTE: ``coforall`` should be used only for creating tasks! // Using it to iterating over a structure is very a bad idea! var num_tasks = 10; // Number of tasks we want coforall taskID in 1..num_tasks { writeln("Hello from task# ", taskID); } // ``forall`` loops are another parallel loop, but only create a smaller number // of tasks, specifically ``--dataParTasksPerLocale=`` number of tasks. forall i in 1..100 { write(i, ", "); } writeln(); // Here we see that there are sections that are in order, followed by // a section that would not follow (e.g. 1, 2, 3, 7, 8, 9, 4, 5, 6,). // This is because each task is taking on a chunk of the range 1..10 // (1..3, 4..6, or 7..9) doing that chunk serially, but each task happens // in parallel. Your results may depend on your machine and configuration // For both the ``forall`` and ``coforall`` loops, the execution of the // parent task will not continue until all the children sync up. // ``forall`` loops are particularly useful for parallel iteration over arrays. // Lets run an experiment to see how much faster a parallel loop is use Time; // Import the Time module to use Timer objects var timer: Timer; var myBigArray: [{1..4000,1..4000}] real; // Large array we will write into // Serial Experiment: timer.start(); // Start timer for (x,y) in myBigArray.domain { // Serial iteration myBigArray[x,y] = (x:real) / (y:real); } timer.stop(); // Stop timer writeln("Serial: ", timer.elapsed()); // Print elapsed time timer.clear(); // Clear timer for parallel loop // Parallel Experiment: timer.start(); // start timer forall (x,y) in myBigArray.domain { // Parallel iteration myBigArray[x,y] = (x:real) / (y:real); } timer.stop(); // Stop timer writeln("Parallel: ", timer.elapsed()); // Print elapsed time timer.clear(); // You may have noticed that (depending on how many cores you have) // the parallel loop went faster than the serial loop. // The bracket style loop-expression described // much earlier implicitly uses a ``forall`` loop. [val in myBigArray] val = 1 / val; // Parallel operation // Atomic variables, common to many languages, are ones whose operations // occur uninterrupted. Multiple threads can therefore modify atomic // variables and can know that their values are safe. // Chapel atomic variables can be of type ``bool``, ``int``, // ``uint``, and ``real``. var uranium: atomic int; uranium.write(238); // atomically write a variable writeln(uranium.read()); // atomically read a variable // Atomic operations are described as functions, so you can define your own. uranium.sub(3); // atomically subtract a variable writeln(uranium.read()); var replaceWith = 239; var was = uranium.exchange(replaceWith); writeln("uranium was ", was, " but is now ", replaceWith); var isEqualTo = 235; if uranium.compareAndSwap(isEqualTo, replaceWith) { writeln("uranium was equal to ", isEqualTo, " so replaced value with ", replaceWith); } else { writeln("uranium was not equal to ", isEqualTo, " so value stays the same... whatever it was"); } sync { begin { // Reader task writeln("Reader: waiting for uranium to be ", isEqualTo); uranium.waitFor(isEqualTo); writeln("Reader: uranium was set (by someone) to ", isEqualTo); } begin { // Writer task writeln("Writer: will set uranium to the value ", isEqualTo, " in..."); countdown(3); uranium.write(isEqualTo); } } // ``sync`` variables have two states: empty and full. // If you read an empty variable or write a full variable, you are waited // until the variable is full or empty again. var someSyncVar$: sync int; // varName$ is a convention not a law. sync { begin { // Reader task writeln("Reader: waiting to read."); var read_sync = someSyncVar$; writeln("Reader: value is ", read_sync); } begin { // Writer task writeln("Writer: will write in..."); countdown(3); someSyncVar$ = 123; } } // ``single`` vars can only be written once. A read on an unwritten ``single`` // results in a wait, but when the variable has a value it can be read indefinitely. var someSingleVar$: single int; // varName$ is a convention not a law. sync { begin { // Reader task writeln("Reader: waiting to read."); for i in 1..5 { var read_single = someSingleVar$; writeln("Reader: iteration ", i,", and the value is ", read_single); } } begin { // Writer task writeln("Writer: will write in..."); countdown(3); someSingleVar$ = 5; // first and only write ever. } } // Here's an example using atomics and a ``sync`` variable to create a // count-down mutex (also known as a multiplexer). var count: atomic int; // our counter var lock$: sync bool; // the mutex lock count.write(2); // Only let two tasks in at a time. lock$.writeXF(true); // Set lock$ to full (unlocked) // Note: The value doesn't actually matter, just the state // (full:unlocked / empty:locked) // Also, writeXF() fills (F) the sync var regardless of its state (X) coforall task in 1..5 { // Generate tasks // Create a barrier do { lock$; // Read lock$ (wait) } while (count.read() < 1); // Keep waiting until a spot opens up count.sub(1); // decrement the counter lock$.writeXF(true); // Set lock$ to full (signal) // Actual 'work' writeln("Task #", task, " doing work."); sleep(2); count.add(1); // Increment the counter lock$.writeXF(true); // Set lock$ to full (signal) } // We can define the operations ``+ * & | ^ && || min max minloc maxloc`` // over an entire array using scans and reductions. // Reductions apply the operation over the entire array and // result in a scalar value. var listOfValues: [1..10] int = [15,57,354,36,45,15,456,8,678,2]; var sumOfValues = + reduce listOfValues; var maxValue = max reduce listOfValues; // 'max' give just max value // ``maxloc`` gives max value and index of the max value. // Note: We have to zip the array and domain together with the zip iterator. var (theMaxValue, idxOfMax) = maxloc reduce zip(listOfValues, listOfValues.domain); writeln((sumOfValues, maxValue, idxOfMax, listOfValues[idxOfMax])); // Scans apply the operation incrementally and return an array with the // values of the operation at that index as it progressed through the // array from ``array.domain.low`` to ``array.domain.high``. var runningSumOfValues = + scan listOfValues; var maxScan = max scan listOfValues; writeln(runningSumOfValues); writeln(maxScan); } // end main() ``` ## Who is this tutorial for? This tutorial is for people who want to learn the ropes of chapel without having to hear about what fiber mixture the ropes are, or how they were braided, or how the braid configurations differ between one another. It won't teach you how to develop amazingly performant code, and it's not exhaustive. Refer to the [language specification](https://chapel-lang.org/docs/latest/language/spec.html) and the [module documentation](https://chapel-lang.org/docs/latest/) for more details. Occasionally check back here and on the [Chapel site](https://chapel-lang.org) to see if more topics have been added or more tutorials created. ### What this tutorial is lacking: * Exposition of the [standard modules](https://chapel-lang.org/docs/latest/modules/standard.html) * Multiple Locales (distributed memory system) * Records * Parallel iterators ## Your input, questions, and discoveries are important to the developers! The Chapel language is still in active development, so there are occasional hiccups with performance and language features. The more information you give the Chapel development team about issues you encounter or features you would like to see, the better the language becomes. There are several ways to interact with the developers: * [Gitter chat](https://gitter.im/chapel-lang/chapel) * [sourceforge email lists](https://sourceforge.net/p/chapel/mailman) If you're really interested in the development of the compiler or contributing to the project, [check out the master GitHub repository](https://github.com/chapel-lang/chapel). It is under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0). ## Installing the Compiler [The Official Chapel documentation details how to download and compile the Chapel compiler.](https://chapel-lang.org/docs/usingchapel/QUICKSTART.html) Chapel can be built and installed on your average 'nix machine (and cygwin). [Download the latest release version](https://github.com/chapel-lang/chapel/releases/) and it's as easy as 1. `tar -xvf chapel-.tar.gz` 2. `cd chapel-` 3. `source util/setchplenv.bash # or .sh or .csh or .fish` 4. `make` 5. `make check # optional` You will need to `source util/setchplenv.EXT` from within the Chapel directory (`$CHPL_HOME`) every time your terminal starts so it's suggested that you drop that command in a script that will get executed on startup (like .bashrc). Chapel is easily installed on macOS with Homebrew 1. `brew update` 2. `brew install chapel` ## Compiling Code Builds like other compilers: `chpl myFile.chpl -o myExe` Notable arguments: * `--fast`: enables a number of optimizations and disables array bounds checks. Should only enable when application is stable. * `--set =`: set config param `` to `` at compile-time. * `--main-module `: use the main() procedure found in the module `` as the executable's main. * `--module-dir `: includes `` in the module search path. ================================================ FILE: chicken.md ================================================ --- name: "CHICKEN" filename: CHICKEN.scm contributors: - ["Diwakar Wagle", "https://github.com/deewakar"] --- CHICKEN is an implementation of Scheme programming language that can compile Scheme programs to C code as well as interpret them. CHICKEN supports R5RS and R7RS (work in progress) standards and many extensions. ```scheme ;; #!/usr/bin/env csi -s ;; Run the CHICKEN REPL in the commandline as follows : ;; $ csi ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 0. Syntax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Single line comments start with a semicolon #| Block comments can span multiple lines and... #| can be nested |# |# ;; S-expression comments are used to comment out expressions #; (display "nothing") ; discard this expression ;; CHICKEN has two fundamental pieces of syntax: Atoms and S-expressions ;; an atom is something that evaluates to itself ;; all builtin data types viz. numbers, chars, booleans, strings etc. are atoms ;; Furthermore an atom can be a symbol, an identifier, a keyword, a procedure ;; or the empty list (also called null) 'athing ;; => athing '+ ;; => + + ;; => ;; S-expressions (short for symbolic expressions) consists of one or more atoms (quote +) ;; => + ; another way of writing '+ (+ 1 2 3) ;; => 6 ; this S-expression evaluates to a function call '(+ 1 2 3) ;; => (+ 1 2 3) ; evaluates to a list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 1. Primitive Datatypes and Operators ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Numbers 99999999999999999999 ;; integers #b1010 ;; binary ; => 10 #o10 ;; octal ; => 8 #x8ded ;; hexadecimal ; => 36333 3.14 ;; real 6.02e+23 3/4 ;; rational ;;Characters and Strings #\A ;; A char "Hello, World!" ;; strings are fixed-length arrays of characters ;; Booleans #t ;; true #f ;; false ;; Function call is written as (f x y z ...) ;; where f is a function and x,y,z, ... are arguments (print "Hello, World!") ;; => Hello, World! ;; formatted output (printf "Hello, ~a.\n" "World") ;; => Hello, World. ;; print commandline arguments (map print (command-line-arguments)) (list 'foo 'bar 'baz) ;; => (foo bar baz) (string-append "pine" "apple") ;; => "pineapple" (string-ref "tapioca" 3) ;; => #\i;; character 'i' is at index 3 (string->list "CHICKEN") ;; => (#\C #\H #\I #\C #\K #\E #\N) (string-intersperse '("1" "2") ":") ;; => "1:2" (string-split "1:2:3" ":") ;; => ("1" "2" "3") ;; Predicates are special functions that return boolean values (atom? #t) ;; => #t (symbol? #t) ;; => #f (symbol? '+) ;; => #t (procedure? +) ;; => #t (pair? '(1 2)) ;; => #t (pair? '(1 2 . 3)) ;; => #t (pair? '()) ;; => #f (list? '()) ;; => #t ;; Some arithmetic operations (+ 1 1) ;; => 2 (- 8 1) ;; => 7 (* 10 2) ;; => 20 (expt 2 3) ;; => 8 (remainder 5 2) ;; => 1 (/ 35 5) ;; => 7 (/ 1 3) ;; => 0.333333333333333 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 2. Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; You can create variables with define ;; A variable name can use any character except: ()[]{}",'`;#\ (define myvar 5) myvar ;; => 5 ;; Alias to a procedure (define ** expt) (** 2 3) ;; => 8 ;; Accessing an undefined variable raises an exception s ;; => Error: unbound variable: s ;; Local binding (let ((me "Bob")) (print me)) ;; => Bob (print me) ;; => Error: unbound variable: me ;; Assign a new value to previously defined variable (set! myvar 10) myvar ;; => 10 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 3. Collections ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Pairs ;; 'cons' constructs pairs, ;; 'car' extracts the first element, 'cdr' extracts the rest of the elements (cons 'subject 'verb) ;; => '(subject . verb) (car (cons 'subject 'verb)) ;; => subject (cdr (cons 'subject 'verb)) ;; => verb ;; Lists ;; cons creates a new list if the second item is a list (cons 0 '()) ;; => (0) (cons 1 (cons 2 (cons 3 '()))) ;; => (1 2 3) ;; 'list' is a convenience variadic constructor for lists (list 1 2 3) ;; => (1 2 3) ;; Use 'append' to append lists together (append '(1 2) '(3 4)) ;; => (1 2 3 4) ;; Some basic operations on lists (map add1 '(1 2 3)) ;; => (2 3 4) (reverse '(1 3 4 7)) ;; => (7 4 3 1) (sort '(11 22 33 44) >) ;; => (44 33 22 11) (define days '(SUN MON FRI)) (list-ref days 1) ;; => MON (set! (list-ref days 1) 'TUE) days ;; => (SUN TUE FRI) ;; Vectors ;; Vectors are heterogeneous structures whose elements are indexed by integers ;; A Vector typically occupies less space than a list of the same length ;; Random access of an element in a vector is faster than in a list #(1 2 3) ;; => #(1 2 3) ;; literal syntax (vector 'a 'b 'c) ;; => #(a b c) (vector? #(1 2 3)) ;; => #t (vector-length #(1 (2) "a")) ;; => 3 (vector-ref #(1 (2) (3 3)) 2);; => (3 3) (define vec #(1 2 3)) (vector-set! vec 2 4) vec ;; => #(1 2 4) ;; Vectors can be created from lists and vice-verca (vector->list #(1 2 4)) ;; => '(1 2 4) (list->vector '(a b c)) ;; => #(a b c) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 4. Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Use 'lambda' to create functions. ;; A function always returns the value of its last expression (lambda () "Hello World") ;; => # ;; Use extra parens around function definition to execute ((lambda () "Hello World")) ;; => Hello World ;; argument list is empty ;; A function with an argument ((lambda (x) (* x x)) 3) ;; => 9 ;; A function with two arguments ((lambda (x y) (* x y)) 2 3) ;; => 6 ;; assign a function to a variable (define sqr (lambda (x) (* x x))) sqr ;; => # (sqr 3) ;; => 9 ;; We can shorten this using the function definition syntactic sugar (define (sqr x) (* x x)) (sqr 3) ;; => 9 ;; We can redefine existing procedures (foldl cons '() '(1 2 3 4 5)) ;; => (((((() . 1) . 2) . 3) . 4) . 5) (define (foldl func accu alist) (if (null? alist) accu (foldl func (func (car alist) accu) (cdr alist)))) (foldl cons '() '(1 2 3 4 5)) ;; => (5 4 3 2 1) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 5. Equality ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; For numbers use '=' (= 3 3.0) ;; => #t (= 2 1) ;; => #f ;; 'eq?' returns #t if two arguments refer to the same object in memory ;; In other words, it's a simple pointer comparison. (eq? '() '()) ;; => #t ;; there's only one empty list in memory (eq? (list 3) (list 3)) ;; => #f ;; not the same object (eq? 'yes 'yes) ;; => #t (eq? 3 3) ;; => #t ;; don't do this even if it works in this case (eq? 3 3.0) ;; => #f ;; it's better to use '=' for number comparisons (eq? "Hello" "Hello") ;; => #f ;; 'eqv?' is same as 'eq?' all datatypes except numbers and characters (eqv? 3 3.0) ;; => #f (eqv? (expt 2 3) (expt 2 3)) ;; => #t (eqv? 'yes 'yes) ;; => #t ;; 'equal?' recursively compares the contents of pairs, vectors, and strings, ;; applying eqv? on other objects such as numbers and symbols. ;; A rule of thumb is that objects are generally equal? if they print the same. (equal? '(1 2 3) '(1 2 3)) ;; => #t (equal? #(a b c) #(a b c)) ;; => #t (equal? 'a 'a) ;; => #t (equal? "abc" "abc") ;; => #t ;; In Summary: ;; eq? tests if objects are identical ;; eqv? tests if objects are operationally equivalent ;; equal? tests if objects have same structure and contents ;; Comparing strings for equality (string=? "Hello" "Hello") ;; => #t ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 6. Control Flow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Conditionals (if #t ;; test expression "True" ;; then expression "False") ;; else expression ;; => "True" (if (> 3 2) "yes" "no") ;; => "yes" ;; In conditionals, all values that are not '#f' are treated as true. ;; 0, '(), #() "" , are all true values (if 0 "0 is not false" "0 is false") ;; => "0 is not false" ;; 'cond' chains a series of tests and returns as soon as it encounters a true condition ;; 'cond' can be used to simulate 'if/elseif/else' statements (cond ((> 2 2) "not true so don't return this") ((< 2 5) "true, so return this") (else "returning default")) ;; => "true, so return this" ;; A case expression is evaluated as follows: ;; The key is evaluated and compared with each datum in sense of 'eqv?', ;; The corresponding clause in the matching datum is evaluated and returned as result (case (* 2 3) ;; the key is 6 ((2 3 5 7) 'prime) ;; datum 1 ((1 4 6 8) 'composite)) ;; datum 2; matched! ;; => composite ;; case with else clause (case (car '(c d)) ((a e i o u) 'vowel) ((w y) 'semivowel) (else 'consonant)) ;; => consonant ;; Boolean expressions ;; 'and' returns the first expression that evaluates to #f ;; otherwise, it returns the result of the last expression (and #t #f (= 2 2.0)) ;; => #f (and (< 2 5) (> 2 0) "0 < 2 < 5") ;; => "0 < 2 < 5" ;; 'or' returns the first expression that evaluates to #t ;; otherwise the result of the last expression is returned (or #f #t #f) ;; => #t (or #f #f #f) ;; => #f ;; 'when' is like 'if' without the else expression (when (positive? 5) "I'm positive") ;; => "I'm positive" ;; 'unless' is equivalent to (when (not ) ) (unless (null? '(1 2 3)) "not null") ;; => "not null" ;; Loops ;; loops can be created with the help of tail-recursions (define (loop count) (unless (= count 0) (print "hello") (loop (sub1 count)))) (loop 4) ;; => hello, hello ... ;; Or with a named let (let loop ((i 0) (limit 5)) (when (< i limit) (printf "i = ~a\n" i) (loop (add1 i) limit))) ;; => i = 0, i = 1.... ;; 'do' is another iteration construct ;; It initializes a set of variables and updates them in each iteration ;; A final expression is evaluated after the exit condition is met (do ((x 0 (add1 x ))) ;; initialize x = 0 and add 1 in each iteration ((= x 10) (print "done")) ;; exit condition and final expression (print x)) ;; command to execute in each step ;; => 0,1,2,3....9,done ;; Iteration over lists (for-each (lambda (a) (print (* a a))) '(3 5 7)) ;; => 9, 25, 49 ;; 'map' is like for-each but returns a list (map add1 '(11 22 33)) ;; => (12 23 34) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 7. Extensions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The CHICKEN core is very minimal, but additional features are provided by library extensions known as Eggs. ;; You can install Eggs with 'chicken-install ' command. ;; complex numbers 3+4i ;; => 3+2i ;; Supports fractions without falling back to inexact flonums 1/3 ;; => 1/3 ;; provides support for large integers through bignums (expt 9 20) ;; => 12157665459056928801 ;; And other 'extended' functions (log 10 (exp 1)) ;; => 2.30258509299405 (numerator 2/3) ;; => 2 ;; 'utf8' provides unicode support (import utf8) "\u03BBx:(\u03BC\u0251.\u0251\u2192\u0251).xx" ;; => "λx:(μɑ.ɑ→ɑ).xx" ;; 'posix' provides file I/O and lots of other services for unix-like operating systems ;; Some of the functions are not available in Windows system, ;; See http://wiki.call-cc.org/man/5/Module%20(chicken%20file%20posix) for more details ;; Open a file to append, open "write only" and create file if it does not exist (define outfn (file-open "chicken-hen.txt" (+ open/append open/wronly open/creat))) ;; write some text to the file (file-write outfn "Did chicken came before hen?") ;; close the file (file-close outfn) ;; Open the file "read only" (define infn (file-open "chicken-hen.txt" open/rdonly)) ;; read some text from the file (file-read infn 30) ;; => ("Did chicken came before hen? ", 28) (file-close infn) ;; CHICKEN also supports SRFI (Scheme Requests For Implementation) extensions ;; See 'http://srfi.schemers.org/srfi-implementers.html" to see srfi's supported by CHICKEN (import srfi-1) ;; list library (filter odd? '(1 2 3 4 5 6 7)) ;; => (1 3 5 7) (count even? '(1 2 3 4 5)) ;; => 2 (take '(12 24 36 48 60) 3) ;; => (12 24 36) (drop '(12 24 36 48 60) 2) ;; => (36 48 60) (circular-list 'z 'q) ;; => z q z q ... (import srfi-13) ;; string library (string-reverse "pan") ;; => "nap" (string-index "Turkey" #\k) ;; => 3 (string-every char-upper-case? "CHICKEN") ;; => #t (string-join '("foo" "bar" "baz") ":") ;; => "foo:bar:baz" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 8. Macros ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; A 'for .. in ..' iteration like python, for lists (define-syntax for (syntax-rules (in) ((for elem in alist body ...) (for-each (lambda (elem) body ...) alist)))) (for x in '(2 4 8 16) (print x)) ;; => 2, 4, 8, 16 (for chr in (string->list "PENCHANT") (print chr)) ;; => P, E, N, C, H, A, N, T ;; While loop (define-syntax while (syntax-rules () ((while cond body ...) (let loop () (when cond body ... (loop)))))) (let ((str "PENCHANT") (i 0)) (while (< i (string-length str)) ;; while (condition) (print (string-ref str i)) ;; body (set! i (add1 i)))) ;; => P, E, N, C, H, A, N, T ;; Advanced Syntax-Rules Primer -> http://petrofsky.org/src/primer.txt ;; Macro system in chicken -> http://lists.gnu.org/archive/html/chicken-users/2008-04/msg00013.html ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 9. Modules ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Also See http://wiki.call-cc.org/man/5/Modules ;; The 'test' module exports a value named 'hello' and a macro named 'greet' (module test (hello greet) (import scheme) (define-syntax greet (syntax-rules () ((_ whom) (begin (display "Hello, ") (display whom) (display " !\n") ) ) ) ) (define (hello) (greet "world") ) ) ;; we can define our modules in a separate file (say test.scm) and load them to the interpreter with ;; (load "test.scm") ;; import the module (import test) (hello) ;; => Hello, world ! (greet "schemers") ;; => Hello, schemers ! ;; We can compile the module files in to shared libraries by using following command, ;; csc -s test.scm ;; (load "test.so") ;; Functors ;; Functors are high level modules that can be parameterized by other modules ;; Following functor requires another module named 'M' that provides a function called 'multiply' ;; The functor itself exports a generic function 'square' (functor (squaring-functor (M (multiply))) (square) (import scheme M) (define (square x) (multiply x x))) ;; Module 'nums' can be passed as a parameter to 'squaring-functor' (module nums (multiply) (import scheme) ;; predefined modules (define (multiply x y) (* x y))) ;; the final module can be imported and used in our program (module number-squarer = (squaring-functor nums)) (import number-squarer) (square 3) ;; => 9 ;; We can instantiate the functor for other inputs ;; Here's another example module that can be passed to squaring-functor (module stars (multiply) (import chicken scheme) ;; chicken module for the 'use' keyword (use srfi-1) ;; we can use external libraries in our module (define (multiply x y) (list-tabulate x (lambda _ (list-tabulate y (lambda _ '*)))))) (module star-squarer = (squaring-functor stars)) (import star-squarer) (square 3) ;; => ((* * *)(* * *)(* * *)) ``` ## Further Reading * [CHICKEN User's Manual](https://wiki.call-cc.org/manual). * [R5RS standards](http://www.schemers.org/Documents/Standards/R5RS) ## Extra Info * [For programmers of other languages](https://wiki.call-cc.org/chicken-for-programmers-of-other-languages) * [Compare CHICKEN syntax with other languages](http://plr.sourceforge.net/cgi-bin/plr/launch.py) ================================================ FILE: citron.md ================================================ --- name: citron filename: learncitron.ctr contributors: - ["AnotherTest", ""] --- ```ruby # Comments start with a '#' # All comments encompass a single line ########################################### ## 1. Primitive Data types and Operators ########################################### # You have numbers 3. # 3 # Numbers are all doubles in interpreted mode # Mathematical operator precedence is not respected. # binary 'operators' are evaluated in ltr order 1 + 1. # 2 8 - 4. # 4 10 + 2 * 3. # 36 # Division is always floating division 35 / 2 # 17.5. # Integer division is non-trivial, you may use floor (35 / 2) floor # 17. # Booleans are primitives True. False. # Boolean messages True not. # False False not. # True 1 = 1. # True 1 !=: 1. # False 1 < 10. # True # Here, `not` is a unary message to the object `Boolean` # Messages are comparable to instance method calls # And they have three different forms: # 1. Unary messages: Length > 1, and they take no arguments: False not. # 2. Binary Messages: Length = 1, and they take a single argument: False & True. # 3. Keyword messages: must have at least one ':', they take as many arguments # as they have `:` s False either: 1 or: 2. # 2 # Strings 'This is a string'. 'There are no character types exposed to the user'. # "You cannot use double quotes for strings" <- Error # Strins can be summed 'Hello, ' + 'World!'. # 'Hello, World!' # Strings allow access to their characters 'This is a beautiful string' at: 0. # 'T' ########################################### ## intermission: Basic Assignment ########################################### # You may assign values to the current scope: var name is value. # assigns `value` into `name` # You may also assign values into the current object's namespace my name is value. # assigns `value` into the current object's `name` property # Please note that these names are checked at compile (read parse if in interpreted mode) time # but you may treat them as dynamic assignments anyway ########################################### ## 2. Lists(Arrays?) and Tuples ########################################### # Arrays are allowed to have multiple types Array new < 1 ; 2 ; 'string' ; Nil. # Array new < 1 ; 2 ; 'string' ; Nil # Tuples act like arrays, but are immutable. # Any shenanigans degrade them to arrays, however [1, 2, 'string']. # [1, 2, 'string'] # They can interoperate with arrays [1, 'string'] + (Array new < 'wat'). # Array new < 1 ; 'string' ; 'wat' # Indexing into them [1, 2, 3] at: 1. # 2 # Some array operations var arr is Array new < 1 ; 2 ; 3. arr head. # 1 arr tail. # Array new < 2 ; 3. arr init. # Array new < 1 ; 2. arr last. # 3 arr push: 4. # Array new < 1 ; 2 ; 3 ; 4. arr pop. # 4 arr pop: 1. # 2, `arr` is rebound to Array new < 1 ; 3. # List comprehensions [x * 2 + y,, arr, arr + [4, 5],, x > 1]. # Array ← 7 ; 9 ; 10 ; 11 # fresh variable names are bound as they are encountered, # so `x` is bound to the values in `arr` # and `y` is bound to the values in `arr + [4, 5]` # # The general format is: [expr,, bindings*,, predicates*] #################################### ## 3. Functions #################################### # A simple function that takes two variables var add is {:a:b ^a + b.}. # this function will resolve all its names except the formal arguments # in the context it is called in. # Using the function add applyTo: 3 and: 5. # 8 add applyAll: [3, 5]. # 8 # Also a (customizable -- more on this later) pseudo-operator allows for a shorthand # of function calls # By default it is REF[args] add[3, 5]. # 8 # To customize this behaviour, you may simply use a compiler pragma: #:callShorthand () # And then you may use the specified operator. # Note that the allowed 'operator' can only be made of any of these: []{}() # And you may mix-and-match (why would anyone do that?) add(3, 5). # 8 # You may also use functions as operators in the following way: 3 `add` 5. # 8 # This call binds as such: add[(3), 5] # because the default fixity is left, and the default precedence is 1 # You may change the precedence/fixity of this operator with a pragma #:declare infixr 1 add 3 `add` 5. # 8 # now this binds as such: add[3, (5)]. # There is another form of functions too # So far, the functions were resolved in a dynamic fashion # But a lexically scoped block is also possible var sillyAdd is {\:x:y add[x,y].}. # In these blocks, you are not allowed to declare new variables # Except with the use of Object::'letEqual:in:` # And the last expression is implicitly returned. # You may also use a shorthand for lambda expressions var mul is \:x:y x * y. # These capture the named bindings that are not present in their # formal parameters, and retain them. (by ref) ########################################### ## 5. Control Flow ########################################### # inline conditional-expressions var citron is 1 = 1 either: 'awesome' or: 'awful'. # citron is 'awesome' # multiple lines is fine too var citron is 1 = 1 either: 'awesome' or: 'awful'. # looping 10 times: {:x Pen writeln: x. }. # 10. -- side effect: 10 lines in stdout, with numbers 0 through 9 in them # Citron properly supports tail-call recursion in lexically scoped blocks # So use those to your heart's desire # mapping most data structures is as simple as `fmap:` [1, 2, 3, 4] fmap: \:x x + 1. # [2, 3, 4, 5] # You can use `foldl:accumulator:` to fold a list/tuple [1, 2, 3, 4] foldl: (\:acc:x acc * 2 + x) accumulator: 4. # 90 # That expression is the same as (2 * (2 * (2 * (2 * 4 + 1) + 2) + 3) + 4) ################################### ## 6. IO ################################### # IO is quite simple # With `Pen` being used for console output # and Program::'input' and Program::'waitForInput' being used for console input Pen writeln: 'Hello, ocean!' # prints 'Hello, ocean!\n' to the terminal Pen writeln: Program waitForInput. # reads a line and prints it back ``` ================================================ FILE: clojure-macros.md ================================================ --- name: Clojure macros filename: learnclojuremacros.clj contributors: - ["Adam Bard", "http://adambard.com/"] --- As with all Lisps, Clojure's inherent [homoiconicity](https://en.wikipedia.org/wiki/Homoiconic) gives you access to the full extent of the language to write code-generation routines called "macros". Macros provide a powerful way to tailor the language to your needs. Be careful though. It's considered bad form to write a macro when a function will do. Use a macro only when you need control over when or if the arguments to a form will be evaluated. You'll want to be familiar with Clojure. Make sure you understand everything in [Clojure in Y Minutes](../clojure/). ```clojure ;; Define a macro using defmacro. Your macro should output a list that can ;; be evaluated as clojure code. ;; ;; This macro is the same as if you wrote (reverse "Hello World") (defmacro my-first-macro [] (list reverse "Hello World")) ;; Inspect the result of a macro using macroexpand or macroexpand-1. ;; ;; Note that the call must be quoted. (macroexpand '(my-first-macro)) ;; -> (# "Hello World") ;; You can eval the result of macroexpand directly: (eval (macroexpand '(my-first-macro))) ; -> (\d \l \o \r \W \space \o \l \l \e \H) ;; But you should use this more succinct, function-like syntax: (my-first-macro) ; -> (\d \l \o \r \W \space \o \l \l \e \H) ;; You can make things easier on yourself by using the more succinct quote syntax ;; to create lists in your macros: (defmacro my-first-quoted-macro [] '(reverse "Hello World")) (macroexpand '(my-first-quoted-macro)) ;; -> (reverse "Hello World") ;; Notice that reverse is no longer function object, but a symbol. ;; Macros can take arguments. (defmacro inc2 [arg] (list + 2 arg)) (inc2 2) ; -> 4 ;; But, if you try to do this with a quoted list, you'll get an error, because ;; the argument will be quoted too. To get around this, clojure provides a ;; way of quoting macros: `. Inside `, you can use ~ to get at the outer scope (defmacro inc2-quoted [arg] `(+ 2 ~arg)) (inc2-quoted 2) ;; You can use the usual destructuring args. Expand list variables using ~@ (defmacro unless [arg & body] `(if (not ~arg) (do ~@body))) ; Remember the do! (macroexpand '(unless true (reverse "Hello World"))) ;; -> ;; (if (clojure.core/not true) (do (reverse "Hello World"))) ;; (unless) evaluates and returns its body if the first argument is false. ;; Otherwise, it returns nil (unless true "Hello") ; -> nil (unless false "Hello") ; -> "Hello" ;; Used without care, macros can do great evil by clobbering your vars (defmacro define-x [] '(do (def x 2) (list x))) (def x 4) (define-x) ; -> (2) (list x) ; -> (2) ;; To avoid this, use gensym to get a unique identifier (gensym 'x) ; -> x1281 (or some such thing) (defmacro define-x-safely [] (let [sym (gensym 'x)] `(do (def ~sym 2) (list ~sym)))) (def x 4) (define-x-safely) ; -> (2) (list x) ; -> (4) ;; You can use # within ` to produce a gensym for each symbol automatically (defmacro define-x-hygienically [] `(do (def x# 2) (list x#))) (def x 4) (define-x-hygienically) ; -> (2) (list x) ; -> (4) ;; It's typical to use helper functions with macros. Let's create a few to ;; help us support a (dumb) inline arithmetic syntax (declare inline-2-helper) (defn clean-arg [arg] (if (seq? arg) (inline-2-helper arg) arg)) (defn apply-arg "Given args [x (+ y)], return (+ x y)" [val [op arg]] (list op val (clean-arg arg))) (defn inline-2-helper [[arg1 & ops-and-args]] (let [ops (partition 2 ops-and-args)] (reduce apply-arg (clean-arg arg1) ops))) ;; We can test it immediately, without creating a macro (inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5)) ; However, we'll need to make it a macro if we want it to be run at compile time (defmacro inline-2 [form] (inline-2-helper form)) (macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1))) ; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1) (inline-2 (1 + (3 / 2) - (1 / 2) + 1)) ; -> 3 (actually, 3N, since the number got cast to a rational fraction with /) ``` ### Further Reading [Writing Macros](http://www.braveclojure.com/writing-macros/) [Official docs](http://clojure.org/macros) [When to use macros?](https://lispcast.com/when-to-use-a-macro/) ================================================ FILE: clojure.md ================================================ --- name: Clojure filename: learnclojure.clj contributors: - ["Adam Bard", "http://adambard.com/"] --- Clojure is a Lisp family language developed for the Java Virtual Machine. It has a much stronger emphasis on pure [functional programming](https://en.wikipedia.org/wiki/Functional_programming) than Common Lisp, but includes several [STM](https://en.wikipedia.org/wiki/Software_transactional_memory) utilities to handle state as it comes up. This combination allows it to handle concurrent processing very simply, and often automatically. (You need a version of Clojure 1.2 or newer) ```clojure ; Comments start with semicolons. ; Clojure is written in "forms", which are just ; lists of things inside parentheses, separated by whitespace. ; ; The clojure reader assumes that the first thing is a ; function or macro to call, and the rest are arguments. ; The first call in a file should be ns, to set the namespace (ns learnclojure) ; More basic examples: ; str will create a string out of all its arguments (str "Hello" " " "World") ; => "Hello World" ; Math is straightforward (+ 1 1) ; => 2 (- 2 1) ; => 1 (* 1 2) ; => 2 (/ 2 1) ; => 2 ; Equality is = (= 1 1) ; => true (= 2 1) ; => false ; You need not for logic, too (not true) ; => false ; Nesting forms works as you expect (+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2 ; Types ;;;;;;;;;;;;; ; Clojure uses Java's object types for booleans, strings and numbers. ; Use `class` to inspect them. (class 1) ; Integer literals are java.lang.Long by default (class 1.); Float literals are java.lang.Double (class ""); Strings always double-quoted, and are java.lang.String (class false) ; Booleans are java.lang.Boolean (class nil); The "null" value is called nil ; If you want to create a literal list of data, use ' to stop it from ; being evaluated '(+ 1 2) ; => (+ 1 2) ; (shorthand for (quote (+ 1 2))) ; You can eval a quoted list (eval '(+ 1 2)) ; => 3 ; Collections & Sequences ;;;;;;;;;;;;;;;;;;; ; Lists are linked-list data structures, while Vectors are array-backed. ; Vectors and Lists are java classes too! (class [1 2 3]); => clojure.lang.PersistentVector (class '(1 2 3)); => clojure.lang.PersistentList ; A list would be written as just (1 2 3), but we have to quote ; it to stop the reader thinking it's a function. ; Also, (list 1 2 3) is the same as '(1 2 3) ; "Collections" are just groups of data ; Both lists and vectors are collections: (coll? '(1 2 3)) ; => true (coll? [1 2 3]) ; => true ; "Sequences" (seqs) are abstract descriptions of lists of data. ; Only lists are seqs. (seq? '(1 2 3)) ; => true (seq? [1 2 3]) ; => false ; A seq need only provide an entry when it is accessed. ; So, seqs which can be lazy -- they can define infinite series: (range 4) ; => (0 1 2 3) (range) ; => (0 1 2 3 4 ...) (an infinite series) (take 4 (range)) ; (0 1 2 3) ; Use cons to add an item to the beginning of a list or vector (cons 4 [1 2 3]) ; => (4 1 2 3) (cons 4 '(1 2 3)) ; => (4 1 2 3) ; Conj will add an item to a collection in the most efficient way. ; For lists, they insert at the beginning. For vectors, they insert at the end. (conj [1 2 3] 4) ; => [1 2 3 4] (conj '(1 2 3) 4) ; => (4 1 2 3) ; Use concat to add lists or vectors together (concat [1 2] '(3 4)) ; => (1 2 3 4) ; Use filter, map to interact with collections (map inc [1 2 3]) ; => (2 3 4) (filter even? [1 2 3]) ; => (2) ; Use reduce to reduce them (reduce + [1 2 3 4]) ; = (+ (+ (+ 1 2) 3) 4) ; => 10 ; Reduce can take an initial-value argument too (reduce conj [] '(3 2 1)) ; = (conj (conj (conj [] 3) 2) 1) ; => [3 2 1] ; Functions ;;;;;;;;;;;;;;;;;;;;; ; Use fn to create new functions. A function always returns ; its last statement. (fn [] "Hello World") ; => fn ; (You need extra parens to call it) ((fn [] "Hello World")) ; => "Hello World" ; You can create a var using def (def x 1) x ; => 1 ; Assign a function to a var (def hello-world (fn [] "Hello World")) (hello-world) ; => "Hello World" ; You can shorten this process by using defn (defn hello-world [] "Hello World") ; The [] is the list of arguments for the function. (defn hello [name] (str "Hello " name)) (hello "Steve") ; => "Hello Steve" ; You can also use this shorthand to create functions: (def hello2 #(str "Hello " %1)) (hello2 "Julie") ; => "Hello Julie" ; You can have multi-variadic functions, too (defn hello3 ([] "Hello World") ([name] (str "Hello " name))) (hello3 "Jake") ; => "Hello Jake" (hello3) ; => "Hello World" ; Functions can pack extra arguments up in a seq for you (defn count-args [& args] (str "You passed " (count args) " args: " args)) (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" ; You can mix regular and packed arguments (defn hello-count [name & args] (str "Hello " name ", you passed " (count args) " extra args")) (hello-count "Finn" 1 2 3) ; => "Hello Finn, you passed 3 extra args" ; Maps ;;;;;;;;;; ; Hash maps and array maps share an interface. Hash maps have faster lookups ; but don't retain key order. (class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap (class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap ; Arraymaps will automatically become hashmaps through most operations ; if they get big enough, so you don't need to worry. ; Maps can use any hashable type as a key, but usually keywords are best ; Keywords are like strings with some efficiency bonuses (class :a) ; => clojure.lang.Keyword (def stringmap {"a" 1, "b" 2, "c" 3}) stringmap ; => {"a" 1, "b" 2, "c" 3} (def keymap {:a 1, :b 2, :c 3}) keymap ; => {:a 1, :c 3, :b 2} ; By the way, commas are always treated as whitespace and do nothing. ; Retrieve a value from a map by calling it as a function (stringmap "a") ; => 1 (keymap :a) ; => 1 ; Keywords can be used to retrieve their value from a map, too! (:b keymap) ; => 2 ; Don't try this with strings. ;("a" stringmap) ; => Exception: java.lang.String cannot be cast to clojure.lang.IFn ; Retrieving a non-present key returns nil (stringmap "d") ; => nil ; Use assoc to add new keys to hash-maps (def newkeymap (assoc keymap :d 4)) newkeymap ; => {:a 1, :b 2, :c 3, :d 4} ; But remember, clojure types are immutable! keymap ; => {:a 1, :b 2, :c 3} ; Use dissoc to remove keys (dissoc keymap :a :b) ; => {:c 3} ; Sets ;;;;;; (class #{1 2 3}) ; => clojure.lang.PersistentHashSet (set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3} ; Add a member with conj (conj #{1 2 3} 4) ; => #{1 2 3 4} ; Remove one with disj (disj #{1 2 3} 1) ; => #{2 3} ; Test for existence by using the set as a function: (#{1 2 3} 1) ; => 1 (#{1 2 3} 4) ; => nil ; There are more functions in the clojure.sets namespace. ; Useful forms ;;;;;;;;;;;;;;;;; ; Logic constructs in clojure are just macros, and look like ; everything else (if false "a" "b") ; => "b" (if false "a") ; => nil ; Use let to create temporary bindings (let [a 1 b 2] (> a b)) ; => false ; Group statements together with do (do (print "Hello") "World") ; => "World" (prints "Hello") ; Functions have an implicit do (defn print-and-say-hello [name] (print "Saying hello to " name) (str "Hello " name)) (print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff") ; So does let (let [name "Urkel"] (print "Saying hello to " name) (str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel") ; Use the threading macros (-> and ->>) to express transformations of ; data more clearly. ; The "Thread-first" macro (->) inserts into each form the result of ; the previous, as the first argument (second item) (-> {:a 1 :b 2} (assoc :c 3) ;=> (assoc {:a 1 :b 2} :c 3) (dissoc :b)) ;=> (dissoc (assoc {:a 1 :b 2} :c 3) :b) ; This expression could be written as: ; (dissoc (assoc {:a 1 :b 2} :c 3) :b) ; and evaluates to {:a 1 :c 3} ; The double arrow does the same thing, but inserts the result of ; each line at the *end* of the form. This is useful for collection ; operations in particular: (->> (range 10) (map inc) ;=> (map inc (range 10)) (filter odd?) ;=> (filter odd? (map inc (range 10))) (into [])) ;=> (into [] (filter odd? (map inc (range 10)))) ; Result: [1 3 5 7 9] ; When you are in a situation where you want more freedom as where to ; put the result of previous data transformations in an ; expression, you can use the as-> macro. With it, you can assign a ; specific name to transformations' output and use it as a ; placeholder in your chained expressions: (as-> [1 2 3] input (map inc input);=> You can use last transform's output at the last position (nth input 2) ;=> and at the second position, in the same expression (conj [4 5 6] input 8 9 10)) ;=> or in the middle ! ; Result: [4 5 6 4 8 9 10] ; Modules ;;;;;;;;;;;;;;; ; Use "use" to get all functions from the module (use 'clojure.set) ; Now we can use set operations (intersection #{1 2 3} #{2 3 4}) ; => #{2 3} (difference #{1 2 3} #{2 3 4}) ; => #{1} ; You can choose a subset of functions to import, too (use '[clojure.set :only [intersection]]) ; Use require to import a module (require 'clojure.string) ; Use / to call functions from a module ; Here, the module is clojure.string and the function is blank? (clojure.string/blank? "") ; => true ; You can give a module a shorter name on import (require '[clojure.string :as str]) (str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst." ; (#"" denotes a regular expression literal) ; You can use require (and use, but don't) from a namespace using :require. ; You don't need to quote your modules if you do it this way. (ns test (:require [clojure.string :as str] [clojure.set :as set])) ; Java ;;;;;;;;;;;;;;;;; ; Java has a huge and useful standard library, so ; you'll want to learn how to get at it. ; Use import to load a java module (import java.util.Date) ; You can import from an ns too. (ns test (:import java.util.Date java.util.Calendar)) ; Use the class name with a "." at the end to make a new instance (Date.) ; ; Use . to call methods. Or, use the ".method" shortcut (. (Date.) getTime) ; (.getTime (Date.)) ; exactly the same thing. ; Use / to call static methods (System/currentTimeMillis) ; (system is always present) ; Use doto to make dealing with (mutable) classes more tolerable (import java.util.Calendar) (doto (Calendar/getInstance) (.set 2000 1 1 0 0 0) .getTime) ; => A Date. set to 2000-01-01 00:00:00 ; STM ;;;;;;;;;;;;;;;;; ; Software Transactional Memory is the mechanism clojure uses to handle ; persistent state. There are a few constructs in clojure that use this. ; An atom is the simplest. Pass it an initial value (def my-atom (atom {})) ; Update an atom with swap!. ; swap! takes a function and calls it with the current value of the atom ; as the first argument, and any trailing arguments as the second (swap! my-atom assoc :a 1) ; Sets my-atom to the result of (assoc {} :a 1) (swap! my-atom assoc :b 2) ; Sets my-atom to the result of (assoc {:a 1} :b 2) ; Use '@' to dereference the atom and get the value my-atom ;=> Atom<#...> (Returns the Atom object) @my-atom ; => {:a 1 :b 2} ; Here's a simple counter using an atom (def counter (atom 0)) (defn inc-counter [] (swap! counter inc)) (inc-counter) (inc-counter) (inc-counter) (inc-counter) (inc-counter) @counter ; => 5 ; Other STM constructs are refs and agents. ; Refs: http://clojure.org/refs ; Agents: http://clojure.org/agents ``` ### Further Reading This is far from exhaustive, but hopefully it's enough to get you on your feet. Clojure.org has lots of articles: [http://clojure.org/](http://clojure.org/) Clojuredocs.org has documentation with examples for most core functions: [http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core) 4Clojure is a great way to build your clojure/FP skills: [https://4clojure.oxal.org/](https://4clojure.oxal.org/) Clojure-doc.org (yes, really) has a number of getting started articles: [http://clojure-doc.org/](http://clojure-doc.org/) Clojure for the Brave and True has a great introduction to Clojure and a free online version: [https://www.braveclojure.com/clojure-for-the-brave-and-true/](https://www.braveclojure.com/clojure-for-the-brave-and-true/) ================================================ FILE: cmake.md ================================================ --- category: tool name: CMake contributors: - ["Bruno Alano", "https://github.com/brunoalano"] filename: CMake --- CMake is a cross-platform, open-source build system. This tool allows you to test, compile, and create packages of your source code. The problem that CMake tries to solve is the problem of Makefiles and Autoconfigure on cross-platforms (different make interpreters have different commands) and the ease-of-use on linking 3rd party libraries. CMake is an extensible, open-source system that manages the build process in an operating system and compiler-agnostic manner. Unlike many cross-platform systems, CMake is designed to be used in conjunction with the native build environment. Simple configuration files placed in each source directory (called CMakeLists.txt files) are used to generate standard build files (e.g., makefiles on Unix and projects/workspaces in Windows MSVC) which are used in the usual way. ```cmake # In CMake, this is a comment # To run our code, please perform the following commands: # - mkdir build && cd build # - cmake .. # - make # # With those steps, we will follow the best practice to compile into a subdir # and the second line will request to CMake to generate a new OS-dependent # Makefile. Finally, run the native Make command. #------------------------------------------------------------------------------ # Basic #------------------------------------------------------------------------------ # # The CMake file MUST be named as "CMakeLists.txt". # Setup the minimum version required of CMake to generate the Makefile cmake_minimum_required (VERSION 2.8) # Raises a FATAL_ERROR if version < 2.8 cmake_minimum_required (VERSION 2.8 FATAL_ERROR) # We define the name of our project, and this changes some directories # naming convention generated by CMake. We can send the LANG of code # as the second param project (learncmake C) # Set the project source dir (just convention) set( LEARN_CMAKE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ) set( LEARN_CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} ) # It's useful to set up the current version of our code in the build system # using a `semver` style set (LEARN_CMAKE_VERSION_MAJOR 1) set (LEARN_CMAKE_VERSION_MINOR 0) set (LEARN_CMAKE_VERSION_PATCH 0) # Send the variables (version number) to the source code header configure_file ( "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in" "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # Include Directories # In GCC, this will invoke the "-I" command include_directories( include ) # Where are the additional libraries installed? Note: provide includes # path here, subsequent checks will resolve everything else set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/modules/" ) # Conditions if ( CONDITION ) # Output! # Incidental information message(STATUS "My message") # CMake Warning, continue processing message(WARNING "My message") # CMake Warning (dev), continue processing message(AUTHOR_WARNING "My message") # CMake Error, continue processing, but skip generation message(SEND_ERROR "My message") # CMake Error, stop processing and generation message(FATAL_ERROR "My message") endif() if( CONDITION ) elseif( CONDITION ) else( CONDITION ) endif( CONDITION ) # Loops foreach(loop_var arg1 arg2 ...) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... endforeach(loop_var) foreach(loop_var RANGE total) foreach(loop_var RANGE start stop [step]) foreach(loop_var IN [LISTS [list1 [...]]] [ITEMS [item1 [...]]]) while(condition) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... endwhile(condition) # Logic Operations if(FALSE AND (FALSE OR TRUE)) message("Don't display!") endif() # Set a regular, cache, or environment variable to a given value. # If the PARENT_SCOPE option is given, the variable will be set in the scope # above the current scope. # `set( ... [PARENT_SCOPE])` # How to reference variables inside quoted and unquoted arguments? # A variable reference is replaced by either the variable value or by the # empty string if the variable is not set. ${variable_name} # Lists # Setup the list of source files set( LEARN_CMAKE_SOURCES src/main.c src/imagem.c src/pather.c ) # Calls the compiler # # ${PROJECT_NAME} refers to Learn_CMake add_executable( ${PROJECT_NAME} ${LEARN_CMAKE_SOURCES} ) # Link the libraries target_link_libraries( ${PROJECT_NAME} ${LIBS} m ) # Where are the additional libraries installed? Note: provide includes # path here, subsequent checks will resolve everything else set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/modules/" ) # Compiler Condition (gcc ; g++) if ( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" ) message( STATUS "Setting the flags for ${CMAKE_C_COMPILER_ID} compiler" ) add_definitions( --std=c99 ) endif() # Check for OS if( UNIX ) set( LEARN_CMAKE_DEFINITIONS "${LEARN_CMAKE_DEFINITIONS} -Wall -Wextra -Werror -Wno-deprecated-declarations -Wno-unused-parameter -Wno-comment" ) endif() ``` ### More Resources + [CMake tutorial](https://cmake.org/cmake-tutorial/) + [CMake documentation](https://cmake.org/documentation/) + [Mastering CMake](http://amzn.com/1930934319/) + [An Introduction to Modern CMake](https://cliutils.gitlab.io/modern-cmake/) ================================================ FILE: cobol.md ================================================ --- name: COBOL contributors: - ["Hyphz", "http://github.com/hyphz/"] filename: learn.cob --- COBOL is a business-oriented language revised multiple times since its original design in 1960. ```cobol *COBOL. Coding like it's 1985. *Compiles with GnuCOBOL in OpenCobolIDE 4.7.6. *COBOL has significant differences between legacy (COBOL-85) *and modern (COBOL-2002 and COBOL-2014) versions. *Legacy versions require columns 1-6 to be blank (they are used *to store the index number of the punched card). *A '*' in column 7 means a comment. *In legacy COBOL, a comment can only be a full line. *Modern COBOL doesn't require fixed columns and uses *> for *a comment, which can appear in the middle of a line. *Legacy COBOL also imposes a limit on maximum line length. *Keywords have to be in capitals in legacy COBOL, *but are case insensitive in modern. *Although modern COBOL allows you to use mixed-case characters *it is still common to use all caps when writing COBOL code. *This is what most professional COBOL developers do. *COBOL statements end with a period. *COBOL code is broken up into 4 divisions. *Those divisions, in order, are: *IDENTIFICATION DIVISION. *ENVIRONMENT DIVISION. *DATA DIVISION. *PROCEDURE DIVISION. *First, we must give our program an ID. *The IDENTIFICATION DIVISION can include other values too, *but they are comments only. PROGRAM-ID is the only one that *is mandatory. IDENTIFICATION DIVISION. PROGRAM-ID. LEARN. AUTHOR. JOHN DOE. DATE-WRITTEN. 05/02/2020. *Let's declare some variables. *We do this in the WORKING-STORAGE section within the DATA DIVISION. *Each data item (aka variable) starts with a level number, *then the name of the item, followed by a PICTURE clause *describing the type of data that the variable will contain. *Almost every COBOL programmer will abbreviate PICTURE as PIC. *A is for alphabetic, X is for alphanumeric, and 9 is for numeric. *example: 01 MYNAME PIC XXXXXXXXXX. *> A 10 character string. *But counting all those Xs can lead to errors, *so the above code can be re-written as 01 MYNAME PIC X(10). *Here are some more examples: 01 AGE PICTURE 9(3). *> A number up to 3 digits. 01 BIRTH_YEAR PIC S9(7). *> A signed number up to 7 digits. 01 LAST_NAME PIC X(10). *> A string up to 10 characters. *In COBOL, multiple spaces are the same as a single space, so it *is common to use multiple spaces to line up your code so that it *is easier for other coders to read. *Now let's write some code. Here is a simple, Hello World program. IDENTIFICATION DIVISION. PROGRAM-ID. HELLO. DATA DIVISION. WORKING-STORAGE SECTION. 01 THE-MESSAGE PIC X(20). PROCEDURE DIVISION. DISPLAY "STARTING PROGRAM". MOVE "HELLO WORLD" TO THE-MESSAGE. DISPLAY THE-MESSAGE. STOP RUN. *The above code will output: *STARTING PROGRAM *HELLO WORLD ********COBOL can perform math*************** ADD 1 TO AGE GIVING NEW-AGE. SUBTRACT 1 FROM COUNT. DIVIDE VAR-1 INTO VAR-2 GIVING VAR-3. COMPUTE TOTAL-COUNT = COUNT1 PLUS COUNT2. *********PERFORM******************** *The PERFORM keyword allows you to jump to another specified *section of the code, and then to return to the next executable *statement once the specified section of code is completed. *You must write the full word, PERFORM, you cannot abbreviate it. IDENTIFICATION DIVISION. PROGRAM-ID. HELLOCOBOL. PROCEDURE DIVISION. FIRST-PARA. DISPLAY 'THIS IS IN FIRST-PARA'. *skip SECOND-PARA and perform 3rd & 4th *then after performing THIRD-PARA and FOURTH-PARA, *return here and continue the program until STOP RUN. PERFORM THIRD-PARA THRU FOURTH-PARA. SECOND-PARA. DISPLAY 'THIS IS IN SECOND-PARA'. STOP RUN. THIRD-PARA. DISPLAY 'THIS IS IN THIRD-PARA'. FOURTH-PARA. DISPLAY 'THIS IS IN FOURTH-PARA'. *When you compile and execute the above program, it produces the *following result (note the order): *THIS IS IN FIRST-PARA *THIS IS IN THIRD-PARA *THIS IS IN FOURTH-PARA *THIS IS IN SECOND-PARA **********Combining variables together using STRING *********** *Now it is time to learn about two related COBOL verbs: STRING and *UNSTRING. *The STRING verb is used to concatenate, or put together, two or *more strings. *UNSTRING is used, not surprisingly, to separate a *string into two or more smaller strings. *It is important that you remember to use DELIMITED BY when you *are using STRING or UNSTRING in your program. IDENTIFICATION DIVISION. PROGRAM-ID. LEARNING. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 FULL-NAME PIC X(20). 01 FIRST-NAME PIC X(13) VALUE "BOB GIBBERISH". 01 LAST-NAME PIC X(5) VALUE "COBB". PROCEDURE DIVISION. STRING FIRST-NAME DELIMITED BY SPACE " " LAST-NAME DELIMITED BY SIZE INTO FULL-NAME END-STRING. DISPLAY "THE FULL NAME IS: "FULL-NAME. STOP RUN. *The above code will output: *THE FULL NAME IS: BOB COBB *Let's examine it to see why. *First, we declared all of our variables, including the one that *we are creating by the string command, in the DATA DIVISION. *The action takes place down in the PROCEDURE DIVISION. *We start with the STRING keyword and end with END-STRING. In *between we list what we want to combine together into the larger, *master variable. Here, we are combining FIRST-NAME, a space, and *LAST-NAME. *The DELIMITED BY phrase that follows FIRST-NAME and *LAST-NAME tells the program how much of each variable we want to *capture. *DELIMITED BY SPACE tells the program to start at the beginning, *and capture the variable until it runs into a space. *DELIMITED BY SIZE tells the program to capture the full size of *the variable. *Since we have DELIMITED BY SPACE after FIRST-NAME, the GIBBERISH *part is ignored. *To make this clearer, change line 10 in the above code to STRING FIRST-NAME DELIMITED BY SIZE *and then re-run the program. This time the output is: *THE FULL NAME IS: BOB GIBBERISH COBB ``` ## Further reading * [GnuCOBOL](https://gnucobol.sourceforge.io/) ================================================ FILE: coffeescript.md ================================================ --- name: CoffeeScript contributors: - ["Tenor Biel", "http://github.com/L8D"] - ["Xavier Yao", "http://github.com/xavieryao"] filename: coffeescript.coffee --- CoffeeScript is a little language that compiles one-to-one into the equivalent JavaScript, and there is no interpretation at runtime. As one of the successors to JavaScript, CoffeeScript tries its best to output readable, pretty-printed and smooth-running JavaScript code, which works well in every JavaScript runtime. It also attempts to try and make JavaScript more in line with the trends of many modern languages. See also [the CoffeeScript website](http://coffeescript.org/), which has a complete tutorial on CoffeeScript. ```coffeescript # Comments are similar to Ruby and Python, using the hash symbol `#` ### Block comments are like these, and they translate directly to '/ *'s and '* /'s for the resulting JavaScript code. You should understand most of JavaScript semantics before continuing. ### # Assignment: number = 42 #=> var number = 42; opposite = true #=> var opposite = true; # Conditions: number = -42 if opposite #=> if(opposite) { number = -42; } # Functions: square = (x) -> x * x #=> var square = function(x) { return x * x; } fill = (container, liquid = "coffee") -> "Filling the #{container} with #{liquid}..." #=>var fill; # #fill = function(container, liquid) { # if (liquid == null) { # liquid = "coffee"; # } # return "Filling the " + container + " with " + liquid + "..."; #}; # Ranges: list = [1..5] #=> var list = [1, 2, 3, 4, 5]; # Objects: math = root: Math.sqrt square: square cube: (x) -> x * square x #=> var math = { # "root": Math.sqrt, # "square": square, # "cube": function(x) { return x * square(x); } # }; # Splats: race = (winner, runners...) -> print winner, runners #=>race = function() { # var runners, winner; # winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : []; # return print(winner, runners); # }; # Existence: alert "I knew it!" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); } # Array comprehensions: cubes = (math.cube num for num in list) #=>cubes = (function() { # var _i, _len, _results; # _results = []; # for (_i = 0, _len = list.length; _i < _len; _i++) { # num = list[_i]; # _results.push(math.cube(num)); # } # return _results; # })(); foods = ['broccoli', 'spinach', 'chocolate'] eat food for food in foods when food isnt 'chocolate' #=>foods = ['broccoli', 'spinach', 'chocolate']; # #for (_k = 0, _len2 = foods.length; _k < _len2; _k++) { # food = foods[_k]; # if (food !== 'chocolate') { # eat(food); # } #} ``` ## Additional resources - [Smooth CoffeeScript](http://autotelicum.github.io/Smooth-CoffeeScript/) - [CoffeeScript Ristretto](https://leanpub.com/coffeescript-ristretto/read) ================================================ FILE: coldfusion.md ================================================ --- name: ColdFusion filename: learncoldfusion.cfm contributors: - ["Wayne Boka", "http://wboka.github.io"] - ["Kevin Morris", "https://twitter.com/kevinmorris"] --- ColdFusion is a scripting language for web development. [Read more here.](http://www.adobe.com/products/coldfusion-family.html) ### CFML _**C**old**F**usion **M**arkup **L**anguage_ ColdFusion started as a tag-based language. Almost all functionality is available using tags. ```cfm HTML tags have been provided for output readability " --->

Simple Variables

Set myVariable to "myValue"

Set myNumber to 3.14

Display myVariable: #myVariable#

Display myNumber: #myNumber#


Complex Variables

Set myArray1 to an array of 1 dimension using literal or bracket notation

Set myArray2 to an array of 1 dimension using function notation

Contents of myArray1

Contents of myArray2

Operators

Arithmetic

1 + 1 = #1 + 1#

10 - 7 = #10 - 7#

15 * 10 = #15 * 10#

100 / 5 = #100 / 5#

120 % 5 = #120 % 5#

120 mod 5 = #120 mod 5#


Comparison

Standard Notation

Is 1 eq 1? #1 eq 1#

Is 15 neq 1? #15 neq 1#

Is 10 gt 8? #10 gt 8#

Is 1 lt 2? #1 lt 2#

Is 10 gte 5? #10 gte 5#

Is 1 lte 5? #1 lte 5#

Alternative Notation

Is 1 == 1? #1 eq 1#

Is 15 != 1? #15 neq 1#

Is 10 > 8? #10 gt 8#

Is 1 < 2? #1 lt 2#

Is 10 >= 5? #10 gte 5#

Is 1 <= 5? #1 lte 5#


Control Structures

Condition to test for: "#myCondition#"

#myCondition#. We're testing. #myCondition#. Proceed Carefully!!! myCondition is unknown

Loops

For Loop

Index equals #i#

For Each Loop (Complex Variables)

Set myArray3 to [5, 15, 99, 45, 100]

Index equals #i#

Set myArray4 to ["Alpha", "Bravo", "Charlie", "Delta", "Echo"]

Index equals #s#

Switch Statement

Set myArray5 to [5, 15, 99, 45, 100]

#i# is a multiple of 5.

#i# is ninety-nine.

#i# is not 5, 15, 45, or 99.


Converting types

Value As Boolean As number As date-time As string
"Yes" TRUE 1 Error "Yes"
"No" FALSE 0 Error "No"
TRUE TRUE 1 Error "Yes"
FALSE FALSE 0 Error "No"
Number True if Number is not 0; False otherwise. Number See "Date-time values" earlier in this chapter. String representation of the number (for example, "8").
String If "Yes", True
If "No", False
If it can be converted to 0, False
If it can be converted to any other number, True
If it represents a number (for example, "1,000" or "12.36E-12"), it is converted to the corresponding number. If it represents a date-time (see next column), it is converted to the numeric value of the corresponding date-time object.
If it is an ODBC date, time, or timestamp (for example "{ts '2001-06-14 11:30:13'}", or if it is expressed in a standard U.S. date or time format, including the use of full or abbreviated month names, it is converted to the corresponding date-time value.
Days of the week or unusual punctuation result in an error.
Dashes, forward-slashes, and spaces are generally allowed.
String
Date Error The numeric value of the date-time object. Date An ODBC timestamp.

Components

Code for reference (Functions must return something to support IE) ``` ```cfs sayHello()

#sayHello()#

getHello()

#getHello()#

getWorld()

#getWorld()#

setHello("Hola")

#setHello("Hola")#

setWorld("mundo")

#setWorld("mundo")#

sayHello()

#sayHello()#

getHello()

#getHello()#

getWorld()

#getWorld()#

``` ### CFScript _**C**old**F**usion **S**cript_ In recent years, the ColdFusion language has added script syntax to mirror tag functionality. When using an up-to-date CF server, almost all functionality is available using scrypt syntax. ## Further Reading The links provided here below are just to get an understanding of the topic, feel free to Google and find specific examples. 1. [Coldfusion Reference From Adobe](https://helpx.adobe.com/coldfusion/cfml-reference/topics.html) 2. [Open Source Documentation](http://cfdocs.org/) ================================================ FILE: common-lisp.md ================================================ --- name: "Common Lisp" filename: commonlisp.lisp contributors: - ["Paul Nathan", "https://github.com/pnathan"] - ["Paul Khuong", "https://github.com/pkhuong"] - ["Rommel Martinez", "https://ebzzry.io"] --- Common Lisp is a general-purpose, multi-paradigm programming language suited for a wide variety of industry applications. It is frequently referred to as a programmable programming language. The classic starting point is [Practical Common Lisp](http://www.gigamonkeys.com/book/). Another popular and recent book is [Land of Lisp](http://landoflisp.com/). A new book about best practices, [Common Lisp Recipes](http://weitz.de/cl-recipes/), was recently published. ```lisp ;;;----------------------------------------------------------------------------- ;;; 0. Syntax ;;;----------------------------------------------------------------------------- ;;; General form ;;; CL has two fundamental pieces of syntax: ATOM and S-EXPRESSION. ;;; Typically, grouped S-expressions are called `forms`. 10 ; an atom; it evaluates to itself :thing ; another atom; evaluating to the symbol :thing t ; another atom, denoting true (+ 1 2 3 4) ; an s-expression '(4 :foo t) ; another s-expression ;;; Comments ;;; Single-line comments start with a semicolon; use four for file-level ;;; comments, three for section descriptions, two inside definitions, and one ;;; for single lines. For example, ;;;; life.lisp ;;; Foo bar baz, because quu quux. Optimized for maximum krakaboom and umph. ;;; Needed by the function LINULUKO. (defun meaning (life) "Return the computed meaning of LIFE" (let ((meh "abc")) ;; Invoke krakaboom (loop :for x :across meh :collect x))) ; store values into x, then return it ;;; Block comments, on the other hand, allow for free-form comments. They are ;;; delimited with #| and |# #| This is a block comment which can span multiple lines and #| they can be nested! |# |# ;;; Environment ;;; A variety of implementations exist; most are standards-conformant. SBCL ;;; is a good starting point. Third party libraries can be easily installed with ;;; Quicklisp ;;; CL is usually developed with a text editor and a Read Eval Print ;;; Loop (REPL) running at the same time. The REPL allows for interactive ;;; exploration of the program while it is running "live". ;;;----------------------------------------------------------------------------- ;;; 1. Primitive datatypes and operators ;;;----------------------------------------------------------------------------- ;;; Symbols 'foo ; => FOO Notice that the symbol is upper-cased automatically. ;;; INTERN manually creates a symbol from a string. (intern "AAAA") ; => AAAA (intern "aaa") ; => |aaa| ;;; Numbers 9999999999999999999999 ; integers #b111 ; binary => 7 #o111 ; octal => 73 #x111 ; hexadecimal => 273 3.14159s0 ; single 3.14159d0 ; double 1/2 ; ratios #C(1 2) ; complex numbers ;;; Function application are written as (f x y z ...) where f is a function and ;;; x, y, z, ... are the arguments. (+ 1 2) ; => 3 ;;; If you want to create literal data, use QUOTE to prevent it from being ;;; evaluated (quote (+ 1 2)) ; => (+ 1 2) (quote a) ; => A ;;; The shorthand for QUOTE is ' '(+ 1 2) ; => (+ 1 2) 'a ; => A ;;; Basic arithmetic operations (+ 1 1) ; => 2 (- 8 1) ; => 7 (* 10 2) ; => 20 (expt 2 3) ; => 8 (mod 5 2) ; => 1 (/ 35 5) ; => 7 (/ 1 3) ; => 1/3 (+ #C(1 2) #C(6 -4)) ; => #C(7 -2) ;;; Booleans t ; true; any non-NIL value is true nil ; false; also, the empty list: () (not nil) ; => T (and 0 t) ; => T (or 0 nil) ; => 0 ;;; Characters #\A ; => #\A #\λ ; => #\GREEK_SMALL_LETTER_LAMDA #\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA ;;; Strings are fixed-length arrays of characters "Hello, world!" "Benjamin \"Bugsy\" Siegel" ; backslash is an escaping character ;;; Strings can be concatenated (concatenate 'string "Hello, " "world!") ; => "Hello, world!" ;;; A string can be treated like a sequence of characters (elt "Apple" 0) ; => #\A ;;; FORMAT is used to create formatted output, which ranges from simple string ;;; interpolation to loops and conditionals. The first argument to FORMAT ;;; determines where will the formatted string go. If it is NIL, FORMAT ;;; simply returns the formatted string as a value; if it is T, FORMAT outputs ;;; to the standard output, usually the screen, then it returns NIL. (format nil "~A, ~A!" "Hello" "world") ; => "Hello, world!" (format t "~A, ~A!" "Hello" "world") ; => NIL ;;;----------------------------------------------------------------------------- ;;; 2. Variables ;;;----------------------------------------------------------------------------- ;;; You can create a global (dynamically scoped) variable using DEFVAR and ;;; DEFPARAMETER. The variable name can use any character except: ()",'`;#|\ ;;; The difference between DEFVAR and DEFPARAMETER is that re-evaluating a ;;; DEFVAR expression doesn't change the value of the variable. DEFPARAMETER, ;;; on the other hand, does. ;;; By convention, dynamically scoped variables have earmuffs in their name. (defparameter *some-var* 5) *some-var* ; => 5 ;;; You can also use unicode characters. (defparameter *AΛB* nil) ;;; Accessing a previously unbound variable results in an UNBOUND-VARIABLE ;;; error, however it is defined behavior. Don't do it. ;;; You can create local bindings with LET. In the following snippet, `me` is ;;; bound to "dance with you" only within the (let ...). LET always returns ;;; the value of the last `form` in the LET form. (let ((me "dance with you")) me) ; => "dance with you" ;;;-----------------------------------------------------------------------------; ;;; 3. Structs and collections ;;;-----------------------------------------------------------------------------; ;;; Structs (defstruct dog name breed age) (defparameter *rover* (make-dog :name "rover" :breed "collie" :age 5)) *rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5) (dog-p *rover*) ; => T (dog-name *rover*) ; => "rover" ;;; DOG-P, MAKE-DOG, and DOG-NAME are all automatically created by DEFSTRUCT ;;; Pairs ;;; CONS constructs pairs. CAR and CDR return the head and tail of a CONS-pair. (cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB) (car (cons 'SUBJECT 'VERB)) ; => SUBJECT (cdr (cons 'SUBJECT 'VERB)) ; => VERB ;;; Lists ;;; Lists are linked-list data structures, made of CONS pairs and end with a ;;; NIL (or '()) to mark the end of the list (cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3) ;;; LIST is a convenience variadic constructor for lists (list 1 2 3) ; => '(1 2 3) ;;; When the first argument to CONS is an atom and the second argument is a ;;; list, CONS returns a new CONS-pair with the first argument as the first ;;; item and the second argument as the rest of the CONS-pair (cons 4 '(1 2 3)) ; => '(4 1 2 3) ;;; Use APPEND to join lists (append '(1 2) '(3 4)) ; => '(1 2 3 4) ;;; Or CONCATENATE (concatenate 'list '(1 2) '(3 4)) ; => '(1 2 3 4) ;;; Lists are a very central type, so there is a wide variety of functionality for ;;; them, a few examples: (mapcar #'1+ '(1 2 3)) ; => '(2 3 4) (mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33) (remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4) (every #'evenp '(1 2 3 4)) ; => NIL (some #'oddp '(1 2 3 4)) ; => T (butlast '(subject verb object)) ; => (SUBJECT VERB) ;;; Vectors ;;; Vector's literals are fixed-length arrays #(1 2 3) ; => #(1 2 3) ;;; Use CONCATENATE to add vectors together (concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) ;;; Arrays ;;; Both vectors and strings are special-cases of arrays. ;;; 2D arrays (make-array (list 2 2)) ; => #2A((0 0) (0 0)) (make-array '(2 2)) ; => #2A((0 0) (0 0)) (make-array (list 2 2 2)) ; => #3A(((0 0) (0 0)) ((0 0) (0 0))) ;;; Caution: the default initial values of MAKE-ARRAY are implementation-defined. ;;; To explicitly specify them: (make-array '(2) :initial-element 'unset) ; => #(UNSET UNSET) ;;; To access the element at 1, 1, 1: (aref (make-array (list 2 2 2)) 1 1 1) ; => 0 ;;; This value is implementation-defined: ;;; NIL on ECL, 0 on SBCL and CCL. ;;; Adjustable vectors ;;; Adjustable vectors have the same printed representation as ;;; fixed-length vector's literals. (defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3) :adjustable t :fill-pointer t)) *adjvec* ; => #(1 2 3) ;;; Adding new elements (vector-push-extend 4 *adjvec*) ; => 3 *adjvec* ; => #(1 2 3 4) ;;; Sets, naively, are just lists: (set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1) (intersection '(1 2 3 4) '(4 5 6 7)) ; => 4 (union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7) (adjoin 4 '(1 2 3 4)) ; => (1 2 3 4) ;;; However, you'll need a better data structure than linked lists when working ;;; with larger data sets ;;; Dictionaries are implemented as hash tables. ;;; Create a hash table (defparameter *m* (make-hash-table)) ;;; Set value (setf (gethash 'a *m*) 1) ;;; Retrieve value (gethash 'a *m*) ; => 1, T ;;; CL expressions have the ability to return multiple values. (values 1 2) ; => 1, 2 ;;; which can be bound with MULTIPLE-VALUE-BIND (multiple-value-bind (x y) (values 1 2) (list y x)) ; => '(2 1) ;;; GETHASH is an example of a function that returns multiple values. The first ;;; value it return is the value of the key in the hash table; if the key is ;;; not found it returns NIL. ;;; The second value determines if that key is indeed present in the hash ;;; table. If a key is not found in the table it returns NIL. This behavior ;;; allows us to check if the value of a key is actually NIL. ;;; Retrieving a non-present value returns nil (gethash 'd *m*) ;=> NIL, NIL ;;; You can provide a default value for missing keys (gethash 'd *m* :not-found) ; => :NOT-FOUND ;;; Let's handle the multiple return values here in code. (multiple-value-bind (a b) (gethash 'd *m*) (list a b)) ; => (NIL NIL) (multiple-value-bind (a b) (gethash 'a *m*) (list a b)) ; => (1 T) ;;;----------------------------------------------------------------------------- ;;; 3. Functions ;;;----------------------------------------------------------------------------- ;;; Use LAMBDA to create anonymous functions. Functions always returns the ;;; value of the last expression. The exact printable representation of a ;;; function varies between implementations. (lambda () "Hello World") ; => # ;;; Use FUNCALL to call anonymous functions (funcall (lambda () "Hello World")) ; => "Hello World" (funcall #'+ 1 2 3) ; => 6 ;;; A call to FUNCALL is also implied when the lambda expression is the CAR of ;;; an unquoted list ((lambda () "Hello World")) ; => "Hello World" ((lambda (val) val) "Hello World") ; => "Hello World" ;;; FUNCALL is used when the arguments are known beforehand. Otherwise, use APPLY (apply #'+ '(1 2 3)) ; => 6 (apply (lambda () "Hello World") nil) ; => "Hello World" ;;; To name a function, use DEFUN (defun hello-world () "Hello World") (hello-world) ; => "Hello World" ;;; The () in the definition above is the list of arguments (defun hello (name) (format nil "Hello, ~A" name)) (hello "Steve") ; => "Hello, Steve" ;;; Functions can have optional arguments; they default to NIL (defun hello (name &optional from) (if from (format t "Hello, ~A, from ~A" name from) (format t "Hello, ~A" name))) (hello "Jim" "Alpacas") ; => Hello, Jim, from Alpacas ;;; The default values can also be specified (defun hello (name &optional (from "The world")) (format nil "Hello, ~A, from ~A" name from)) (hello "Steve") ; => Hello, Steve, from The world (hello "Steve" "the alpacas") ; => Hello, Steve, from the alpacas ;;; Functions also have keyword arguments to allow non-positional arguments (defun generalized-greeter (name &key (from "the world") (honorific "Mx")) (format t "Hello, ~A ~A, from ~A" honorific name from)) (generalized-greeter "Jim") ; => Hello, Mx Jim, from the world (generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr") ; => Hello, Mr Jim, from the alpacas you met last summer ;;;----------------------------------------------------------------------------- ;;; 4. Equality ;;;----------------------------------------------------------------------------- ;;; CL has a sophisticated equality system. Some are covered here. ;;; For numbers, use `=' (= 3 3.0) ; => T (= 2 1) ; => NIL ;;; For object identity (approximately) use EQL (eql 3 3) ; => T (eql 3 3.0) ; => NIL (eql (list 3) (list 3)) ; => NIL ;;; for lists, strings, and bit-vectors use EQUAL (equal (list 'a 'b) (list 'a 'b)) ; => T (equal (list 'a 'b) (list 'b 'a)) ; => NIL ;;;----------------------------------------------------------------------------- ;;; 5. Control Flow ;;;----------------------------------------------------------------------------- ;;; Conditionals (if t ; test expression "this is true" ; then expression "this is false") ; else expression ; => "this is true" ;;; In conditionals, all non-NIL values are treated as true (member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO) (if (member 'Groucho '(Harpo Groucho Zeppo)) 'yep 'nope) ; => 'YEP ;;; COND chains a series of tests to select a result (cond ((> 2 2) (error "wrong!")) ((< 2 2) (error "wrong again!")) (t 'ok)) ; => 'OK ;;; TYPECASE switches on the type of the value (typecase 1 (string :string) (integer :int)) ; => :int ;;; Looping ;;; Recursion (defun fact (n) (if (< n 2) 1 (* n (fact(- n 1))))) (fact 5) ; => 120 ;;; Iteration (defun fact (n) (loop :for result = 1 :then (* result i) :for i :from 2 :to n :finally (return result))) (fact 5) ; => 120 (loop :for x :across "abcd" :collect x) ; => (#\a #\b #\c #\d) (dolist (i '(1 2 3 4)) (format t "~A" i)) ; => 1234 ;;;----------------------------------------------------------------------------- ;;; 6. Mutation ;;;----------------------------------------------------------------------------- ;;; Use SETF to assign a new value to an existing variable. This was ;;; demonstrated earlier in the hash table example. (let ((variable 10)) (setf variable 2)) ; => 2 ;;; Good Lisp style is to minimize the use of destructive functions and to avoid ;;; mutation when reasonable. ;;;----------------------------------------------------------------------------- ;;; 7. Classes and objects ;;;----------------------------------------------------------------------------- ;;; No more animal classes. Let's have Human-Powered Mechanical ;;; Conveyances. (defclass human-powered-conveyance () ((velocity :accessor velocity :initarg :velocity) (average-efficiency :accessor average-efficiency :initarg :average-efficiency)) (:documentation "A human powered conveyance")) ;;; The arguments to DEFCLASS, in order are: ;;; 1. class name ;;; 2. superclass list ;;; 3. slot list ;;; 4. optional specifiers ;;; When no superclass list is set, the empty list defaults to the ;;; standard-object class. This *can* be changed, but not until you ;;; know what you're doing. Look up the Art of the Metaobject Protocol ;;; for more information. (defclass bicycle (human-powered-conveyance) ((wheel-size :accessor wheel-size :initarg :wheel-size :documentation "Diameter of the wheel.") (height :accessor height :initarg :height))) (defclass recumbent (bicycle) ((chain-type :accessor chain-type :initarg :chain-type))) (defclass unicycle (human-powered-conveyance) nil) (defclass canoe (human-powered-conveyance) ((number-of-rowers :accessor number-of-rowers :initarg :number-of-rowers))) ;;; Calling DESCRIBE on the HUMAN-POWERED-CONVEYANCE class in the REPL gives: (describe 'human-powered-conveyance) ; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE ; [symbol] ; ; HUMAN-POWERED-CONVEYANCE names the standard-class #: ; Documentation: ; A human powered conveyance ; Direct superclasses: STANDARD-OBJECT ; Direct subclasses: UNICYCLE, BICYCLE, CANOE ; Not yet finalized. ; Direct slots: ; VELOCITY ; Readers: VELOCITY ; Writers: (SETF VELOCITY) ; AVERAGE-EFFICIENCY ; Readers: AVERAGE-EFFICIENCY ; Writers: (SETF AVERAGE-EFFICIENCY) ;;; Note the reflective behavior available. CL was designed to be an ;;; interactive system ;;; To define a method, let's find out what our circumference of the ;;; bike wheel turns out to be using the equation: C = d * pi (defmethod circumference ((object bicycle)) (* pi (wheel-size object))) ;;; PI is defined as a built-in in CL ;;; Let's suppose we find out that the efficiency value of the number ;;; of rowers in a canoe is roughly logarithmic. This should probably be set ;;; in the constructor/initializer. ;;; To initialize your instance after CL gets done constructing it: (defmethod initialize-instance :after ((object canoe) &rest args) (setf (average-efficiency object) (log (1+ (number-of-rowers object))))) ;;; Then to construct an instance and check the average efficiency... (average-efficiency (make-instance 'canoe :number-of-rowers 15)) ; => 2.7725887 ;;;----------------------------------------------------------------------------- ;;; 8. Macros ;;;----------------------------------------------------------------------------- ;;; Macros let you extend the syntax of the language. CL doesn't come ;;; with a WHILE loop, however, it's trivial to write one. If we obey our ;;; assembler instincts, we wind up with: (defmacro while (condition &body body) "While `condition` is true, `body` is executed. `condition` is tested prior to each execution of `body`" (let ((block-name (gensym)) (done (gensym))) `(tagbody ,block-name (unless ,condition (go ,done)) (progn ,@body) (go ,block-name) ,done))) ;;; Let's look at the high-level version of this: (defmacro while (condition &body body) "While `condition` is true, `body` is executed. `condition` is tested prior to each execution of `body`" `(loop while ,condition do (progn ,@body))) ;;; However, with a modern compiler, this is not required; the LOOP form ;;; compiles equally well and is easier to read. ;;; Note that ``` is used, as well as `,` and `@`. ``` is a quote-type operator ;;; known as quasiquote; it allows the use of `,` . `,` allows "unquoting" ;;; variables. @ interpolates lists. ;;; GENSYM creates a unique symbol guaranteed to not exist elsewhere in ;;; the system. This is because macros are expanded at compile time and ;;; variables declared in the macro can collide with variables used in ;;; regular code. ;;; See Practical Common Lisp and On Lisp for more information on macros. ``` ## Further reading - [Practical Common Lisp](http://www.gigamonkeys.com/book/) - [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf) ## Extra information - [CLiki](http://www.cliki.net/) - [common-lisp.net](https://common-lisp.net/) - [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl) - [Lisp Lang](http://lisp-lang.org/) ================================================ FILE: compojure.md ================================================ --- category: tool name: Compojure contributors: - ["Adam Bard", "http://adambard.com/"] filename: learncompojure.clj --- ## Getting Started with Compojure Compojure is a DSL for *quickly* creating *performant* web applications in Clojure with minimal effort: ```clojure (ns myapp.core (:require [compojure.core :refer :all] [org.httpkit.server :refer [run-server]])) ; httpkit is a server (defroutes myapp (GET "/" [] "Hello World")) (defn -main [] (run-server myapp {:port 5000})) ``` **Step 1:** Create a project with [Leiningen](http://leiningen.org/): ``` lein new myapp ``` **Step 2:** Put the above code in `src/myapp/core.clj` **Step 3:** Add some dependencies to `project.clj`: ``` [compojure "1.1.8"] [http-kit "2.1.16"] ``` **Step 4:** Run: ``` lein run -m myapp.core ``` View at: Compojure apps will run on any ring-compatible server, but we recommend [http-kit](http://http-kit.org/) for its performance and [massive concurrency](http://http-kit.org/600k-concurrent-connection-http-kit.html). ### Routes In compojure, each route is an HTTP method paired with a URL-matching pattern, an argument list, and a body. ```clojure (defroutes myapp (GET "/" [] "Show something") (POST "/" [] "Create something") (PUT "/" [] "Replace something") (PATCH "/" [] "Modify Something") (DELETE "/" [] "Annihilate something") (OPTIONS "/" [] "Appease something") (HEAD "/" [] "Preview something")) ``` Compojure route definitions are just functions which [accept request maps and return response maps](https://github.com/mmcgrana/ring/blob/master/SPEC): ```clojure (myapp {:uri "/" :request-method :post}) ; => {:status 200 ; :headers {"Content-Type" "text/html; charset=utf-8} ; :body "Create Something"} ``` The body may be a function, which must accept the request as a parameter: ```clojure (defroutes myapp (GET "/" [] (fn [req] "Do something with req"))) ``` Or, you can just use the request directly: ```clojure (defroutes myapp (GET "/" req "Do something with req")) ``` Route patterns may include named parameters: ```clojure (defroutes myapp (GET "/hello/:name" [name] (str "Hello " name))) ``` You can adjust what each parameter matches by supplying a regex: ```clojure (defroutes myapp (GET ["/file/:name.:ext" :name #".*", :ext #".*"] [name ext] (str "File: " name ext))) ``` ### Middleware Clojure uses [Ring](https://github.com/ring-clojure/ring) for routing. Handlers are just functions that accept a request map and return a response map (Compojure will turn strings into 200 responses for you). You can easily write middleware that wraps all or part of your application to modify requests or responses: ```clojure (defroutes myapp (GET "/" req (str "Hello World v" (:app-version req)))) (defn wrap-version [handler] (fn [request] (handler (assoc request :app-version "1.0.1")))) (defn -main [] (run-server (wrap-version myapp) {:port 5000})) ``` [Ring-Defaults](https://github.com/ring-clojure/ring-defaults) provides some handy middlewares for sites and apis, so add it to your dependencies: ``` [ring/ring-defaults "0.1.1"] ``` Then, you can import it in your ns: ``` (ns myapp.core (:require [compojure.core :refer :all] [ring.middleware.defaults :refer :all] [org.httpkit.server :refer [run-server]])) ``` And use `wrap-defaults` to add the `site-defaults` middleware to your app: ``` (defn -main [] (run-server (wrap-defaults myapp site-defaults) {:port 5000})) ``` Now, your handlers may utilize query parameters: ```clojure (defroutes myapp (GET "/posts" req (let [title (get (:params req) :title) author (get (:params req) :author)] (str "Title: " title ", Author: " author)))) ``` Or, for POST and PUT requests, form parameters as well ```clojure (defroutes myapp (POST "/posts" req (let [title (get (:params req) :title) author (get (:params req) :author)] (str "Title: " title ", Author: " author)))) ``` ### Return values The return value of a route block determines the response body passed on to the HTTP client, or at least the next middleware in the ring stack. Most commonly, this is a string, as in the above examples. But, you may also return a [response map](https://github.com/mmcgrana/ring/blob/master/SPEC): ```clojure (defroutes myapp (GET "/" [] {:status 200 :body "Hello World"}) (GET "/is-403" [] {:status 403 :body ""}) (GET "/is-json" [] {:status 200 :headers {"Content-Type" "application/json"} :body "{}"})) ``` ### Static Files To serve up static files, use `compojure.route.resources`. Resources will be served from your project's `resources/` folder. ```clojure (require '[compojure.route :as route]) (defroutes myapp (GET "/") (route/resources "/")) ; Serve static resources at the root path (myapp {:uri "/js/script.js" :request-method :get}) ; => Contents of resources/public/js/script.js ``` ### Views / Templates To use templating with Compojure, you'll need a template library. Here are a few: #### [Stencil](https://github.com/davidsantiago/stencil) [Stencil](https://github.com/davidsantiago/stencil) is a [Mustache](http://mustache.github.com/) template library: ```clojure (require '[stencil.core :refer [render-string]]) (defroutes myapp (GET "/hello/:name" [name] (render-string "Hello {{name}}" {:name name}))) ``` You can easily read in templates from your resources directory. Here's a helper function ```clojure (require 'clojure.java.io) (defn read-template [filename] (slurp (clojure.java.io/resource filename))) (defroutes myapp (GET "/hello/:name" [name] (render-string (read-template "templates/hello.html") {:name name}))) ``` #### [Selmer](https://github.com/yogthos/Selmer) [Selmer](https://github.com/yogthos/Selmer) is a Django and Jinja2-inspired templating language: ```clojure (require '[selmer.parser :refer [render-file]]) (defroutes myapp (GET "/hello/:name" [name] (render-file "templates/hello.html" {:name name}))) ``` #### [Hiccup](https://github.com/weavejester/hiccup) [Hiccup](https://github.com/weavejester/hiccup) is a library for representing HTML as Clojure code ```clojure (require '[hiccup.core :as hiccup]) (defroutes myapp (GET "/hello/:name" [name] (hiccup/html [:html [:body [:h1 {:class "title"} (str "Hello " name)]]]))) ``` #### [Markdown](https://github.com/yogthos/markdown-clj) [Markdown-clj](https://github.com/yogthos/markdown-clj) is a Markdown implementation. ```clojure (require '[markdown.core :refer [md-to-html-string]]) (defroutes myapp (GET "/hello/:name" [name] (md-to-html-string "## Hello, world"))) ``` Further reading: * [Official Compojure Documentation](https://github.com/weavejester/compojure/wiki) * [Clojure for the Brave and True](http://www.braveclojure.com/) ================================================ FILE: coq.md ================================================ --- name: Coq filename: learncoq.v contributors: - ["Philip Zucker", "http://www.philipzucker.com/"] --- The Coq system is a proof assistant. It is designed to build and verify mathematical proofs. The Coq system contains the functional programming language Gallina and is capable of proving properties about programs written in this language. Coq is a dependently typed language. This means that the types of the language may depend on the values of variables. In this respect, it is similar to other related languages such as Agda, Idris, F*, Lean, and others. Via the Curry-Howard correspondence, programs, properties and proofs are formalized in the same language. Coq is developed in OCaml and shares some syntactic and conceptual similarity with it. Coq is a language containing many fascinating but difficult topics. This tutorial will focus on the programming aspects of Coq, rather than the proving. It may be helpful, but not necessary to learn some OCaml first, especially if you are unfamiliar with functional programming. This tutorial is based upon its OCaml equivalent The standard usage model of Coq is to write it with interactive tool assistance, which operates like a high powered REPL. Two common such editors are the CoqIDE and Proof General Emacs mode. Inside Proof General `Ctrl+C Ctrl+` will evaluate up to your cursor. ```coq (*** Comments ***) (* Comments are enclosed in (* and *). It's fine to nest comments. *) (* There are no single-line comments. *) (*** Variables and functions ***) (* The Coq proof assistant can be controlled and queried by a command language called the vernacular. Vernacular keywords are capitalized and the commands end with a period. Variable and function declarations are formed with the Definition vernacular. *) Definition x := 10. (* Coq can sometimes infer the types of arguments, but it is common practice to annotate with types. *) Definition inc_nat (x : nat) : nat := x + 1. (* There exists a large number of vernacular commands for querying information. These can be very useful. *) Compute (1 + 1). (* 2 : nat *) (* Compute a result. *) Check tt. (* tt : unit *) (* Check the type of an expressions *) About plus. (* Prints information about an object *) (* Print information including the definition *) Print true. (* Inductive bool : Set := true : Bool | false : Bool *) Search nat. (* Returns a large list of nat related values *) Search "_ + _". (* You can also search on patterns *) Search (?a -> ?a -> bool). (* Patterns can have named parameters *) Search (?a * ?a). (* Locate tells you where notation is coming from. Very helpful when you encounter new notation. *) Locate "+". (* Calling a function with insufficient number of arguments does not cause an error, it produces a new function. *) Definition make_inc x y := x + y. (* make_inc is nat -> nat -> nat *) Definition inc_2 := make_inc 2. (* inc_2 is nat -> nat *) Compute inc_2 3. (* Evaluates to 5 *) (* Definitions can be chained with "let ... in" construct. This is roughly the same to assigning values to multiple variables before using them in expressions in imperative languages. *) Definition add_xy : nat := let x := 10 in let y := 20 in x + y. (* Pattern matching is somewhat similar to switch statement in imperative languages, but offers a lot more expressive power. *) Definition is_zero (x : nat) := match x with | 0 => true | _ => false (* The "_" pattern means "anything else". *) end. (* You can define recursive function definition using the Fixpoint vernacular.*) Fixpoint factorial n := match n with | 0 => 1 | (S n') => n * factorial n' end. (* Function application usually doesn't need parentheses around arguments *) Compute factorial 5. (* 120 : nat *) (* ...unless the argument is an expression. *) Compute factorial (5-1). (* 24 : nat *) (* You can define mutually recursive functions using "with" *) Fixpoint is_even (n : nat) : bool := match n with | 0 => true | (S n) => is_odd n end with is_odd n := match n with | 0 => false | (S n) => is_even n end. (* As Coq is a total programming language, it will only accept programs when it can understand they terminate. It can be most easily seen when the recursive call is on a pattern matched out subpiece of the input, as then the input is always decreasing in size. Getting Coq to understand that functions terminate is not always easy. See the references at the end of the article for more on this topic. *) (* Anonymous functions use the following syntax: *) Definition my_square : nat -> nat := fun x => x * x. Definition my_id (A : Type) (x : A) : A := x. Definition my_id2 : forall A : Type, A -> A := fun A x => x. Compute my_id nat 3. (* 3 : nat *) (* You can ask Coq to infer terms with an underscore *) Compute my_id _ 3. (* An implicit argument of a function is an argument which can be inferred from contextual knowledge. Parameters enclosed in {} are implicit by default *) Definition my_id3 {A : Type} (x : A) : A := x. Compute my_id3 3. (* 3 : nat *) (* Sometimes it may be necessary to turn this off. You can make all arguments explicit again with @ *) Compute @my_id3 nat 3. (* Or give arguments by name *) Compute my_id3 (A:=nat) 3. (* Coq has the ability to extract code to OCaml, Haskell, and Scheme *) Require Extraction. Extraction Language OCaml. Extraction "factorial.ml" factorial. (* The above produces a file factorial.ml and factorial.mli that holds: type nat = | O | S of nat (** val add : nat -> nat -> nat **) let rec add n m = match n with | O -> m | S p -> S (add p m) (** val mul : nat -> nat -> nat **) let rec mul n m = match n with | O -> O | S p -> add m (mul p m) (** val factorial : nat -> nat **) let rec factorial n = match n with | O -> S O | S n' -> mul n (factorial n') *) (*** Notation ***) (* Coq has a very powerful Notation system that can be used to write expressions in more natural forms. *) Compute Nat.add 3 4. (* 7 : nat *) Compute 3 + 4. (* 7 : nat *) (* Notation is a syntactic transformation applied to the text of the program before being evaluated. Notation is organized into notation scopes. Using different notation scopes allows for a weak notion of overloading. *) (* Imports the Zarith module holding definitions related to the integers Z *) Require Import ZArith. (* Notation scopes can be opened *) Open Scope Z_scope. (* Now numerals and addition are defined on the integers. *) Compute 1 + 7. (* 8 : Z *) (* Integer equality checking *) Compute 1 =? 2. (* false : bool *) (* Locate is useful for finding the origin and definition of notations *) Locate "_ =? _". (* Z.eqb x y : Z_scope *) Close Scope Z_scope. (* We're back to nat being the default interpretation of "+" *) Compute 1 + 7. (* 8 : nat *) (* Scopes can also be opened inline with the shorthand % *) Compute (3 * -7)%Z. (* -21%Z : Z *) (* Coq declares by default the following interpretation scopes: core_scope, type_scope, function_scope, nat_scope, bool_scope, list_scope, int_scope, uint_scope. You may also want the numerical scopes Z_scope (integers) and Q_scope (fractions) held in the ZArith and QArith module respectively. *) (* You can print the contents of scopes *) Print Scope nat_scope. (* Scope nat_scope Delimiting key is nat Bound to classes nat Nat.t "x 'mod' y" := Nat.modulo x y "x ^ y" := Nat.pow x y "x ?= y" := Nat.compare x y "x >= y" := ge x y "x > y" := gt x y "x =? y" := Nat.eqb x y "x a end. (* A destructuring let is available if a pattern match is irrefutable *) Definition my_fst2 {A B : Type} (x : A * B) : A := let (a,b) := x in a. (*** Lists ***) (* Lists are built by using cons and nil or by using notation available in list_scope. *) Compute cons 1 (cons 2 (cons 3 nil)). (* (1 :: 2 :: 3 :: nil)%list : list nat *) Compute (1 :: 2 :: 3 :: nil)%list. (* There is also list notation available in the ListNotations modules *) Require Import List. Import ListNotations. Compute [1 ; 2 ; 3]. (* [1; 2; 3] : list nat *) (* There is a large number of list manipulation functions available, including: • length • head : first element (with default) • tail : all but first element • app : appending • rev : reverse • nth : accessing n-th element (with default) • map : applying a function • flat_map : applying a function returning lists • fold_left : iterator (from head to tail) • fold_right : iterator (from tail to head) *) Definition my_list : list nat := [47; 18; 34]. Compute List.length my_list. (* 3 : nat *) (* All functions in coq must be total, so indexing requires a default value *) Compute List.nth 1 my_list 0. (* 18 : nat *) Compute List.map (fun x => x * 2) my_list. (* [94; 36; 68] : list nat *) Compute List.filter (fun x => Nat.eqb (Nat.modulo x 2) 0) my_list. (* [18; 34] : list nat *) Compute (my_list ++ my_list)%list. (* [47; 18; 34; 47; 18; 34] : list nat *) (*** Strings ***) Require Import Strings.String. (* Use double quotes for string literals. *) Compute "hi"%string. Open Scope string_scope. (* Strings can be concatenated with the "++" operator. *) Compute String.append "Hello " "World". (* "Hello World" : string *) Compute "Hello " ++ "World". (* "Hello World" : string *) (* Strings can be compared for equality *) Compute String.eqb "Coq is fun!" "Coq is fun!". (* true : bool *) Compute "no" =? "way". (* false : bool *) Close Scope string_scope. (*** Other Modules ***) (* Other Modules in the standard library that may be of interest: • Logic : Classical logic and dependent equality • Arith : Basic Peano arithmetic • PArith : Basic positive integer arithmetic • NArith : Basic binary natural number arithmetic • ZArith : Basic relative integer arithmetic • Numbers : Various approaches to natural, integer and cyclic numbers (currently axiomatically and on top of 2^31 binary words) • Bool : Booleans (basic functions and results) • Lists : Monomorphic and polymorphic lists (basic functions and results), Streams (infinite sequences defined with co-inductive types) • Sets : Sets (classical, constructive, finite, infinite, power set, etc.) • FSets : Specification and implementations of finite sets and finite maps (by lists and by AVL trees) • Reals : Axiomatization of real numbers (classical, basic functions, integer part, fractional part, limit, derivative, Cauchy series, power series and results,...) • Relations : Relations (definitions and basic results) • Sorting : Sorted list (basic definitions and heapsort correctness) • Strings : 8-bit characters and strings • Wellfounded : Well-founded relations (basic results) *) (*** User-defined data types ***) (* Because Coq is dependently typed, defining type aliases is no different than defining an alias for a value. *) Definition my_three : nat := 3. Definition my_nat : Type := nat. (* More interesting types can be defined using the Inductive vernacular. Simple enumeration can be defined like so *) Inductive ml := OCaml | StandardML | Coq. Definition lang := Coq. (* Has type "ml". *) (* For more complicated types, you will need to specify the types of the constructors. *) (* Type constructors don't need to be empty. *) Inductive my_number := plus_infinity | nat_value : nat -> my_number. Compute nat_value 3. (* nat_value 3 : my_number *) (* Record syntax is sugar for tuple-like types. It defines named accessor functions for the components. Record types are defined with the notation {...} *) Record Point2d (A : Set) := mkPoint2d { x2 : A ; y2 : A }. (* Record values are constructed with the notation {|...|} *) Definition mypoint : Point2d nat := {| x2 := 2 ; y2 := 3 |}. Compute x2 nat mypoint. (* 2 : nat *) Compute mypoint.(x2 nat). (* 2 : nat *) (* Types can be parameterized, like in this type for "list of lists of anything". 'a can be substituted with any type. *) Definition list_of_lists a := list (list a). Definition list_list_nat := list_of_lists nat. (* Types can also be recursive. Like in this type analogous to built-in list of naturals. *) Inductive my_nat_list := EmptyList | NatList : nat -> my_nat_list -> my_nat_list. Compute NatList 1 EmptyList. (* NatList 1 EmptyList : my_nat_list *) (** Matching type constructors **) Inductive animal := Dog : string -> animal | Cat : string -> animal. Definition say x := match x with | Dog x => (x ++ " says woof")%string | Cat x => (x ++ " says meow")%string end. Compute say (Cat "Fluffy"). (* "Fluffy says meow". *) (** Traversing data structures with pattern matching **) (* Recursive types can be traversed with pattern matching easily. Let's see how we can traverse a data structure of the built-in list type. Even though the built-in cons ("::") looks like an infix operator, it's actually a type constructor and can be matched like any other. *) Fixpoint sum_list l := match l with | [] => 0 | head :: tail => head + (sum_list tail) end. Compute sum_list [1; 2; 3]. (* Evaluates to 6 *) (*** A Taste of Proving ***) (* Explaining the proof language is out of scope for this tutorial, but here is a taste to whet your appetite. Check the resources below for more. *) (* A fascinating feature of dependently type based theorem provers is that the same primitive constructs underly the proof language as the programming features. For example, we can write and prove the proposition A and B implies A in raw Gallina *) Definition my_theorem : forall A B, A /\ B -> A := fun A B ab => match ab with | (conj a b) => a end. (* Or we can prove it using tactics. Tactics are a macro language to help build proof terms in a more natural style and automate away some drudgery. *) Theorem my_theorem2 : forall A B, A /\ B -> A. Proof. intros A B ab. destruct ab as [ a b ]. apply a. Qed. (* We can easily prove simple polynomial equalities using the automated tactic ring. *) Require Import Ring. Require Import Arith. Theorem simple_poly : forall (x : nat), (x + 1) * (x + 2) = x * x + 3 * x + 2. Proof. intros. ring. Qed. (* Here we prove the closed form for the sum of all numbers 1 to n using induction *) Fixpoint sumn (n : nat) : nat := match n with | 0 => 0 | (S n') => n + (sumn n') end. Theorem sum_formula : forall n, 2 * (sumn n) = (n + 1) * n. Proof. intros n. induction n. - reflexivity. (* 0 = 0 base case *) - simpl. ring [IHn]. (* induction step *) Qed. ``` With this we have only scratched the surface of Coq. It is a massive ecosystem with many interesting and peculiar topics leading all the way up to modern research. ## Further reading * [The Coq reference manual](https://coq.inria.fr/refman/) * [Software Foundations](https://softwarefoundations.cis.upenn.edu/) * [Certified Programming with Dependent Types](http://adam.chlipala.net/cpdt/) * [Mathematical Components](https://math-comp.github.io/mcb/) * [Coq'Art: The Calculus of Inductive Constructions](http://www.cse.chalmers.se/research/group/logic/TypesSS05/resources/coq/CoqArt/) * [FRAP](http://adam.chlipala.net/frap/) ================================================ FILE: crystal.md ================================================ --- name: Crystal filename: learncrystal.cr contributors: - ["Vitalii Elenhaupt", "http://veelenga.com"] - ["Arnaud Fernandés", "https://github.com/TechMagister/"] - ["Valentin Baca", "https://github.com/valbaca/"] --- ```crystal # This is a comment # Everything is an object nil.class #=> Nil 100.class #=> Int32 true.class #=> Bool # Falsey values are: nil, false and null pointers !nil #=> true : Bool !false #=> true : Bool !0 #=> false : Bool # Integers 1.class #=> Int32 # Five signed integer types 1_i8.class #=> Int8 1_i16.class #=> Int16 1_i32.class #=> Int32 1_i64.class #=> Int64 1_i128.class #=> Int128 # Five unsigned integer types 1_u8.class #=> UInt8 1_u16.class #=> UInt16 1_u32.class #=> UInt32 1_u64.class #=> UInt64 1_u128.class #=> UInt128 2147483648.class #=> Int64 9223372036854775808.class #=> UInt64 # Binary numbers 0b1101 #=> 13 : Int32 # Octal numbers 0o123 #=> 83 : Int32 # Hexadecimal numbers 0xFE012D #=> 16646445 : Int32 0xfe012d #=> 16646445 : Int32 # Floats 1.0.class #=> Float64 # There are two floating point types 1.0_f32.class #=> Float32 1_f32.class #=> Float32 1e10.class #=> Float64 1.5e10.class #=> Float64 1.5e-7.class #=> Float64 # Chars use 'a' pair of single quotes 'a'.class #=> Char # Chars are 32-bit unicode 'あ' #=> 'あ' : Char # Unicode codepoint '\u0041' #=> 'A' : Char # Strings use a "pair" of double quotes "s".class #=> String # Strings are immutable s = "hello, " #=> "hello, " : String s.object_id #=> 134667712 : UInt64 s += "Crystal" s #=> "hello, Crystal" : String s.object_id #=> 142528472 : UInt64 # Supports interpolation "sum = #{1 + 2}" #=> "sum = 3" : String # Multiline string "This is multiline string" #=> "This is\n multiline string" # String with double quotes %(hello "world") #=> "hello \"world\"" # Symbols # Immutable, reusable constants represented internally as Int32 integer value. # They're often used instead of strings to efficiently convey specific, # meaningful values :symbol.class #=> Symbol sentence = :question? # :"question?" : Symbol sentence == :question? #=> true : Bool sentence == :exclamation! #=> false : Bool sentence == "question?" #=> false : Bool # Arrays [1, 2, 3].class #=> Array(Int32) [1, "hello", 'x'].class #=> Array(Char | Int32 | String) # Empty arrays should specify a type [] # Syntax error: for empty arrays use '[] of ElementType' [] of Int32 #=> [] : Array(Int32) Array(Int32).new #=> [] : Array(Int32) # Arrays can be indexed array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] : Array(Int32) array[0] #=> 1 : Int32 array[10] # raises IndexError array[-6] # raises IndexError array[10]? #=> nil : (Int32 | Nil) array[-6]? #=> nil : (Int32 | Nil) # From the end array[-1] #=> 5 # With a start index and size array[2, 3] #=> [3, 4, 5] # Or with range array[1..3] #=> [2, 3, 4] # Add to an array array << 6 #=> [1, 2, 3, 4, 5, 6] # Remove from the end of the array array.pop #=> 6 array #=> [1, 2, 3, 4, 5] # Remove from the beginning of the array array.shift #=> 1 array #=> [2, 3, 4, 5] # Check if an item exists in an array array.includes? 3 #=> true # Special syntax for an array of string and an array of symbols %w(one two three) #=> ["one", "two", "three"] : Array(String) %i(one two three) #=> [:one, :two, :three] : Array(Symbol) # There is a special array syntax with other types too, as long as # they define a .new and a #<< method set = Set{1, 2, 3} #=> Set{1, 2, 3} set.class #=> Set(Int32) # The above is equivalent to set = Set(typeof(1, 2, 3)).new #=> Set{} : Set(Int32) set << 1 #=> Set{1} : Set(Int32) set << 2 #=> Set{1, 2} : Set(Int32) set << 3 #=> Set{1, 2, 3} : Set(Int32) # Hashes {1 => 2, 3 => 4}.class #=> Hash(Int32, Int32) {1 => 2, 'a' => 3}.class #=> Hash(Char| Int32, Int32) # Empty hashes must specify a type {} # Syntax Error: for empty hashes use '{} of KeyType => ValueType' {} of Int32 => Int32 # {} : Hash(Int32, Int32) Hash(Int32, Int32).new # {} : Hash(Int32, Int32) # Hashes can be quickly looked up by key hash = {"color" => "green", "number" => 5} hash["color"] #=> "green" hash["no_such_key"] #=> Missing hash key: "no_such_key" (KeyError) hash["no_such_key"]? #=> nil # The type of the returned value is based on all key types hash["number"] #=> 5 : (Int32 | String) # Check existence of keys hash hash.has_key? "color" #=> true # Special notation for symbol and string keys {key1: 'a', key2: 'b'} # {:key1 => 'a', :key2 => 'b'} {"key1": 'a', "key2": 'b'} # {"key1" => 'a', "key2" => 'b'} # Special hash literal syntax with other types too, as long as # they define a .new and a #[]= methods class MyType def []=(key, value) puts "do stuff" end end MyType{"foo" => "bar"} # The above is equivalent to tmp = MyType.new tmp["foo"] = "bar" tmp # Ranges 1..10 #=> Range(Int32, Int32) Range.new(1, 10).class #=> Range(Int32, Int32) # Can be inclusive or exclusive (3..5).to_a #=> [3, 4, 5] (3...5).to_a #=> [3, 4] # Check whether range includes the given value or not (1..8).includes? 2 #=> true # Tuples are a fixed-size, immutable, stack-allocated sequence of values of # possibly different types. {1, "hello", 'x'}.class #=> Tuple(Int32, String, Char) # Access tuple's value by its index tuple = {:key1, :key2} tuple[1] #=> :key2 tuple[2] #=> Error: index out of bounds for Tuple(Symbol, Symbol) (2 not in -2..1) # Can be expanded into multiple variables a, b, c = {:a, 'b', "c"} a #=> :a b #=> 'b' c #=> "c" # Procs represent a function pointer with an optional context (the closure data) # It is typically created with a proc literal proc = ->(x : Int32) { x.to_s } proc.class # Proc(Int32, String) # Or using the new method Proc(Int32, String).new { |x| x.to_s } # Invoke proc with call method proc.call 10 #=> "10" # Control statements if true "if statement" elsif false "else-if, optional" else "else, also optional" end puts "if as a suffix" if true # If as an expression a = if 2 > 1 3 else 4 end a #=> 3 # Ternary if a = 1 > 2 ? 3 : 4 #=> 4 # Case statement cmd = "move" action = case cmd when "create" "Creating..." when "copy" "Copying..." when "move" "Moving..." when "delete" "Deleting..." end action #=> "Moving..." # Loops index = 0 while index <= 3 puts "Index: #{index}" index += 1 end # Index: 0 # Index: 1 # Index: 2 # Index: 3 index = 0 until index > 3 puts "Index: #{index}" index += 1 end # Index: 0 # Index: 1 # Index: 2 # Index: 3 # But the preferable way is to use each (1..3).each do |index| puts "Index: #{index}" end # Index: 1 # Index: 2 # Index: 3 # Variable's type depends on the type of the expression # in control statements if a < 3 a = "hello" else a = true end typeof(a) #=> (Bool | String) if a && b # here both a and b are guaranteed not to be Nil end if a.is_a? String a.class #=> String end # Functions def double(x) x * 2 end # Functions (and all blocks) implicitly return the value of the last statement double(2) #=> 4 # Parentheses are optional where the call is unambiguous double 3 #=> 6 double double 3 #=> 12 def sum(x, y) x + y end # Method arguments are separated by a comma sum 3, 4 #=> 7 sum sum(3, 4), 5 #=> 12 # yield # All methods have an implicit, optional block parameter # it can be called with the 'yield' keyword def surround puts '{' yield puts '}' end surround { puts "hello world" } # { # hello world # } # You can pass a block to a function # "&" marks a reference to a passed block def guests(&block) block.call "some_argument" end # You can pass a list of arguments, which will be converted into an array # That's what splat operator ("*") is for def guests(*array) array.each { |guest| puts guest } end # If a method returns an array, you can use destructuring assignment def foods ["pancake", "sandwich", "quesadilla"] end breakfast, lunch, dinner = foods breakfast #=> "pancake" dinner #=> "quesadilla" # By convention, all methods that return booleans end with a question mark 5.even? # false 5.odd? # true # Also by convention, if a method ends with an exclamation mark, it does # something destructive like mutate the receiver. # Some methods have a ! version to make a change, and # a non-! version to just return a new changed version fruits = ["grapes", "apples", "bananas"] fruits.sort #=> ["apples", "bananas", "grapes"] fruits #=> ["grapes", "apples", "bananas"] fruits.sort! #=> ["apples", "bananas", "grapes"] fruits #=> ["apples", "bananas", "grapes"] # However, some mutating methods do not end in ! fruits.shift #=> "apples" fruits #=> ["bananas", "grapes"] # Define a class with the class keyword class Human # A class variable. It is shared by all instances of this class. @@species = "H. sapiens" # An instance variable. Type of name is String @name : String # Basic initializer # Assign the argument to the "name" instance variable for the instance # If no age given, we will fall back to the default in the arguments list. def initialize(@name, @age = 0) end # Basic setter method def name=(name) @name = name end # Basic getter method def name @name end # The above functionality can be encapsulated using the property method as follows property :name # Getter/setter methods can also be created individually like this getter :name setter :name # A class method uses self to distinguish from instance methods. # It can only be called on the class, not an instance. def self.say(msg) puts msg end def species @@species end end # Instantiate a class jim = Human.new("Jim Halpert") dwight = Human.new("Dwight K. Schrute") # Let's call a couple of methods jim.species #=> "H. sapiens" jim.name #=> "Jim Halpert" jim.name = "Jim Halpert II" #=> "Jim Halpert II" jim.name #=> "Jim Halpert II" dwight.species #=> "H. sapiens" dwight.name #=> "Dwight K. Schrute" # Call the class method Human.say("Hi") #=> print Hi and returns nil # Variables that start with @ have instance scope class TestClass @var = "I'm an instance var" end # Variables that start with @@ have class scope class TestClass @@var = "I'm a class var" end # Variables that start with a capital letter are constants Var = "I'm a constant" Var = "can't be updated" # Error: already initialized constant Var # Class is also an object in Crystal. So a class can have instance variables. # Class variable is shared among the class and all of its descendants. # base class class Human @@foo = 0 def self.foo @@foo end def self.foo=(value) @@foo = value end end # derived class class Worker < Human end Human.foo #=> 0 Worker.foo #=> 0 Human.foo = 2 #=> 2 Worker.foo #=> 0 Worker.foo = 3 #=> 3 Human.foo #=> 2 Worker.foo #=> 3 module ModuleExample def foo "foo" end end # Including modules binds their methods to the class instances # Extending modules binds their methods to the class itself class Person include ModuleExample end class Book extend ModuleExample end Person.foo # => undefined method 'foo' for Person:Class Person.new.foo # => 'foo' Book.foo # => 'foo' Book.new.foo # => undefined method 'foo' for Book # Exception handling # Define new exception class MyException < Exception end # Define another exception class MyAnotherException < Exception; end ex = begin raise MyException.new rescue ex1 : IndexError "ex1" rescue ex2 : MyException | MyAnotherException "ex2" rescue ex3 : Exception "ex3" rescue ex4 # catch any kind of exception "ex4" end ex #=> "ex2" ``` ## Additional resources - [Official Documentation](https://crystal-lang.org/) ================================================ FILE: cs/bf.md ================================================ --- contributors: - ["Prajit Ramachandran", "http://prajitr.github.io/"] - ["Mathias Bynens", "http://mathiasbynens.be/"] translators: - ["Vojta Svoboda", "https://github.com/vojtasvoboda/"] filename: learnbrainfuck.bf --- Brainfuck (psaný bez kapitálek s vyjímkou začátku věty) je extrémně minimální Turingovsky kompletní (ekvivalentní) programovací jazyk a má pouze 8 příkazů. Můžete si ho vyzkoušet přímo v prohlížeči s [brainfuck-visualizer](http://fatiherikli.github.io/brainfuck-visualizer/). ```bf Jakýkoliv znak mimo "><+-.,[]" (bez uvozovek) je ignorován. Brainfuck je reprezentován jako pole, které má 30.000 buněk s počátkem v nule a datovým ukazatelem na aktuální buňce. Můžeme využít těchto osm příkazů: + : Přičte k aktuální buňce jedničku. - : Odečte od aktuální buňky jedničku. > : Posune datový ukazatel na další buňku, která je napravo. < : Posune datový ukazatel na předchozí buňku, která je nalevo. . : Vytiskne ASCII hodnotu aktuální buňky (například 65 = 'A'). , : Načte jeden znak do aktuální buňky. [ : Pokud je hodnota aktuální buňky nulová, přeskočí na buňku odpovídající ] . Jinak skočí na další instrukci. ] : Pokud je hodnota aktuální buňky nulova, přeskočí na další instrukci. Jinak skočí zpět na instrukci odpovídající [ . [ a ] tak tvoří 'while' smyčku a tyto symboly musí tak být v páru. Pojďme se mrknout na některé brainfuck programy. ++++++ [ > ++++++++++ < - ] > +++++ . Tento program vypíše písmeno 'A' (v ASCII je to číslo 65). Nejdříve navýší buňku #1 na hodnotu 6. Buňka #1 bude použita pro smyčku. Potom program vstoupí do smyčky ([) a sníží hodnotu buňky #1 o jedničku. Ve smyčce zvýší hodnotu buňky #2 desetkrát, vrátí ze zpět na buňku #1 a sníží její hodnotu o jedničku. Toto se stane šestkrát (je potřeba šestkrát snížit hodnotu buňky #1, aby byla nulová a program přeskočil na konec cyklu označený znakem ]. Na konci smyčky, kdy jsme na buňce #1 (která má hodnotu 0), tak má buňka #2 hodnotu 60. Přesuneme se na buňku #2 a pětkrát zvýšíme její hodnotu o jedničku na hodnotu 65. Na konci vypíšeme hodnotu buňky #2 - 65, což je v ASCII znak 'A' na terminálu. , [ > + < - ] > . Tento program přečte znak z uživatelského vstupu a zkopíruje ho do buňky #1. Poté začne smyčka - přesun na buňku #2, zvýšení hodnoty buňky #2 o jedničku, přesun zpět na buňku #1 a snížení její hodnoty o jedničku. Takto smyčka pokračuje do té doby, než je buňka #1 nulová a buňka #2 nabyde původní hodnotu buňky #1. Protože jsme na buňce #1, přesuneme se na buňku #2 a vytiskneme její hodnotu v ASCII. Je dobré vědět, že mezery jsou v programu uvedené pouze z důvodu čitelnosti. Program je možné klidně zapsat i takto: ,[>+<-]>. Nyní se podívejte na tento program a zkuste zjistit co dělá: ,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> Tento program vezme dvě čísla ze vstupu a vynásobí je. Program nejdříve načte dvě vstupní hodnoty. Poté začíná smyčka řízená hodnotou v buňce #1 - přesun na buňku #2 a start druhé vnořené smyčky, která je řízená hodnotou v buňce #2 a zvyšuje hodnotu v buňce #3. Nicméně je zde problém kdy na konci vnitřní smyčky je v buňce #2 nula a smyčka by tak znovu napokračovala. Vyřešíme to tak, že zvyšujeme o jedničku i buňku #4 a její hodnotu poté překopírujeme do buňky #2. Na konci programu je v buňce #3 výsledek. ``` A to je brainbuck. Zase tak složitý není, co? Zkuste si nyní napsat nějaký vlastní brainfuck program a nebo interpretr v jiném jazyce, což není zase tak složité, ale pokud jste opravdový masochista, zkuste si naprogramovat interpretr jazyka brainfuck v jazyce... brainfuck :) ================================================ FILE: cs/css.md ================================================ --- contributors: - ["Mohammad Valipour", "https://github.com/mvalipour"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["Geoffrey Liu", "https://github.com/g-liu"] - ["Connor Shea", "https://github.com/connorshea"] - ["Deepanshu Utkarsh", "https://github.com/duci9y"] translators: - ["Michal Martinek", "https://github.com/MichalMartinek"] --- V ranných dobách webu se nevyskytovaly žádné vizuální elementy, pouze čistý text, ale s vývojem webových browserů se staly stránky plné grafických prvků běžné. A právě proto vzniklo CSS, aby oddělilo obsah (HTML) od vzhledu webové stránky. Pomocí CSS můžete označit různé elementy na HTML stránce a přiřadit jim různé vzhledové vlastnosti. Tento návod byl napsán pro CSS 2, avšak CSS 3 se stalo velmi oblíbené a v dnešní době už běžné. **POZNÁMKA** Protože CSS produkuje vizuální výsledky, je nutné k jeho naučení všechno zkoušet třeba na [dabbletu](http://dabblet.com/). Tento článek se zaměřuje hlavně na syntaxi a poskytue také pár obecných tipů. ```css /* komentáře jsou ohraničeny lomítkem s hvězdičkou, přesně jako tyto dva řádky, v CSS není nic jako jednořádkový komentář, pouze tenhle zápis */ /* ################ ## SELEKTORY ################ */ /* Selektor se používá pro vybrání elementu na stránce: selektor { vlastnost: hodnota; /* více vlastností... }*/ /* Toto je náš element:
*/ /* Můžeme vybrat tento element třeba podle jeho třídy */ .trida1 { } /* nebo obou tříd! */ .trida1.trida2 { } /* nebo jeho jména */ div { } /* nebo jeho id */ #nejakeID { } /* nebo podle toho, že má atribut! */ [attr] { font-size:smaller; } /* nebo že argument nabývá specifické hodnoty*/ [attr='hodnota'] { font-size:smaller; } /* začíná nějakou hodnotou (CSS 3) */ [attr^='ho'] { font-size:smaller; } /* nebo končí něčím (CSS 3) */ [attr$='ta'] { font-size:smaller; } /* nebo obsahuje nějakou hodnotu, která je v atributu oddělená mezerami */ [otherAttr~='co'] { } [otherAttr~='neco'] { } /* nebo obsahuje hodnotu oddělenou pomlčkou - "-" (U+002D) */ [otherAttr|='cs'] { font-size:smaller; } /* Můžeme spojit různé selektory, abychom získali specifičtější selektor. Pozor, nedávejte mezi ně mezery! */ div.nejaka-trida[attr$='ta'] { } /* Můžeme vybrat element, který je potomek jineho */ div.vnejsi-element > .jmeno-tridy { } /* nebo zanořen ještě hlouběji. Potomci jsou přímo pod vnější třídou, pouze 1 úroveň pod rodičem. Tento selektor bude fungovat na jakékoliv úrovni pod rodičem */ div.rodic .jmeno-tridy { } /* Varování: stejný selektor bez mezery má úplně jiný význam Vzpomínáte si jaký? */ div.rodic.jmeno-tridy { } /* Možná budete chtít vybrat element, který leží přímo vedle */ .jsem-primo-pred + .timto-elementem { } /* nebo kdekoliv na stejné úrovni stromu */ .jsem-kdekoliv-pred ~ .timto-elementem { } /* Existují selektory nazvané pseudo třídy, kterými můžeme vybrat elementy, když jsou v určitém stavu */ /* na příklad, když kurzor najede na element */ selektor:hover { } /* nebo již navštívený odkaz */ selektor:visited { } /* nebo nebyl navštíven */ selektor:link { } /* nebo když je vybrán, např kliknutím do inputu*/ selektor:focus { } /* element, ktery je prvni potomek rodiče */ selektor:first-child {} /* element, který je poslední potomek rodiče */ selektor:last-child {} /* Stejně jako pseudo třídy, umožňují pseudo elementy stylizovat určité části dokumentu */ /* odpovídá virtuálnímu prvnímu potomku */ selektor::before {} /* odpovídá virtuálnímu poslednímu potomku */ selektor::after {} /* Na vhodném místě, může být použitá hvězdička jako žolík, který vybere každý element */ * { } /* všechny elementy */ .rodic * { } /* všechny vnořené elementy */ .rodic > * { } /* všichni potomci */ /* #################### ## VLASTNOSTI #################### */ selektor { /* Jednotky délky můžou být relativní nebo absolutní */ /* Relativní jednotky */ width: 50%; /* počet procent šířky rodičovského elementu */ font-size: 2em; /* násobek puvodní velikosti fontu elementu */ font-size: 2rem; /* nebo kořenového elementu */ font-size: 2vw; /* násobek 1% šířky zařízení (viewport) (CSS 3) */ font-size: 2vh; /* nebo jeho výšky */ font-size: 2vmin; /* násobek 1% výšky nebo šířky, dle toho, co je menší */ font-size: 2vmax; /* nebo větší */ /* Absolutní jednotky */ width: 200px; /* pixely */ font-size: 20pt; /* body */ width: 5cm; /* centimetry */ min-width: 50mm; /* milimetry */ max-width: 5in; /* palce */ /* Barvy */ color: #F6E; /* krátký hexadecimální formát */ color: #FF66EE; /* dlouhý hexadecimální formát */ color: tomato; /* pojmenovaná barva */ color: rgb(255, 255, 255); /* hodnoty rgb */ color: rgb(10%, 20%, 50%); /* procenta rgb */ color: rgba(255, 0, 0, 0.3); /* hodnoty rgba (CSS 3) Poznámka: 0 < a < 1 */ color: transparent; /* ekvivalentní jako nastavení alfy 0 */ color: hsl(0, 100%, 50%); /* procenta hsl (CSS 3) */ color: hsla(0, 100%, 50%, 0.3); /* procenta hsl s alfou */ /* Obrázky jako pozadí elementu */ background-image: url(/cesta/k/obrazku.jpg); /* uvozovky jsou dobrovolné */ /* Fonty */ font-family: Arial; /* když název fontu obsahuje mezeru, tak musí být v uvozovkách */ font-family: "Courier New"; /* když se první nenaleze, použije se další atd. */ font-family: "Courier New", Trebuchet, Arial, sans-serif; } ``` ## Použití Uložte CSS soubor s příponou `.css`. ```xml
``` ## Priorita nebo kaskáda Element může být vybrán více selektory a jeho vlastnosti můžou být nastaveny více než jednou. V těchto případech, má jedno zadání vlastnosti prioritu před druhým. Obecně platí, že více specifické selektory mají přednost před těmi méně specifickými. Tento proces se nazývá kaskáda, proto i název kaskádové styly(Cascading Style Sheets). Máme následující CSS ```css /* A */ p.trida1[attr='hodnota'] /* B */ p.trida1 { } /* C */ p.trida2 { } /* D */ p { } /* E */ p { vlastnost: hodnota !important; } ``` a tento element ```xml

``` Priorita stylu je následující. Pamatujte, priorita pro každou **vlastnost**, ne pro celý blok. * `E` má nejvyšší prioritu kvůli slůvku `!important`. Je doporučováno se úplně vyhnout jeho použití. * `F` je další, kvůli stylu zadanému přimo do elementu * `A` je další, protože je více specifické, než cokoliv dalšího. Má 3 selektory: jméno elementu `p`, jeho třídu `trida1`, atribut `attr='hodnota'`. * `C` je další, i když je stejně specifický jako `B`, protože je uveden až po něm. * `B` je další * `D` je poslední ## Kompatibilita Většina z možností v CSS 2 (a spousta v CSS 3) je dostupná napříč všemi browsery a zařízeními. Ale pořád je dobrá praxe, zkontrolovat dostupnost, před užitím nové vlastnosti/fičury. ## Zdroje * Přehled dostupnosti [CanIUse](http://caniuse.com). * CSS hřiště [Dabblet](http://dabblet.com/). * [Mozilla Developer Network - CSS dokumentace](https://developer.mozilla.org/en-US/docs/Web/CSS) * [Codrops](http://tympanus.net/codrops/css_reference/) ## Další čtení * [Pochopení priority v CSS: specifičnost, děditelnost a kaskáda](http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/) * [Vybírání elementů pomocí atributů](https://css-tricks.com/almanac/selectors/a/attribute/) * [QuirksMode CSS](http://www.quirksmode.org/css/) * [Z-Index - překrývání obsahu](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context) * [SASS](http://sass-lang.com/) a [LESS](http://lesscss.org/) pro CSS pre-processing * [CSS-Triky](https://css-tricks.com) ================================================ FILE: cs/elm.md ================================================ --- contributors: - ["Max Goldstein", "http://maxgoldste.in/"] translators: - ["Robin Pokorný", "http://robinpokorny.com/"] --- Elm je funkcionální reaktivní jazyk, který se kompiluje do (klientského) JavaScriptu. Elm je silně typovaný, díky tomu je překladač schopen zachytit většinu chyb okamžitě a vypsat snadno srozumitelná chybová hlášení. Elm se hodí k tvorbě webových uživatelských rozhraní a her. ```haskell -- Jednořádkové komentáře začínají dvěma pomlčkami. {- Víceřádkové komentáře mohou být takto uzavřeny do bloku. {- Mohou být i zanořeny. -} -} {-- Základy --} -- Aritmetika 1 + 1 -- 2 8 - 1 -- 7 10 * 2 -- 20 -- Každé číslo bez desetinné tečky je typu Int nebo Float. 33 / 2 -- 16.5 s reálným dělením 33 // 2 -- 16 s celočíselným dělením -- Umocňování 5 ^ 2 -- 25 -- Pravdivostní proměnné not True -- False not False -- True 1 == 1 -- True 1 /= 1 -- False 1 < 10 -- True -- Řetězce a znaky "Toto je textový řetězec, protože používá dvojité uvozovky." 'a' -- znak v jednoduchých uvozovkách -- Řetězce lze spojovat. "Ahoj " ++ "světe!" -- "Ahoj světe!" {-- Seznamy (List), n-tice (Tuple) a Záznamy (Record) --} -- Každá položka seznamu musí být stejného typu. ["příliš", "žluťoučký", "kůň", "úpěl"] [1, 2, 3, 4, 5] -- Druhý příklad lze zapsat také pomocí dvou teček. List.range 1 5 -- Spojovat seznamy lze stejně jako řetězce. List.range 1 5 ++ List.range 6 10 == List.range 1 10 -- True -- K přidání položky do seznamu použijte funkci "cons". 0 :: List.range 1 5 -- [0, 1, 2, 3, 4, 5] -- Funkce "head" pro získání první položky seznamu i funkce "tail" pro získání následujích položek -- vrací typ Maybe. Místo zjišťování, jestli nějaká položka není null, -- se s chybějcími hodnotami vypořádáme explicitně. List.head (List.range 1 5) -- Just 1 List.tail (List.range 1 5) -- Just [2, 3, 4, 5] List.head [] -- Nothing -- List.nazevFunkce odkazuje na funkci, která žije v modulu List. -- Každý prvek v n-tici může být jiného typu, ale n-tice má pevný počet prvků. ("elm", 42) -- K získání hodnot z dvojice použijte funkce first a second. -- (Toto je pouze zkratka. Brzy si ukážeme, jak na to "správně".) Tuple.first ("elm", 42) -- "elm" Tuple.second ("elm", 42) -- 42 -- Prázná n-tice, neboli "unit", se občas používá jako zástupný symbol. -- Je to jediná hodnota svého typu, který se také nazývá "Unit". () -- Záznamy jsou podobné n-ticím, ale prvky jsou pojmenovány. Na pořadí nezáleží. -- Povšimněte si, že hodnoty vlastností se přiřazují rovnítky, ne dvojtečkami. { x = 3, y = 7 } -- K hodnotám se přistupuje pomocí tečky a názvu vlastnosti. { x = 3, y = 7 }.x -- 3 -- Nebo využitím přístupové funkce, což je jen tečka a název vlastnosti. .y { x = 3, y = 7 } -- 7 -- Změna hodnoty vlastnosti v záznamu. (Záznam tuto vlastnost už musí mít.) { osoba | jmeno = "Jiří" } -- Změna více vlastností s využitím aktuálních hodnot. { hmotnyBod | poloha = hmotnyBod.poloha + hmotnyBod.rychlost, rychlost = hmotnyBod.rychlost + hmotnyBod.zrychleni } {-- Řídicí struktury --} -- Podmínky vždy musí mít větev "else" a obě větve musí být stejného typu. if powerLevel > 9000 then "PÁNI!" else "hmm" -- Podmínky lze skládat za sebe. if n < 0 then "n je záporné" else if n > 0 then "n je kladné" else "n je nula" -- Použíjte příkaz "case" k nalezení shody vzoru a různých možností. case seznam of [] -> "odpovídá práznému seznamu" [x]-> "odpovídá seznamu o právě jedné položce, " ++ toString x x::xs -> "odpovídá seznamu o alespoň jedné položce, jehož prvním prvkem je " ++ toString x -- Shody se vyhodnocují v zapsaném pořadí. Kdybychom umístili [x] poslední, nikdy by nenastala shoda, -- protože x::xs také odpovídá (xs by byl prázdný seznam). Shody "nepropadají". -- Překladač vždy upozorní na chybějící nebo přebývající větve. -- Větvení typu Maybe. case List.head seznam of Just x -> "První položka je " ++ toString x Nothing -> "Seznam byl prázdný." {-- Funkce --} -- Syntaxe funkcí je v Elmu velmi úsporná, založená spíše na mezerách -- než na závorkách. Neexistuje tu klíčové slovo "return". -- Funkci definujeme jejím jménem, parametry, rovnítkem a tělem. vynasob a b = a * b -- Funkci voláme předáním parametrů (bez oddělujících čárek). vynasob 7 6 -- 42 -- Částečně aplikované funkci předáme pouze některé parametry. -- Poté zvolíme nové jméno. zdvoj = vynasob 2 -- Konstanty jsou podobné, ale nepřijímají žádné parametry. odpoved = 42 -- Předejte funkci jako parametr jiným funkcím. List.map zdvoj (List.range 1 4) -- [2, 4, 6, 8] -- Nebo použijte anonymní funkci. List.map (\a -> a * 2) (List.range 1 4) -- [2, 4, 6, 8] -- V definici funkce lze zapsat vzor, může-li nastat pouze jeden případ. -- Tato funkce přijímá jednu dvojici místo dvou parametrů. obsah (sirka, delka) = sirka * delka obsah (6, 7) -- 42 -- Složenými závorkami vytvořte vzor pro názvy vlastností v záznamu. -- Použijte "let" k definici lokálních proměnných. objem {sirka, delka, hloubka} = let obsah = sirka * delka in obsah * hloubka objem { sirka = 3, delka = 2, hloubka = 7 } -- 42 -- Funkce mohou být rekurzivní. fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2) List.map fib (List.range 0 8) -- [1, 1, 2, 3, 5, 8, 13, 21, 34] -- Jiná rekurzivní funkce (v praxi použijte List.length). delkaSeznamu seznam = case seznam of [] -> 0 x::xs -> 1 + delkaSeznamu xs -- Funkce se volají před jakýmkoli infixovým operátorem. Závorky určují prioritu. cos (degrees 30) ^ 2 + sin (degrees 30) ^ 2 -- 1 -- Nejprve se aplikuje "degrees" na číslo 30, výsledek je pak předán trigonometrickým -- funkcím, které jsou následně umocněny na druhou, na závěr proběhne sčítání. {-- Typy a typové anotace --} -- Překladač odvodí typ každé hodnoty ve vašem programu. -- Typy vždy začínají velkým písmenem. Čtete x : T jako "x je typu T". -- Některé běžné typy, které můžete videt v Elmovém REPLu. 5 : Int 6.7 : Float "ahoj" : String True : Bool -- Funkce mají také typy. Čtěte "->" jako "vrací". -- O typu na konci uvažujte jako návratovém typu, o ostatních jako typech argumentů. not : Bool -> Bool round : Float -> Int -- Když definujete hodnotu, je dobrým zvykem zapsat nad ni její typ. -- Anotace je formou dokumentace, která je ověřována překladačem. zdvoj : Int -> Int zdvoj x = x * 2 -- Funkce jako parametr je uzavřena v závorkách. -- Typy s malým počátečním písmenem jsou typové proměnné: -- mohou být libovolného typu, ale v každém volání musí být stejné. List.map : (a -> b) -> List a -> List b -- "List tečka map je typu a-vrací-b, vrací seznam-položek-typu-a, vrací seznam-položek-typu-b." -- Existují tři speciální typové proměnné: -- číslo (number), porovnatelné (comparable), and spojitelné (appendable). -- Čísla dovolují použít aritmetiku na Int a Float. -- Porovnatelné dovolují uspořádat čísla a řetězce, např. a < b. -- Spojitelné lze zřetězit pomocí a ++ b. {-- Typové aliasy a výčtové typy --} -- Pro záznamy a n-tice již typy automaticky existují. -- (Povšimněte si, že typ vlatnosti záznamu přiřazujeme dvojtečkou a hodnotu rovnítkem.) pocatek : { x : Float, y : Float, z : Float } pocatek = { x = 0, y = 0, z = 0 } -- Stávajícím typům lze dávat jména využitím aliasů. type alias Bod3D = { x : Float, y : Float, z : Float } -- Alias pro záznam funguje také jako jeho konstruktor. jinyPocatek : Bod3D jinyPocatek = Bod3D 0 0 0 -- Jedná se stále o stejný typ, lze je tedy porovnat. pocatek == jinyPocatek -- True -- Oproti tomu výčtový (union) typ definuje zcela nový typ. -- Výčtový typ se takto jmenuje, protože může být jedním z několika vybraných možností. -- Každá možnost je reprezentována jako "tag". type Smer = Sever | Jih | Vychod | Zapad -- Tagy mohou obsahovat další hodnoty známých typů. Lze využít i rekurze. type IntStrom = Vrchol | Uzel Int IntStrom IntStrom -- "Vrchol" i "Uzel" jsou tagy. Vše, co následuje za tagem, je typ. -- Tagy lze použít jako hodnoty funkcí. koren : IntStrom koren = Vrchol 7 List List -- Výčtové typy (a typové aliasy) mohou obsahovat typové proměnné. type Strom a = Vrchol | Uzel a (Strom a) (Strom a) -- "Typ strom-prvků-a je vrchol, nebo uzel obsahující a, strom-prvků-a a strom-prvků-a." -- Vzory se shodují s tagy. Tagy s velkým počátečním písmenem odpovídají přesně. -- Proměnné malým písmem odpovídají čemukoli. Podtržítko také odpovídá čemukoli, -- ale určuje, že tuto hodnotu dále nechceme používat. nejviceVlevo : Strom a -> Maybe a nejviceVlevo strom = case strom of Vrchol -> Nothing Uzel x Vrchol _ -> Just x Uzel _ podstrom _ -> nejviceVlevo podstrom -- To je víceméně vše o jazyku samotném. -- Podívejme se nyní, jak organizovat a spouštět náš kód. {-- Moduly a importování --} -- Standardní knihovny jsou organizovány do modulů, stejně jako knihovny třetích stran, -- které můžete využívat. Ve větších projektech můžete definovat vlastní moduly. -- Vložte toto na začátek souboru. Pokud nic neuvedete, předpokládá se "Main". module Jmeno where -- Výchozím chováním je, že se exportuje vše. -- Případně můžete definovat exportované vlastnosti explicitně. module Jmeno (MujTyp, mojeHodnota) where -- Běžný návrhový vzor je expotovat pouze výčtový typ bez jeho tagů. -- Tento vzor je znám jako krycí typ a často se využívá v knihovnách. -- Z jiných modulů lze importovat kód a použít jej v aktuálním modulu. -- Nasledující umístí Dict do aktuálního scope, takže lze volat Dict.insert. import Dict -- Importuje modul Dict a typ Dict, takže v anotacích není nutné psát Dict.Dict. -- Stále lze volat Dict.insert. import Dict exposing (Dict) -- Přejmenování importu. import Graphics.Collage as C {-- Porty --} -- Port oznamuje, že budete komunikovat s vnějším světem. -- Porty jsou dovoleny pouze v modulu Main. -- Příchozí port je jen typová anotace. port idKlienta : Int -- Odchozí port má definici. port objednavkaKlienta : List String port objednavkaKlienta = ["Knihy", "Potraviny", "Nábytek"] -- Nebudeme zacházet do detailů, ale v JavaScriptu se dají nastavit -- callbacky pro zasílání na příchozí porty a čtení z odchozích portů. {-- Nástroje pro příkazovou řádku --} -- Kompilace souboru. $ elm make MujSoubor.elm -- Při prvním spuštění nainstaluje Elm standardní knihovny a vytvoří soubor -- elm-package.json, kde jsou uloženy informace o vašem projektu. -- Elm reactor je server, který překládá a spouští vaše soubory. -- Kliknutím na klíč vedle názvu souboru spustíte debugger s cestovám v čase! $ elm reactor -- Zkoušejte si jednoduché příkazy v Read-Eval-Print Loop. $ elm repl -- Balíčky jsou určeny uživatelským jménem na GitHubu a názvem repozitáře. -- Nainstalujte nový balíček a uložte jej v souboru elm-package.json. $ elm package install evancz/elm-lang/html -- Porovnejte změny mezi verzemi jednoho balíčku. $ elm package diff elm-lang/html 1.1.0 2.0.0 -- Správce balíčků v Elmu vyžaduje sémantické verzování, -- takže minor verze nikdy nerozbije váš build. ``` Jazyk Elm je překvapivě malý. Nyní se můžete podívat do skoro jakéhokoli zdrojového kódu v Elmu a budete mít zběžnou představu o jeho fungování. Ovšem možnosti, jak psát kód, který je odolný vůči chybám a snadno se refaktoruje, jsou neomezené! Zde jsou některé užitečné zdroje (v angličtině). * [Hlavní stránka Elmu](http://elm-lang.org/). Obsahuje: * Odkazy na [instalátory](http://elm-lang.org/install) * [Documentaci](http://elm-lang.org/docs), včetně [popisu syntaxe](http://elm-lang.org/docs/syntax) * Spoustu nápomocných [příkladů](http://elm-lang.org/examples) * Documentace pro [standardní knihovny Elmu](http://package.elm-lang.org/packages/elm-lang/core/latest/). Povšimněte si: * [Základy](http://package.elm-lang.org/packages/elm-lang/core/latest/Basics), které jsou automaticky importovány * Typ [Maybe](http://package.elm-lang.org/packages/elm-lang/core/latest/Maybe) a jeho bratranec typ [Result](http://package.elm-lang.org/packages/elm-lang/core/latest/Result), které se běžně používají pro chybějící hodnoty a ošetření chyb. * Datové struktury jako [List](http://package.elm-lang.org/packages/elm-lang/core/latest/List), [Array](http://package.elm-lang.org/packages/elm-lang/core/latest/Array), [Dict](http://package.elm-lang.org/packages/elm-lang/core/latest/Dict) a [Set](http://package.elm-lang.org/packages/elm-lang/core/latest/Set) * JSON [enkódování](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Encode) a [dekódování](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode) * [Architektura Elmu](https://github.com/evancz/elm-architecture-tutorial#the-elm-architecture). Esej od tvůrce Elmu s příklady, jak organizovat kód do komponent. * [Elm mailing list](https://groups.google.com/forum/#!forum/elm-discuss). Všichni jsou přátelští a nápomocní. * [Scope v Elmu](https://github.com/elm-guides/elm-for-js/blob/master/Scope.md#scope-in-elm) a [Jak číst typové anotace](https://github.com/elm-guides/elm-for-js/blob/master/How%20to%20Read%20a%20Type%20Annotation.md#how-to-read-a-type-annotation). Další komunitní návody o základech Elmu, psáno pro JavaScriptové vývojáře. Běžte si zkusit něco napsat v Elmu! ================================================ FILE: cs/go.md ================================================ --- contributors: - ["Sonia Keys", "https://github.com/soniakeys"] - ["Christopher Bess", "https://github.com/cbess"] - ["Jesse Johnson", "https://github.com/holocronweaver"] - ["Quint Guvernator", "https://github.com/qguv"] - ["Jose Donizetti", "https://github.com/josedonizetti"] - ["Alexej Friesen", "https://github.com/heyalexej"] - ["Clayton Walker", "https://github.com/cwalk"] translators: - ["Ondra Linek", "https://github.com/defectus/"] --- Jazyk Go byl vytvořen, jelikož bylo potřeba dokončit práci. Není to poslední trend ve světě počítačové vědy, ale je to nejrychlejší a nejnovější způsob, jak řešit realné problémy. Go používá známé koncepty imperativních jazyků se statickým typováním. Rychle se kompiluje a také rychle běží. Přidává snadno pochopitelnou podporu konkurenčnosti, což umožňuje využít výhody multi-core procesorů a jazyk také obsahuje utility, které pomáhají se škálovatelným programováním. Go má již v základu vynikající knihovnu a je s ním spojená nadšená komunita. ```go // Jednořádkový komentář /* Několika řádkový komentář */ // Každý zdroják začíná deklarací balíčku (package) // main je vyhrazené jméno, které označuje spustitelný soubor, // narozdíl od knihovny package main // Importní deklarace říkají, které knihovny budou použity v tomto souboru. import ( "fmt" // Obsahuje formátovací funkce a tisk na konzolu "io/ioutil" // Vstupně/výstupní funkce m "math" // Odkaz na knihovnu math (matematické funkce) pod zkratkou m "net/http" // Podpora http protokolu, klient i server. "strconv" // Konverze řetězců, např. na čísla a zpět. ) // Definice funkce. Funkce main je zvláštní, je to vstupní bod do programu. // Ať se vám to líbí, nebo ne, Go používá složené závorky func main() { // Println vypisuje na stdout. // Musí být kvalifikováno jménem svého balíčko, ftm. fmt.Println("Hello world!") // Zavoláme další funkci svetPoHello() } // Funkce mají své parametry v závorkách // Pokud funkce nemá parametry, tak musíme stejně závorky uvést. func svetPoHello() { var x int // Deklarace proměnné. Proměnné musí být před použitím deklarované x = 3 // Přiřazení hodnoty do proměnné // Existuje "krátká" deklarace := kde se typ proměnné odvodí, // proměnná vytvoří a přiřadí se jí hodnota y := 4 sum, prod := naucSeNasobit(x, y) // Funkce mohou vracet více hodnot fmt.Println("sum:", sum, "prod:", prod) // Jednoduchý výstup naucSeTypy() // < y minut je za námi, je čas učit se víc! } /* <- začátek mnohořádkového komentáře Funkce mohou mít parametry a (několik) návratových hodnot. V tomto případě jsou `x`, `y` parametry a `sum`, `prod` jsou návratové hodnoty. Všiměte si, že `x` a `sum` jsou typu `int`. */ func naucSeNasobit(x, y int) (sum, prod int) { return x + y, x * y // Vracíme dvě hodnoty } // zabudované typy a literáty. func naucSeTypy() { // Krátká deklarace většinou funguje str := "Learn Go!" // typ řetězec. s2 := `"surový" literát řetězce může obsahovat nové řádky` // Opět typ řetězec. // Můžeme použít ne ASCII znaky, Go používá UTF-8. g := 'Σ' // type runa, což je alias na int32 a ukládá se do něj znak UTF-8 f := 3.14159 // float64, je IEEE-754 64-bit číslem s plovoucí čárkou. c := 3 + 4i // complex128, interně uložené jako dva float64. // takhle vypadá var s inicializací var u uint = 7 // Číslo bez znaménka, jehož velikost záleží na implementaci, // stejně jako int var pi float32 = 22. / 7 // takto se převádí typy za pomoci krátké syntaxe n := byte('\n') // byte je jiné jméno pro uint8. // Pole mají fixní délku, které se určuje v době kompilace. var a4 [4]int // Pole 4 intů, všechny nastaveny na 0. a3 := [...]int{3, 1, 5} // Pole nastaveno na tři hodnoty // elementy mají hodntu 3, 1 a 5 // Slicy mají dynamickou velikost. Pole i slacy mají své výhody, // ale většinou se používají slicy. s3 := []int{4, 5, 9} // Podobně jako a3, ale není tu výpustka. s4 := make([]int, 4) // Alokuj slice 4 intů, všechny nastaveny na 0. var d2 [][]float64 // Deklarace slicu, nic se nealokuje. bs := []byte("a slice") // Přetypování na slice // Protože jsou dynamické, můžeme ke slicům přidávat za běhu // Přidat ke slicu můžeme pomocí zabudované funkce append(). // Prvním parametrem je slice, návratová hodnota je aktualizovaný slice. s := []int{1, 2, 3} // Výsledkem je slice se 3 elementy. s = append(s, 4, 5, 6) // Přidány další 3 elementy. Slice má teď velikost 6. fmt.Println(s) // Slice má hodnoty [1 2 3 4 5 6] // Pokud chceme k poli přičíst jiné pole, můžeme předat referenci na slice, // nebo jeho literát a přidat výpustku, čímž se slicu "rozbalí" a přidá se k // původnímu slicu. s = append(s, []int{7, 8, 9}...) // druhým parametrem je literát slicu. fmt.Println(s) // slice má teď hodnoty [1 2 3 4 5 6 7 8 9] p, q := naucSePraciSPameti() // Deklarujeme p a q jako typ pointer na int. fmt.Println(*p, *q) // * dereferencuje pointer. Tím se vypíší dva inty. // Mapy jsou dynamické rostoucí asociativní pole, jako hashmapa, nebo slovník // (dictionary) v jiných jazycích m := map[string]int{"tri": 3, "ctyri": 4} m["jedna"] = 1 // Napoužité proměnné jsou v Go chybou. // Použijte podtržítko, abychom proměnno "použili". _, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs // Výpis promenné se počítá jako použití. fmt.Println(s, c, a4, s3, d2, m) naucSeVetveníProgramu() // Zpátky do běhu. } // narozdíl od jiných jazyků, v Go je možné mít pojmenované návratové hodnoty. // Tak můžeme vracet hodnoty z mnoha míst funkce, aniž bychom uváděli hodnoty v // return. func naucSePojmenovaneNavraty(x, y int) (z int) { z = x * y return // z je zde implicitní, jelikož bylo pojmenováno. } // Go má garbage collector. Používá pointery, ale neumožňuje jejich aritmetiku. // Můžete tedy udělat chybu použitím nil odkazu, ale ne jeho posunutím. func naucSePraciSPameti() (p, q *int) { // Pojmenované parametry p a q mají typ odkaz na int. p = new(int) // Zabudované funkce new alokuje paměť. // Alokované místo pro int má hodnotu 0 a p už není nil. s := make([]int, 20) // Alokujeme paměť pro 20 intů. s[3] = 7 // Jednu z nich nastavíme. r := -2 // Deklarujeme další lokální proměnnou. return &s[3], &r // a vezmeme si jejich odkaz pomocí &. } func narocnyVypocet() float64 { return m.Exp(10) } func naucSeVetveníProgramu() { // Výraz if vyžaduje složené závorky, ale podmínka nemusí být v závorkách. if true { fmt.Println("říkal jsme ti to") } // Formátování je standardizované pomocí utility "go fmt". if false { // posměšek. } else { // úšklebek. } // Použij switch, když chceš zřetězit if. x := 42.0 switch x { case 0: case 1: case 42: // jednotlivé case nepropadávají. není potřeba "break" case 43: // nedosažitelné, jelikož už bylo ošetřeno. default: // implicitní větev je nepovinná. } // Stejně jako if, for (smyčka) nepoužívá závorky. // Proměnné definované ve for jsou lokální vůči smyčce. for x := 0; x < 3; x++ { // ++ je výrazem. fmt.Println("iterace", x) } // zde je x == 42. // For je jediná smyčka v Go, ale má několik tvarů. for { // Nekonečná smyčka break // Dělám si legraci continue // Sem se nedostaneme } // Můžete použít klíčové slovo range pro iteraci nad mapami, poli, slicy, // řetězci a kanály. // range vrací jednu (kanál) nebo dvě hodnoty (pole, slice, řetězec a mapa). for key, value := range map[string]int{"jedna": 1, "dva": 2, "tri": 3} { // pro každý pár (klíč a hodnota) je vypiš fmt.Printf("klíč=%s, hodnota=%d\n", key, value) } // stejně jako for, := v podmínce if přiřazuje hodnotu // nejříve nastavíme y a pak otestujeme, jestli je y větší než x. if y := narocnyVypocet(); y > x { x = y } // Funkční literáty jsou tzv. uzávěry (closure) xBig := func() bool { return x > 10000 // odkazuje na x deklarované ve příkladu použití switch } x = 99999 fmt.Println("xBig:", xBig()) // true x = 1.3e3 // To udělá z x == 1300 fmt.Println("xBig:", xBig()) // teď už false. // Dále je možné funkční literáty definovat a volat na místě jako parametr // funkce, dokavaď: // a) funkční literát je okamžitě volán pomocí (), // b) výsledek se shoduje s očekávaným typem. fmt.Println("Sečte + vynásobí dvě čísla: ", func(a, b int) int { return (a + b) * 2 }(10, 2)) // Voláno s parametry 10 a 2 // => Sečti a vynásob dvě čísla. 24 // Když to potřebujete, tak to milujete goto miluji miluji: naučteSeFunkčníFactory() // funkce vracející funkce je zábava(3)(3) naučteSeDefer() // malá zajížďka k důležitému klíčovému slovu. naučteSeInterfacy() // Přichází dobré věci! } func naučteSeFunkčníFactory() { // Následující dvě varianty jsou stejné, ale ta druhá je praktičtější fmt.Println(větaFactory("létní")("Hezký", "den!")) d := větaFactory("letní") fmt.Println(d("Hezký", "den!")) fmt.Println(d("Líný", "odpoledne!")) } // Dekorátory jsou běžné v jiných jazycích. To samé můžete udělat v Go // pomocí parameterizovatelných funkčních literátů. func větaFactory(můjŘetězec string) func(před, po string) string { return func(před, po string) string { return fmt.Sprintf("%s %s %s", před, můjŘetězec, po) // nový řetězec } } func naučteSeDefer() (ok bool) { // Odloží (defer) příkazy na okamžik těsně před opuštěním funkce. // tedy poslední se provede první defer fmt.Println("odložené příkazy jsou zpravovaná v LIFO pořadí.") defer fmt.Println("\nProto je tato řádka vytištěna první") // Defer se běžně používá k zavírání souborů a tím se zajistí, že soubor // bude po ukončení funkce zavřen. return true } // definuje typ interfacu s jednou metodou String() type Stringer interface { String() string } // Definuje pár jako strukturu se dvěma poli typu int x a y. type pár struct { x, y int } // Definuje method pár. Pár tedy implementuje interface Stringer. func (p pár) String() string { // p je tu nazýváno "Receiver" - přijímač // Sprintf je další veřejná funkce z balíčku fmt. // Pomocí tečky přistupujeme k polím proměnné p return fmt.Sprintf("(%d, %d)", p.x, p.y) } func naučteSeInterfacy() { // Složené závorky jsou "strukturální literáty. Vyhodnotí a inicializuje // strukturu. Syntaxe := deklaruje a inicializuje strukturu. p := pár{3, 4} fmt.Println(p.String()) // Volá metodu String na p typu pár. var i Stringer // Deklaruje i jako proměnné typu Stringer. i = p // Toto je možné, jelikož oba implementují Stringer // zavolá metodu String(( typu Stringer a vytiskne to samé jako předchozí. fmt.Println(i.String()) // Funkce ve balíčku fmt volají metodu String, když zjišťují, jak se má typ // vytisknout. fmt.Println(p) // Vytiskne to samé, jelikož Println volá String(). fmt.Println(i) // Ten samý výstup. naučSeVariabilníParametry("super", "učit se", "tady!") } // Funcke mohou mít proměnlivé množství parametrů. func naučSeVariabilníParametry(mojeŘetězce ...interface{}) { // Iterujeme přes všechny parametry // Potržítku tu slouží k ignorování indexu v poli. for _, param := range mojeŘetězce { fmt.Println("parameter:", param) } // Použít variadický parametr jako variadický parametr, nikoliv pole. fmt.Println("parametery:", fmt.Sprintln(mojeŘetězce...)) naučSeOšetřovatChyby() } func naučSeOšetřovatChyby() { // ", ok" je metodou na zjištění, jestli něco fungovalo, nebo ne. m := map[int]string{3: "tri", 4: "ctyri"} if x, ok := m[1]; !ok { // ok bude false, jelikož 1 není v mapě. fmt.Println("není tu jedna") } else { fmt.Print(x) // x by bylo tou hodnotou, pokud by bylo v mapě. } // hodnota error není jen znamením OK, ale může říct více o chybě. if _, err := strconv.Atoi("ne-int"); err != nil { // _ hodnotu zahodíme // vytiskne 'strconv.ParseInt: parsing "non-int": invalid syntax' fmt.Println(err) } // Znovu si povíme o interfacech, zatím se podíváme na naučSeKonkurenčnost() } // c je kanál, způsob, jak bezpečně komunikovat v konkurenčním prostředí. func zvyš(i int, c chan int) { c <- i + 1 // <- znamená "pošli" a posílá data do kanálu na levé straně. } // Použijeme funkci zvyš a konkurečně budeme zvyšovat čísla. func naučSeKonkurenčnost() { // funkci make jsme již použili na slicy. make alokuje a inicializuje slidy, // mapy a kanály. c := make(chan int) // nastartuj tři konkurenční go-rutiny. Čísla se budou zvyšovat // pravděpodobně paralelně pokud je počítač takto nakonfigurován. // Všechny tři zapisují do toho samého kanálu. go zvyš(0, c) // go je výraz pro start nové go-rutiny. go zvyš(10, c) go zvyš(-805, c) // Přečteme si tři výsledky a vytiskeneme je.. // Nemůžeme říct, v jakém pořadí výsledky přijdou! fmt.Println(<-c, <-c, <-c) // pokud je kanál na pravo, jedná se o "přijmi". cs := make(chan string) // Další kanál, tentokrát pro řetězce. ccs := make(chan chan string) // Kanál kanálu řetězců. go func() { c <- 84 }() // Start nové go-rutiny na posílání hodnot. go func() { cs <- "wordy" }() // To samé s cs. // Select má syntaxi jako switch, ale vztahuje se k operacím nad kanály. // Náhodně vybere jeden case, který je připraven na komunikaci. select { case i := <-c: // Přijatá hodnota může být přiřazena proměnné. fmt.Printf("je to typ %T", i) case <-cs: // nebo může být zahozena fmt.Println("je to řetězec") case <-ccs: // prázdný kanál, nepřipraven ke komunikaci. fmt.Println("to se nestane.") } // V tomto okamžiku máme hodnotu buď z kanálu c nabo cs. Jedna nebo druhá // nastartovaná go-rutina skončila a další zůstane blokovaná. naučSeProgramovatWeb() // Go to umí. A vy to chcete taky. } // jen jedna funkce z balíčku http spustí web server. func naučSeProgramovatWeb() { // První parametr ListenAndServe je TCP adresa, kde poslouchat. // Druhý parametr je handler, implementující interace http.Handler. go func() { err := http.ListenAndServe(":8080", pár{}) fmt.Println(err) // neignoruj chyby }() requestServer() } // Umožní typ pár stát se http tím, že implementuje její jedinou metodu // ServeHTTP. func (p pár) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Servíruj data metodou http.ResponseWriter w.Write([]byte("Naučil ses Go za y minut!")) } func requestServer() { resp, err := http.Get("http://localhost:8080") fmt.Println(err) defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Printf("\nWebserver řekl: `%s`", string(body)) } ``` ## Kam dále Vše hlavní o Go se nachází na [oficiálních stránkách go](https://go.dev/). Tam najdete tutoriály, interaktivní konzolu a mnoho materiálu ke čtení. Kromě úvodu, [dokumenty](https://go.dev/doc/) tam obsahují jak psát čistý kód v Go popis balíčků (package), dokumentaci příkazové řádky a historii releasů. Také doporučujeme přečíst si definici jazyka. Je čtivá a překvapivě krátká. Tedy alespoň proti jiným současným jazyků. Pokud si chcete pohrát s Go, tak navštivte [hřiště Go](https://go.dev/play/p/r46YvCu-XX). Můžete tam spouštět programy s prohlížeče. Také můžete [https://go.dev/play/](https://go.dev/play/) použít jako [REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop), kde si v rychlosti vyzkoušíte věci, bez instalace Go. Na vašem knižním seznamu, by neměly chybět [zdrojáky stadardní knihovny](https://go.dev/src/). Důkladně popisuje a dokumentuje Go, styl zápisu Go a Go idiomy. Pokud kliknete na [dokumentaci](https://go.dev/pkg/) tak se podíváte na dokumentaci. Dalším dobrým zdrojem informací je [Go v ukázkách](https://gobyexample.com/). Go mobile přidává podporu pro Android a iOS. Můžete s ním psát nativní mobilní aplikace nebo knihovny, které půjdou spustit přes Javu (pro Android), nebo Objective-C (pro iOS). Navštivte [web Go Mobile](https://go.dev/wiki/Mobile) pro více informací. ================================================ FILE: cs/hack.md ================================================ --- contributors: - ["Stephen Holdaway", "https://github.com/stecman"] translators: - ["Vojta Svoboda", "https://github.com/vojtasvoboda/"] --- Hack je nadmnožinou PHP a běží v rámci virtuálního stroje zvaného HHVM. Hack dokáže skoro plně spolupracovat s existujícím PHP a přidává několik vylepšení, které známe ze staticky typovaných jazyků. Níže jsou popsané pouze vlastnosti jazyka Hack. Detaily ohledně jazyka PHP a jeho syntaxe pak najdete na těchto stránkách v samostatném [článku o PHP](/php/). ```php id = $id; } } // Stručné anonymní funkce (lambda funkce) $multiplier = 5; array_map($y ==> $y * $multiplier, [1, 2, 3]); // Generika (generické funkce) class Box { protected T $data; public function __construct(T $data) { $this->data = $data; } public function getData(): T { return $this->data; } } function openBox(Box $box) : int { return $box->getData(); } // Tvary // // Hack zavádí koncept tvaru pro definování strukturovaných polí s garantovanou // typovou kontrolou pro klíče. type Point2D = shape('x' => int, 'y' => int); function distance(Point2D $a, Point2D $b) : float { return sqrt(pow($b['x'] - $a['x'], 2) + pow($b['y'] - $a['y'], 2)); } distance( shape('x' => -1, 'y' => 5), shape('x' => 2, 'y' => 50) ); // Type aliasing // // Hack přidává několik vylepšení pro lepší čitelnost komplexních typů newtype VectorArray = array>; // Množina obsahující čísla newtype Point = (int, int); function addPoints(Point $p1, Point $p2) : Point { return tuple($p1[0] + $p2[0], $p1[1] + $p2[1]); } addPoints( tuple(1, 2), tuple(5, 6) ); // Výčtový typ enum RoadType : int { Road = 0; Street = 1; Avenue = 2; Boulevard = 3; } function getRoadType() : RoadType { return RoadType::Avenue; } // Automatické nastavení proměnných třídy // // Aby se nemuseli definovat proměnné třídy a její konstruktor, // který pouze nastavuje třídní proměnné, můžeme v Hacku vše // definovat najednou. class ArgumentPromotion { public function __construct(public string $name, protected int $age, private bool $isAwesome) {} } // Takto by to vypadalo bez automatického nastavení proměnných class WithoutArugmentPromotion { public string $name; protected int $age; private bool $isAwesome; public function __construct(string $name, int $age, bool $isAwesome) { $this->name = $name; $this->age = $age; $this->isAwesome = $isAwesome; } } // Ko-operativní multi-tasking // // Nová klíčová slova "async" and "await" mohou být použité pro spuštění mutli-taskingu // Tato vlastnost ovšem zahrnuje vícevláknové zpracování, pouze povolí řízení přenosu async function cooperativePrint(int $start, int $end) : Awaitable { for ($i = $start; $i <= $end; $i++) { echo "$i "; // Dává ostatním úlohám šanci něco udělat await RescheduleWaitHandle::create(RescheduleWaitHandle::QUEUE_DEFAULT, 0); } } // Toto vypíše "1 4 7 2 5 8 3 6 9" AwaitAllWaitHandle::fromArray([ cooperativePrint(1, 3), cooperativePrint(4, 6), cooperativePrint(7, 9) ])->getWaitHandle()->join(); // Atributy // // Atributy jsou určitou formou metadat pro funkce. Hack přidává některé vestavěné // atributy které aktivnují uživatečné chování funkcí. // Speciální atribut __Memoize způsobí, že výsledek funkce je uložen do cache <<__Memoize>> function doExpensiveTask() : ?string { return file_get_contents('http://example.com'); } // Tělo funkce je v tomto případě vykonáno pouze jednou: doExpensiveTask(); doExpensiveTask(); // Speciální atribut __ConsistentConstruct signalizuje typové kontrole Hacku, že // zápis __construct bude stejný pro všechny podtřídy. <<__ConsistentConstruct>> class ConsistentFoo { public function __construct(int $x, float $y) { // ... } public function someMethod() { // ... } } class ConsistentBar extends ConsistentFoo { public function __construct(int $x, float $y) { // Typová kontrola Hacku zajistí volání konstruktoru rodičovské třídy parent::__construct($x, $y); // ... } // Anotace __Override je volitelný signál pro typovou kontrolu Hacku, že // tato metoda přetěžuje metodu rodičovské třídy, nebo traitu. Bez uvedení // této anotace vyhodí typová kontrola chybu. <<__Override>> public function someMethod() { // ... } } class InvalidFooSubclass extends ConsistentFoo { // Nedodržení zápisu dle rodičovského konstruktoru způsobí syntaktickou chybu: // // "Tento objekt je typu ConsistentBaz a není kompatibilní v tímto objektem, // který je typu ConsistentFoo protože některé jeho metody nejsou kompatibilní." // public function __construct(float $x) { // ... } // Použitím anotace __Override na nepřetíženou metodu způsobí chybu typové kontroly: // // "InvalidFooSubclass::otherMethod() je označená jako přetížená, ale nebyla nalezena // taková rodičovská metoda, nebo rodič kterého přetěžujete není zapsán v > public function otherMethod() { // ... } } // Traity mohou implementovat rozhraní, což standardní PHP neumí interface KittenInterface { public function play() : void; } trait CatTrait implements KittenInterface { public function play() : void { // ... } } class Samuel { use CatTrait; } $cat = new Samuel(); $cat instanceof KittenInterface === true; // True ``` ## Více informací Pro více informací navštivte [referenční příručku jazyka Hack](http://docs.hhvm.com/manual/en/hacklangref.php), kde se dozvíte více detailu a vylepšení, které jazyk Hack přidává do PHP, a nebo navštivte [oficiální stránky jazyka Hack](http://hacklang.org/) pro obecné informace. Pro instrukce k instalaci jazyka Hack navštivte [oficiální HHVM stránky](http://hhvm.com/). Pro více informací ohledně zpětné kompatibility s PHP navštivte článek o [nepodporovaných PHP vlastnostech Hacku](http://docs.hhvm.com/manual/en/hack.unsupported.php). ================================================ FILE: cs/javascript.md ================================================ --- contributors: - ["Leigh Brenecki", "https://leigh.net.au"] - ["Ariel Krakowski", "http://www.learneroo.com"] translators: - ["Michal Martinek", "https://github.com/MichalMartinek"] --- JavaScript byl vytvořen Brendanem Eichem v roce 1995 pro Netscape. Původně byl zamýšlen jako jednoduchý skriptovací jazyk pro webové stránky, jako doplněk Javy, která byla zamýšlena pro komplexnější webové aplikace. Úzké propojení JavaScriptu s webovými stránkami a vestavěná podpora v prohlížečích způsobila, že se stal ve webovém frontendu běžnějším než Java. JavaScript není omezen pouze na webové prohlížeče. Např. projekt Node.js, který zprostředkovává samostatně běžící prostředí V8 JavaScriptového jádra z Google Chrome se stává stále oblíbenější i pro serverovou část webových aplikací. ```js // Jednořádkové komentáře začínají dvojitým lomítkem, /* a víceřádkové komentáře začínají lomítkem s hvězdičkou a končí hvězdičkou s lomítkem */ // Příkazy mohou být ukončeny středníkem ; delejNeco(); // ... ale nemusí, protože středníky jsou automaticky vloženy kdekoliv, // kde končí řádka, kromě pár speciálních případů. delejNeco(); // Protože tyto případy můžou způsobit neočekávané výsledky, budeme // středníky v našem návodu používat. ///////////////////////////////// // 1. Čísla, řetězce a operátory // JavaScript má jeden číselný typ (čímž je 64-bitový IEEE 754 double). // Double má 52-bitovou přesnost, což je dostatečně přesné pro ukládání celých // čísel až do 9✕10¹⁵. 3; // = 3 1.5; // = 1.5 // Základní matematické operace fungují tak, jak byste očekávali 1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 // Včetně dělení 5 / 2; // = 2.5 // A také dělení modulo 10 % 2; // = 0 30 % 4; // = 2 18.5 % 7; // = 4.5 // Bitové operace také fungují; když provádíte bitové operace, desetinné číslo // (float) se převede na celé číslo (int) se znaménkem *až do* 32 bitů 1 << 2; // = 4 // Přednost se vynucuje závorkami. (1 + 3) * 2; // = 8 // Existují 3 hodnoty mimo obor reálných čísel: Infinity; // + nekonečno; výsledek např. 1/0 -Infinity; // - nekonečno; výsledek např. -1/0 NaN; // výsledek např. 0/0, znamená, že výsledek není číslo ('Not a Number') // Také existují hodnoty typu boolean. true; // pravda false; // nepravda // Řetězce znaků jsou obaleny ' nebo ". 'abc'; "Hello, world"; // Negace se tvoří pomocí znaku ! !true; // = false !false; // = true // Rovnost se porovnává pomocí === 1 === 1; // = true 2 === 1; // = false // Nerovnost zase pomocí !== 1 !== 1; // = false 2 !== 1; // = true // Další srovnávání 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true // Řetězce znaků se spojují pomocí + "Hello " + "world!"; // = "Hello world!" // ... což funguje nejen s řetězci "1, 2, " + 3; // = "1, 2, 3" "Hello " + ["world", "!"]; // = "Hello world,!" // a porovnávají se pomocí < nebo > "a" < "b"; // = true // Rovnost s převodem typů se dělá za pomoci dvojitého rovnítka... "5" == 5; // = true null == undefined; // = true // ...dokud nepoužijete === "5" === 5; // = false null === undefined; // = false // ...což může občas způsobit divné chování... 13 + !0; // 14 "13" + !0; // '13true' // Můžeme přistupovat k jednotlivým znakům v řetězci pomocí `charAt` "Toto je řetězec".charAt(0); // = 'T' // ...nebo použít `substring` k získání podřetězce. "Hello world".substring(0, 5); // = "Hello" // `length` znamená délka a je to vlastnost, takže nepoužívejte (). "Hello".length; // = 5 // Existují také typy `null` a `undefined`. null; // obvykle označuje něco záměrně bez hodnoty undefined; // obvykle označuje, že hodnota není momentálně definovaná (ačkoli // `undefined` je hodnota sama o sobě) // false, null, undefined, NaN, 0 a "" vrací nepravdu (false). Všechno ostatní // vrací pravdu (true). // Všimněte si, že 0 vrací nepravdu, ale "0" vrací pravdu, i když 0 == "0" // vrací pravdu. /////////////////////////////////// // 2. Proměnné, pole a objekty // Proměnné jsou deklarovány pomocí slůvka `var`. JavaScript je dynamicky // typovaný, takže nemusíme specifikovat typ. K přiřazení hodnoty se používá // znak `=`. var promenna = 5; // Když vynecháte slůvko 'var', nedostanete chybovou hlášku... jinaPromenna = 10; // ...ale vaše proměnná bude vytvořena globálně. Bude vytvořena v globální // oblasti působnosti, tedy nejenom v lokální tam, kde jste ji vytvořili. // Proměnné vytvořené bez přiřazení obsahují hodnotu undefined. var dalsiPromenna; // = undefined // Pokud chcete vytvořit několik proměnných najednou, můžete je oddělit čárkou var someFourthVar = 2, someFifthVar = 4; // Existuje kratší forma pro matematické operace nad proměnnými promenna += 5; // se provede stejně jako promenna = promenna + 5; // promenna je teď 10 promenna *= 10; // teď je promenna rovna 100 // a tohle je způsob, jak přičítat a odečítat 1 promenna++; // teď je promenna 101 promenna--; // zpět na 100 // Pole jsou uspořádané seznamy hodnot jakéhokoliv typu. var myArray = ["Ahoj", 45, true]; // Jednotlivé hodnoty jsou přístupné přes hranaté závorky. // Členové pole se začínají počítat na nule. myArray[1]; // = 45 // Pole je proměnlivé délky a členové se můžou měnit. myArray.push("World"); myArray.length; // = 4 // Přidání/změna na specifickém indexu myArray[3] = "Hello"; // Přidání nebo odebrání člena ze začátku nebo konce pole myArray.unshift(3); // Přidej jako první člen someVar = myArray.shift(); // Odstraň prvního člena a vrať jeho hodnotu myArray.push(3); // Přidej jako poslední člen someVar = myArray.pop(); // Odstraň posledního člena a vrať jeho hodnotu // Spoj všechny členy pole středníkem var myArray0 = [32,false,"js",12,56,90]; myArray0.join(";") // = "32;false;js;12;56;90" // Vrať část pole s elementy od pozice 1 (včetně) do pozice 4 (nepočítaje) myArray0.slice(1,4); // = [false,"js",12] // Odstraň čtyři členy od pozice 2, vlož následující // "hi","wr" and "ld"; vrať odstraněné členy myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] // myArray0 === [32,false,"hi","wr","ld"] // JavaScriptové objekty jsou stejné jako asociativní pole v jiných programovacích // jazycích: je to neuspořádaná množina páru hodnot - klíč:hodnota. var mujObjekt = {klic1: "Hello", klic2: "World"}; // Klíče jsou řetězce, ale nemusí mít povinné uvozovky, pokud jsou validními // JavaScriptovými identifikátory. Hodnoty můžou být jakéhokoliv typu. var mujObjekt = {klic: "mojeHodnota", "muj jiny klic": 4}; // K hodnotám můžeme přistupovat opět pomocí hranatých závorek mujObjekt["muj jiny klic"]; // = 4 // ... nebo pokud je klíč platným identifikátorem, můžeme přistupovat k // hodnotám i přes tečku mujObjekt.klic; // = "mojeHodnota" // Objekty jsou měnitelné, můžeme upravit hodnoty, nebo přidat nové klíče. mujObjekt.mujDalsiKlic = true; // Pokud se snažíte přistoupit ke klíči, který neexistuje, dostanete undefined. mujObjekt.dalsiKlic; // = undefined /////////////////////////////////// // 3. Řízení toku programu // Funkce `if` funguje, jak byste čekali. var pocet = 1; if (pocet == 3){ // provede, když se pocet rovná 3 } else if (pocet == 4){ // provede, když se pocet rovná 4 } else { // provede, když je pocet cokoliv jiného } // Stejně tak cyklus `while`. while (true){ // nekonečný cyklus! } // Do-while cyklus je stejný jako while, akorát se vždy provede aspoň jednou. var vstup; do { vstup = nactiVstup(); } while (!jeValidni(vstup)) // Cyklus `for` je stejný jako v Javě nebo jazyku C: // inicializace; podmínka pro pokračování; iterace. for (var i = 0; i < 5; i++){ // provede se pětkrát } // Opuštění cyklu s návěštím je podobné jako v Javě outer: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; // opustí vnější (outer) cyklus místo pouze vnitřního (inner) cyklu } } } // Cyklus For-in iteruje přes každou vlastnost prototypu var popis = ""; var osoba = {prijmeni:"Paul", jmeno:"Ken", vek:18}; for (var x in osoba){ popis += osoba[x] + " "; } // popis = 'Paul Ken 18 ' // Příkaz for/of umožňuje iterovat iterovatelné objekty (včetně vestavěných typů // String, Array, například polím podobným argumentům nebo NodeList objektům, // TypeArray, Map a Set, či uživatelsky definované iterovatelné objekty). var myPets = ""; var pets = ["cat", "dog", "hamster", "hedgehog"]; for (var pet of pets){ myPets += pet + " "; } // myPets = 'cat dog hamster hedgehog ' // && je logické a, || je logické nebo if (dum.velikost == "velký" && dum.barva == "modrá"){ dum.obsahuje = "medvěd"; } if (barva == "červená" || barva == "modrá"){ // barva je červená nebo modrá } // && a || jsou praktické i pro nastavení základních hodnot var jmeno = nejakeJmeno || "default"; // `switch` zkoumá přesnou rovnost (===) // Používejte 'break;' po každé možnosti, jinak se provede i možnost za ní. znamka = 'B'; switch (znamka) { case 'A': console.log("Výborná práce"); break; case 'B': console.log("Dobrá práce"); break; case 'C': console.log("Dokážeš to i lépe"); break; default: console.log("Ale ne"); break; } //////////////////////////////////////////////////////// // 4. Funkce, Oblast platnosti (scope) a Vnitřní funkce // JavaScriptové funkce jsou definovány slůvkem `function`. function funkce(text){ return text.toUpperCase(); } funkce("něco"); // = "NĚCO" // Dávejte si pozor na to, že hodnota k vrácení musí začínat na stejné řádce // jako slůvko return, jinak se vrátí 'undefined', kvůli automatickému vkládání // středníků. Platí to zejména pro Allmanův styl zápisu. function funkce(){ return // <- zde je automaticky vložen středník { tohleJe: "vlastnost objektu"}; } funkce(); // = undefined // JavaScriptové funkce jsou objekty, takže můžou být přiřazeny různým proměnným // a předány dalším funkcím jako argumenty, na příklad: function funkce(){ // tento kód bude zavolán za 5 vteřin } setTimeout(funkce, 5000); // Poznámka: setTimeout není část JS jazyka, ale funkce poskytována // prohlížeči a NodeJS // Další funkce poskytovaná prohlížeči je je setInterval function myFunction(){ // tento kód bude volán každých 5 vteřin } setInterval(myFunction, 5000); // Objekty funkcí nemusíme ani deklarovat pomocí jména, můžeme je napsat jako // anonymní funkci přímo vloženou jako argument setTimeout(function(){ // tento kód bude zavolán za 5 vteřin }, 5000); // JavaScript má oblast platnosti funkce, funkce ho mají, ale jiné bloky ne if (true){ var i = 5; } i; // = 5 - ne undefined, jak byste očekávali v jazyku, kde mají bloky svůj // rámec působnosti // Toto je běžný model, který chrání před únikem dočasných proměnných do //globální oblasti (function(){ var docasna = 5; // Můžeme přistupovat ke globálního oblasti přes přiřazování globálním // objektům. Ve webovém prohlížeči je to vždy 'window`. Globální objekt // může mít v jiných prostředích jako Node.js jiné jméno. window.trvala = 10; })(); docasna; // způsobí ReferenceError trvala; // = 10 // Jedna z nejmocnějších vlastností JavaScriptu je vnitřní funkce. Je to funkce // definovaná v jiné funkci. Vnitřní funkce má přístup ke všem proměnným ve // vnější funkci, dokonce i poté, co vnější funkce skončí. function ahojPoPetiVterinach(jmeno){ var prompt = "Ahoj, " + jmeno + "!"; // Vnitřní funkce je dána do lokální oblasti platnosti, jako kdyby byla // deklarovaná slůvkem 'var' function vnitrni(){ alert(prompt); } setTimeout(vnitrni, 5000); // setTimeout je asynchronní, takže se funkce ahojPoPetiVterinach ukončí // okamžitě, ale setTimeout zavolá funkci vnitrni až poté. Avšak // vnitrni je definována přes ahojPoPetiVterinach a má pořád přístup k // proměnné prompt, když je konečně zavolána. } ahojPoPetiVterinach("Adam"); // otevře popup s "Ahoj, Adam!" za 5s /////////////////////////////////////////////////// // 5. Více o objektech, konstruktorech a prototypech // Objekty můžou obsahovat funkce. var mujObjekt = { mojeFunkce: function(){ return "Hello world!"; } }; mujObjekt.mojeFunkce(); // = "Hello world!" // Když jsou funkce z objektu zavolány, můžou přistupovat k objektu přes slůvko // 'this'' var mujObjekt = { text: "Hello world!", mojeFunkce: function(){ return this.text; } }; mujObjekt.mojeFunkce(); // = "Hello world!" // Slůvko this je nastaveno k tomu, kde je voláno, ne k tomu, kde je definováno // Takže naše funkce nebude fungovat, když nebude v kontextu objektu. var mojeFunkce = mujObjekt.mojeFunkce; mojeFunkce(); // = undefined // Opačně, funkce může být přiřazena objektu a může přistupovat k objektu přes // this, i když nebyla přímo v definici. var mojeDalsiFunkce = function(){ return this.text.toUpperCase(); } mujObjekt.mojeDalsiFunkce = mojeDalsiFunkce; mujObjekt.mojeDalsiFunkce(); // = "HELLO WORLD!" // Můžeme také specifikovat, v jakém kontextu má být funkce volána pomocí // `call` nebo `apply`. var dalsiFunkce = function(s){ return this.text + s; }; dalsiFunkce.call(mujObjekt, " A ahoj měsíci!"); // = "Hello world! A ahoj měsíci!" // Funkce `apply`je velmi podobná, pouze bere jako druhý argument pole argumentů dalsiFunkce.apply(mujObjekt, [" A ahoj slunce!"]); // = "Hello world! A ahoj slunce!" // To je praktické, když pracujete s funkcí, která bere sekvenci argumentů a // chcete předat pole. Math.min(42, 6, 27); // = 6 Math.min([42, 6, 27]); // = NaN Math.min.apply(Math, [42, 6, 27]); // = 6 // Ale `call` a `apply` jsou pouze dočasné. Pokud je chcete připojit trvale // použijte `bind`. var pripojenaFunkce = dalsiFunkce.bind(mujObjekt); pripojenaFunkce(" A ahoj Saturne!"); // = "Hello world! A ahoj Saturne!" // `bind` může být použito částečně k provázání funkcí var nasobeni = function(a, b){ return a * b; }; var zdvojeni = nasobeni.bind(this, 2); zdvojeni(8); // = 16 // Když zavoláte funkci se slůvkem 'new', vytvoří se nový objekt a // a udělá se dostupný funkcím skrz slůvko 'this'. Funkcím volaným takto se říká // konstruktory. var MujKonstruktor = function(){ this.mojeCislo = 5; }; mujObjekt = new MujKonstruktor(); // = {mojeCislo: 5} mujObjekt.mojeCislo; // = 5 // Na rozdíl od nejznámějších objektově orientovaných jazyků, JavaScript nezná // koncept instancí vytvořených z tříd. Místo toho JavaScript kombinuje // vytváření instancí a dědění do konceptu zvaného 'prototyp'. // Každý JavaScriptový objekt má prototyp. Když budete přistupovat k vlastnosti // objektu, který neexistuje na objektu, tak se JS podívá do prototypu. // Některé JS implementace vám umožní přistupovat k prototypu přes magickou // vlastnost '__proto__'. I když je toto užitečné k vysvětlování prototypů, není // to součást standardu. Ke standardnímu způsobu používání prototypu se // dostaneme později. var mujObjekt = { mujText: "Hello world!" }; var mujPrototyp = { smyslZivota: 42, mojeFunkce: function(){ return this.mujText.toLowerCase(); } }; mujObjekt.__proto__ = mujPrototyp; mujObjekt.smyslZivota; // = 42 // Toto funguje i pro funkce mujObjekt.mojeFunkce(); // = "Hello world!" // Samozřejmě, pokud není vlastnost na vašem prototypu, tak se hledá na // prototypu od prototypu atd. mujPrototyp.__proto__ = { mujBoolean: true }; mujObjekt.mujBoolean; // = true // Zde není žádné kopírování; každý objekt ukládá referenci na svůj prototyp // Toto znamená, že můžeme měnit prototyp a změny se projeví všude. mujPrototyp.smyslZivota = 43; mujObjekt.smyslZivota; // = 43 // Příkaz for/in umožňuje iterovat vlastnosti objektu až do úrovně null // prototypu. for (var x in myObj){ console.log(myObj[x]); } ///Vypíše: // Hello world! // 43 // [Function: myFunc] // Pro výpis pouze vlastností patřících danému objektu a nikoli jeho prototypu, // použijte kontrolu pomocí `hasOwnProperty()`. for (var x in myObj){ if (myObj.hasOwnProperty(x)){ console.log(myObj[x]); } } ///Vypíše: // Hello world! // Zmínili jsme již předtím, že '__proto__' není ve standardu a není cesta, jak // měnit prototyp existujícího objektu. Avšak existují možnosti, jak vytvořit // nový objekt s daným prototypem. // První je Object.create, což je nedávný přídavek do JS a není dostupný zatím // ve všech implementacích. var mujObjekt = Object.create(mujPrototyp); mujObjekt.smyslZivota; // = 43 // Druhý způsob, který funguje všude, je pomocí konstruktoru. Konstruktor má // vlastnost jménem prototype. Toto *není* prototyp samotného konstruktoru, ale // prototyp nového objektu. MujKonstruktor.prototype = { mojeCislo: 5, ziskejMojeCislo: function(){ return this.mojeCislo; } }; var mujObjekt2 = new MujKonstruktor(); mujObjekt2.ziskejMojeCislo(); // = 5 mujObjekt2.mojeCislo = 6; mujObjekt2.ziskejMojeCislo(); // = 6 // Vestavěné typy jako čísla nebo řetězce mají také konstruktory, které vytváří // ekvivalentní obalovací objekty (wrappery). var mojeCislo = 12; var mojeCisloObj = new Number(12); mojeCislo == mojeCisloObj; // = true // Avšak nejsou úplně přesně stejné typeof mojeCislo; // = 'number' typeof mojeCisloObj; // = 'object' mojeCislo === mojeCisloObj; // = false if (0){ // Tento kód se nespustí, protože 0 je nepravdivá (false) } if (new Number(0)){ // Tento kód se spustí, protože obalená čísla jsou objekty, // a objekty jsou vždy pravdivé } // Avšak, obalovací objekty a normální vestavěné typy sdílejí prototyp, takže // můžete přidat funkcionalitu k řetězci String.prototype.prvniZnak = function(){ return this.charAt(0); } "abc".prvniZnak(); // = "a" // Tento fakt je často používán v polyfillech, což je implementace novějších // vlastností JavaScriptu do starších variant, takže je můžete používat třeba // ve starých prohlížečích. // Na příklad jsme zmínili, že Object.create není dostupný ve všech // implementacích, ale můžeme si ho přidat pomocí polyfillu: if (Object.create === undefined){ // nebudeme ho přepisovat, když existuje Object.create = function(proto){ // vytvoříme dočasný konstruktor var Constructor = function(){}; Constructor.prototype = proto; // ten použijeme k vytvoření nového objektu s prototypem return new Constructor(); }; } ``` ## Kam dál [Mozilla Developer Network][1] obsahuje perfektní dokumentaci pro JavaScript, který je používaný v prohlížečích. Navíc je to i wiki, takže jakmile se naučíte více, můžete pomoci ostatním tím, že přispějete svými znalostmi. MDN's [A re-introduction to JavaScript][2] pojednává o konceptech vysvětlených zde v mnohem větší hloubce. Tento návod pokrývá hlavně JavaScript sám o sobě. Pokud se chcete naučit, jak se používá na webových stránkách, začněte tím, že se podíváte na [DOM][3] [JavaScript Garden][5] je sbírka příkladů těch nejnepředvídatelnějších částí tohoto jazyka. [JavaScript: The Definitive Guide][6] je klasická výuková kniha. [Eloquent JavaScript][8] od Marijn Haverbeke je výbornou JS knihou/e-knihou. [JavaScript: The Right Way][10] je průvodcem JavaScriptem pro začínající vývojáře i pomocníkem pro zkušené vývojáře, kteří si chtějí prohloubit své znalosti. [javascript.info][11] je moderním JavaScriptovým průvodcem, který pokrývá základní i pokročilé témata velice výstižným výkladem. Jako dodatek k přímým autorům tohoto článku byly na těchto stránkách části obsahu převzaty z Pythonního tutoriálu Louiho Dinha, a tak0 z [JS Tutorial][7] na stránkách Mozilla Developer Network. [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript [3]: https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core [5]: https://shamansir.github.io/JavaScript-Garden/ [6]: http://www.amazon.com/gp/product/0596805527/ [7]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript [8]: http://eloquentjavascript.net/ [10]: http://jstherightway.org/ [11]: https://javascript.info/ ================================================ FILE: cs/json.md ================================================ --- contributors: - ["Anna Harren", "https://github.com/iirelu"] - ["Marco Scannadinari", "https://github.com/marcoms"] translators: - ["Vojta Svoboda", "https://github.com/vojtasvoboda/"] --- JSON je exterémně jednoduchý datově nezávislý formát a bude asi jeden z nejjednodušších 'Learn X in Y Minutes' ze všech. JSON nemá ve své nejzákladnější podobě žádné komentáře, ale většina parserů umí pracovat s komentáři ve stylu jazyka C (`//`, `/* */`). Pro tyto účely však budeme používat 100% validní JSON bez komentářů. Pojďme se podívat na syntaxi formátu JSON: ```json { "klic": "value", "hodnoty": "Musí být vždy uvozený v dvojitých uvozovkách", "cisla": 0, "retezce": "Hellø, wørld. Všechny unicode znaky jsou povolené, společně s \"escapováním\".", "pravdivostni_hodnota": true, "prazdna_hodnota": null, "velke_cislo": 1.2e+100, "objekt": { "komentar": "Most of your structure will come from objects.", "pole": [0, 1, 2, 3, "Pole nemusí být pouze homogenní.", 5], "jiny_objekt": { "comment": "Je povolené jakkoli hluboké zanoření." } }, "cokoli": [ { "zdroje_drasliku": ["banány"] }, [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, "neo"], [0, 0, 0, 1] ] ], "alternativni_styl_zapisu": { "komentar": "Mrkni se na toto!" , "pozice_carky": "Na pozici čárky nezáleží - pokud je před hodnotou, ať už je kdekoli, tak je validní." , "dalsi_komentar": "To je skvělé." }, "to_bylo_rychle": "A tím jsme hotový. Nyní již víte vše, co může formát JSON nabídnout!" } ``` ================================================ FILE: cs/markdown.md ================================================ --- contributors: - ["Dan Turkel", "http://danturkel.com/"] translators: - ["Michal Martinek", "https://github.com/MichalMartinek"] - ["Tomáš Hartman", "https://github.com/tomas-hartman"] --- Markdown byl vytvořen Johnem Gruberem v roce 2004 jako značkovací jazyk, který lze snadno číst a psát a který je možné jednoduše převést do HTML (a dnes i do mnoha dalších formátů). Implementace markdownu se v různých parserech (syntaktických analyzátorech, které markdown dále zpracovávají) mírně odlišuje. V této příručce se snažíme upozorňovat, kdy se jedná o obecnou vlastnost markdownu a kdy se jedná o specifickou vlastnost daného parseru. ## HTML Elementy Markdown je nadstavba HTML. To znamená, že každý HTML kód je zároveň validním kódem v Markdownu. ```md ``` ## Nadpisy HTML elementy `

` až `

` vytvoříte jednoduše tak, že nadpisu předsadíte takový počet křížků (#), jaký odpovídá úrovni nadpisu. ```md # Toto je

## Toto je

### Toto je

#### Toto je

##### Toto je

###### Toto je
``` Markdown obsahuje ještě dva další způsoby, jak vytvořit h1 a h2: ```md Toto je h1 ========== Toto je h2 ---------- ``` ## Jednoduché stylování textu Pomocí markdownu můžete text jednoduše označit jako kurzívu či tučný text. ```md *Tento text je kurzívou;* _Stejně jako tento._ **Tento text je tučně** __Stejně jako tento.__ ***Tento text je obojí*** **_Tak jako tento!_** *__Nebo tento!__* ``` Ve verzi Markdownu od GitHubu máme k dispozici také přeškrtnutí: ```md ~~Tento text je přeškrtnutý.~~ ``` ## Odstavce Odstavce tvoří jeden nebo více řádků textu, oddělených jedním nebo více prázdnými řádky. ```md Toto je odstavec. Zde jsem napsal odstavec a je to bezva! Teď jsem v odstavci 2. A tady jsem pořád v odstavci 2! Ale tady už je odstavec 3. ``` Pokud byste chtěli vložit HTML element `
`, můžete na konec odstavce napsat dvě nebo více mezer a potom začít nový odstavec. ```md Tento odstavec končí dvěma mezerami. Nad tímto odstavcem je
! ``` ### Blokové citace Blokové citace se dělají jednoduše uvozením řádku znakem >. ```md > Toto je bloková citace. Můžete dokonce > manuálně rozdělit řádky, a před každý vložit >, nebo nechat vaše řádky > jakkoli dlouhé, ať se zarovnají samy. > Je to jedno, pokud vždy začínají symbolem `>`. > Použít můžu i více než jednu úroveň >> odsazení. > Co vy na to? ``` ## Seznamy Nečíslovaný seznam můžete jednoduše udělat pomocí hvězdiček, plusů nebo pomlček: ```md * Položka * Položka * Jiná položka nebo + Položka + Položka + Další položka nebo - Položka - Položka - Další položka ``` Číslované seznamy se dělají pomocí číslice a `.`. ```md 1. Položka jedna 2. Položka dvě 3. Položka tři 1. Položka jedna 1. Položka dvě 1. Položka tři ``` Můžete také tvořit podseznamy: ```md 1. Položka jedna 2. Položka dvě 3. Položka tři - Podpoložka - Podpoložka 4. Položka čtyři ``` Vytvořit lze i zaškrtávací seznamy. Takto lze vytvořit seznam s HTML checkboxy. (Boxy níže bez 'x' jsou nezaškrtnuté checkboxy.) ```md - [ ] První úkol, který je třeba dokončit - [ ] Druhý úkol na dodělání Tento box bude zaškrtnutý - [x] Tento úkol byl dokončen ``` ## Bloky kódu Bloky kódu můžete označit tak, že řádek odsadíte čtyřmi mezerami nebo pomocí tabu. Pro interpretaci kódu parser používá `` element. ```md Toto je kód Stejně jako toto ``` Pro ještě hlubší odsazení můžete přidat další 4 mezery nebo další tab: ```md moje_pole.each do |i| puts i end ``` Jednořádkový kód můžete zabalit do dvou zpětných apostrofů (`) tak, jako kdybyste text normálně stylovali: ```md Honza neměl tušení, co dělá funkce `go_to()`! ``` V Markdownu od GitHubu, můžete použít speciální syntaxi pro kód: ````md ```ruby def neco puts "Ahoj světe!" end ``` ```` Text výše nepotřebuje čtyřmezerové odsazení a parser navíc použije zvýraznění syntaxe pro zvolený jazyk. ## Vodorovná čára (`
`) Vodorovnou oddělovací čáru lze snadno přidat pomocí 3 nebo více hvězdiček (nebo pomlček), a to buď s mezerami mezi jednotlivými znaky, nebo bez nich. ```md *** --- - - - **************** ``` ## Odkazy ```md [Klikni na mě!](http://test.com/) [Klikni na mě!](http://test.com/ "Odkaz na Test.com") [Jdi na hudbu](/hudba/). [Klikni na tento odkaz][link1] pro více informací! [Taky zkontrolujte tento odkaz][neco], jestli tedy chcete. [link1]: http://test.com/ "Cool!" [neco]: http://neco.czz/ "Dobře!" [Toto][] je odkaz.. [toto]: http://totojelink.cz/ ``` ### Obsahy Kombinace seznamů, odkazů a nadpisů využívají také některé parsery pro generování obsahu Markdown souborů. Jako identifikátory slouží jména nadpisů psané malými písmeny, které jsou uvozené křížkem (`#`). Víceslovné nadpisy bývají propojeny pomlčkou (`-`), která někdy nahrazuje i speciální znaky. Jiné speciální znaky mohou být vynechány. ```md - [Nadpis](#nadpis) - [Víceslovný text](#víceslovný-text) - [Odstavce](#odstavce) - [Podkapitola

](#podkapitola-h3-) ``` V případě obsahů se v každém případě jedná o nadstavbu, která nemusí všude fungovat stejně. ## Obrázky ```md ![Toto je atribut alt pro obrázek](http://imgur.com/myimage.jpg "Nepovinný titulek") ![Toto je atribut alt][mujobrazek] [mujobrazek]: relativni/cesta/obrazek.jpg "a toto by byl titulek" ``` ## Ostatní ### Automatické odkazy ```md je stejné jako [http://stranka.cz/](http://stranka.cz/) ``` ### Automatické odkazy z emailů ```md ``` ### Escapování znaků ```md Chci napsat *tento text obklopený hvězdičkami*, ale protože nechci, aby to bylo kurzívou, tak hvězdičky vyescapuji `\`: \*tento text bude obklopený hvězdičkami\*. ``` ### Klávesové zkratky ```md Váš počítač přestal pracovat? Zkuste Ctrl+Alt+Del ``` ### Tabulky Tabulky lze využít pouze v Markdownu od GitHubu a jejich syntax je trošku zvláštní. Kdybyste je chtěli použít, vytváří se takto: ```md | Sloupec1 | Sloupec2 | Sloupec3 | | :----------- | :------: | ------------: | | Vlevo zarovn.| Na střed | Vpravo zarovn.| | blah | blah | blah | Sloupec 1 | Sloupec2 | Sloupec3 :-- | :-: | --: Že se to nedá číst? | No tak to takhle | radši nedělejte. ``` ## Markdownlint Pro usnadnění práce s Markdownem a s cílem sjednotit styl psaní jeho kódu vznikl nástroj `Markdownlint`. Tento nástroj je dostupný i jako plugin pro některé editory kódu (IDE) a lze jej použít jako nástroj pro vytváření a ověřování validity a čitelnosti Markdownu kódu. --- ## Reference Pro více informací doporučujeme oficiální článek o syntaxi od Johna Grubera [zde](http://daringfireball.net/projects/markdown/syntax) a skvělý tahák od Adama Pritcharda [zde](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). --- > _Pozn. překladatele:_ Tento text vznikl jako překlad původního článku, který > pochází z roku 2013 a kombinace původního českého překladu z roku 2015. > Některé informace v tomto článku, zejména ty, týkající se specifických > vlastností parserů markdownu tak již dnes mohou být zastaralé. Aktuální informace o specifických vlastnostech různých implementací Markdownu můžete nalézt zde (v angličtině): - [Markdown pro GitHub](https://docs.github.com/en/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) - [Markdown pro GitLab](https://docs.gitlab.com/ee/user/markdown.html) ================================================ FILE: cs/python.md ================================================ --- contributors: - ["Louie Dinh", "http://pythonpracticeprojects.com"] - ["Steven Basart", "http://github.com/xksteven"] - ["Andre Polykanine", "https://github.com/Oire"] - ["Tomáš Bedřich", "http://tbedrich.cz"] translators: - ["Tomáš Bedřich", "http://tbedrich.cz"] --- Python byl vytvořen Guidem Van Rossum v raných 90. letech. Nyní je jedním z nejpopulárnějších jazyků. Zamiloval jsem si Python pro jeho syntaktickou čistotu - je to vlastně spustitelný pseudokód. Poznámka: Tento článek je zaměřen na Python 3. Zde se můžete [naučit starší Python 2.7](/pythonlegacy/). ```python # Jednořádkový komentář začíná křížkem """ Víceřádkové komentáře používají tři uvozovky nebo apostrofy a jsou často využívány jako dokumentační komentáře k metodám """ #################################################### ## 1. Primitivní datové typy a operátory #################################################### # Čísla 3 # => 3 # Aritmetické operace se chovají běžným způsobem 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 # Až na dělení, které vrací desetinné číslo 35 / 5 # => 7.0 # Při celočíselném dělení je na výsledek aplikována funkce floor(), # což znamená zaokrouhlení směrem k mínus nekonečnu (pro kladná i záporná čísla). 5 // 3 # => 1 5.0 // 3.0 # => 1.0 # celočíselně dělit lze i desetinným číslem -5 // 3 # => -2 -5.0 // 3.0 # => -2.0 # Pokud použijete desetinné číslo, výsledek je jím také 3 * 2.0 # => 6.0 # Modulo 7 % 3 # => 1 # Mocnění (x na y-tou) 2**4 # => 16 # Pro vynucení priority použijte závorky (1 + 3) * 2 # => 8 # Logické hodnoty True False # Negace se provádí pomocí not not True # => False not False # => True # Logické operátory # U operátorů záleží na velikosti písmen True and False # => False False or True # => True # Používání logických operátorů s čísly 0 and 2 # => 0 -5 or 0 # => -5 # Při porovnání s boolean hodnotou nepoužívejte operátor rovnosti "==". # Stejně jako u hodnoty None. # Viz PEP8: https://www.python.org/dev/peps/pep-0008/ 0 is False # => True 2 is True # => False 1 is True # => True # Rovnost je == 1 == 1 # => True 2 == 1 # => False # Nerovnost je != 1 != 1 # => False 2 != 1 # => True # Další porovnání 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # Porovnání se dají řetězit! 1 < 2 < 3 # => True 2 < 3 < 2 # => False # Řetězce používají " nebo ' a mohou obsahovat unicode znaky "Toto je řetězec." 'Toto je také řetězec.' # Řetězce se také dají slučovat "Hello " + "world!" # => "Hello world!" # Dají se spojovat i bez '+' "Hello " "world!" # => "Hello world!" # Řetězec lze považovat za seznam znaků "Toto je řetězec"[0] # => 'T' # .format lze použít ke skládání řetězců "{} mohou být {}".format("řetězce", "skládány") # Formátovací argumenty můžete opakovat "{0} {1} stříkaček stříkalo přes {0} {1} střech".format("tři sta třicet tři", "stříbrných") # => "tři sta třicet tři stříbrných stříkaček stříkalo přes tři sta třicet tři stříbrných střech" # Pokud nechcete počítat, můžete použít pojmenované argumenty "{jmeno} si dal {jidlo}".format(jmeno="Franta", jidlo="guláš") # => "Franta si dal guláš" # Pokud zároveň potřebujete podporovat Python 2.5 a nižší, můžete použít starší způsob formátování "%s se dají %s jako v %s" % ("řetězce", "skládat", "jazyce C") # None je objekt (jinde NULL, nil, ...) None # => None # Pokud porovnáváte něco s None, nepoužívejte operátor rovnosti "==", # použijte raději operátor "is", který testuje identitu. "něco" is None # => False None is None # => True # None, 0, a prázdný řetězec/seznam/N-tice/slovník/množina se vyhodnotí jako False # Vše ostatní se vyhodnotí jako True bool(0) # => False bool("") # => False bool([]) # => False bool(tuple()) # => False bool({}) # => False bool(set()) # => False #################################################### ## 2. Proměnné a kolekce #################################################### # Python má funkci print print("Jsem 3. Python 3.") # Proměnné není třeba deklarovat před přiřazením # Konvence je používat male_pismo_s_podtrzitky nazev_promenne = 5 nazev_promenne # => 5 # Názvy proměnných mohou obsahovat i unicode znaky, ale nedělejte to. # Viz PEP 3131 -- Supporting Non-ASCII Identifiers: # https://www.python.org/dev/peps/pep-3131/ název_proměnné = 5 # Přístup k předtím nedefinované proměnné vyvolá výjimku # Odchytávání vyjímek - viz další kapitola neznama_promenna # Vyhodí NameError # Seznam se používá pro ukládání sekvencí sez = [] # Lze ho rovnou naplnit jiny_seznam = [4, 5, 6] # Na konec seznamu se přidává pomocí append sez.append(1) # sez je nyní [1] sez.append(2) # sez je nyní [1, 2] sez.append(4) # sez je nyní [1, 2, 4] sez.append(3) # sez je nyní [1, 2, 4, 3] # Z konce se odebírá se pomocí pop sez.pop() # => 3 a sez je nyní [1, 2, 4] # Vložme trojku zpátky sez.append(3) # sez je nyní znovu [1, 2, 4, 3] # Přístup k prvkům funguje jako v poli sez[0] # => 1 # Mínus počítá odzadu (-1 je poslední prvek) sez[-1] # => 3 # Přístup mimo seznam vyhodí IndexError sez[4] # Vyhodí IndexError # Pomocí řezů lze ze seznamu vybírat různé intervaly # (pro matematiky: jedná se o uzavřený/otevřený interval) sez[1:3] # => [2, 4] # Odříznutí začátku sez[2:] # => [4, 3] # Odříznutí konce sez[:3] # => [1, 2, 4] # Vybrání každého druhého prvku sez[::2] # =>[1, 4] # Vrácení seznamu v opačném pořadí sez[::-1] # => [3, 4, 2, 1] # Lze použít jakoukoliv kombinaci parametrů pro vytvoření složitějšího řezu # sez[zacatek:konec:krok] # Odebírat prvky ze seznamu lze pomocí del del sez[2] # sez je nyní [1, 2, 3] # Seznamy můžete slučovat # Hodnoty sez a jiny_seznam přitom nejsou změněny sez + jiny_seznam # => [1, 2, 3, 4, 5, 6] # Spojit seznamy lze pomocí extend sez.extend(jiny_seznam) # sez je nyní [1, 2, 3, 4, 5, 6] # Kontrola, jestli prvek v seznamu existuje, se provádí pomocí in 1 in sez # => True # Délku seznamu lze zjistit pomocí len len(sez) # => 6 # N-tice je jako seznam, ale je neměnná ntice = (1, 2, 3) ntice[0] # => 1 ntice[0] = 3 # Vyhodí TypeError # S n-ticemi lze dělat většinu operací, jako se seznamy len(ntice) # => 3 ntice + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) ntice[:2] # => (1, 2) 2 in ntice # => True # N-tice (nebo seznamy) lze rozbalit do proměnných jedním přiřazením a, b, c = (1, 2, 3) # a je nyní 1, b je nyní 2 a c je nyní 3 # N-tice jsou vytvářeny automaticky, když vynecháte závorky d, e, f = 4, 5, 6 # Prohození proměnných je tak velmi snadné e, d = d, e # d je nyní 5, e je nyní 4 # Slovníky ukládají klíče a hodnoty prazdny_slovnik = {} # Lze je také rovnou naplnit slovnik = {"jedna": 1, "dva": 2, "tři": 3} # Přistupovat k hodnotám lze pomocí [] slovnik["jedna"] # => 1 # Všechny klíče dostaneme pomocí keys() jako iterovatelný objekt. Nyní ještě # potřebujeme obalit volání v list(), abychom dostali seznam. To rozebereme # později. Pozor, že jakékoliv pořadí klíčů není garantováno - může být různé. list(slovnik.keys()) # => ["dva", "jedna", "tři"] # Všechny hodnoty opět jako iterovatelný objekt získáme pomocí values(). Opět # tedy potřebujeme použít list(), abychom dostali seznam. Stejně jako # v předchozím případě, pořadí není garantováno a může být různé list(slovnik.values()) # => [3, 2, 1] # Operátorem in se lze dotázat na přítomnost klíče "jedna" in slovnik # => True 1 in slovnik # => False # Přístup k neexistujícímu klíči vyhodí KeyError slovnik["čtyři"] # Vyhodí KeyError # Metoda get() funguje podobně jako [], ale vrátí None místo vyhození KeyError slovnik.get("jedna") # => 1 slovnik.get("čtyři") # => None # Metodě get() lze předat i výchozí hodnotu místo None slovnik.get("jedna", 4) # => 1 slovnik.get("čtyři", 4) # => 4 # metoda setdefault() vloží prvek do slovníku pouze pokud tam takový klíč není slovnik.setdefault("pět", 5) # slovnik["pět"] je nastaven na 5 slovnik.setdefault("pět", 6) # slovnik["pět"] je pořád 5 # Přidání nové hodnoty do slovníku slovnik["čtyři"] = 4 # Hromadně aktualizovat nebo přidat data lze pomocí update(), parametrem je opět slovník slovnik.update({"čtyři": 4}) # slovnik je nyní {"jedna": 1, "dva": 2, "tři": 3, "čtyři": 4, "pět": 5} # Odebírat ze slovníku dle klíče lze pomocí del del slovnik["jedna"] # odebere klíč "jedna" ze slovnik # Množiny ukládají ... překvapivě množiny prazdna_mnozina = set() # Také je lze rovnou naplnit. A ano, budou se vám plést se slovníky. Bohužel. mnozina = {1, 1, 2, 2, 3, 4} # mnozina je nyní {1, 2, 3, 4} # Přidání položky do množiny mnozina.add(5) # mnozina je nyní {1, 2, 3, 4, 5} # Průnik lze udělat pomocí operátoru & jina_mnozina = {3, 4, 5, 6} mnozina & jina_mnozina # => {3, 4, 5} # Sjednocení pomocí operátoru | mnozina | jina_mnozina # => {1, 2, 3, 4, 5, 6} # Rozdíl pomocí operátoru - {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # Operátorem in se lze dotázat na přítomnost prvku v množině 2 in mnozina # => True 9 in mnozina # => False #################################################### ## 3. Řízení toku programu, cykly #################################################### # Vytvořme si proměnnou promenna = 5 # Takto vypadá podmínka. Na odsazení v Pythonu záleží! # Vypíše "proměnná je menší než 10". if promenna > 10: print("proměnná je velká jak Rusko") elif promenna < 10: # Část elif je nepovinná print("proměnná je menší než 10") else: # Část else je také nepovinná print("proměnná je právě 10") """ Smyčka for umí iterovat (nejen) přes seznamy vypíše: pes je savec kočka je savec myš je savec """ for zvire in ["pes", "kočka", "myš"]: # Můžete použít formát pro složení řetězce print("{} je savec".format(zvire)) """ range(cislo) vrací iterovatelný objekt čísel od 0 do cislo vypíše: 0 1 2 3 """ for i in range(4): print(i) """ range(spodni_limit, horni_limit) vrací iterovatelný objekt čísel mezi limity vypíše: 4 5 6 7 """ for i in range(4, 8): print(i) """ Smyčka while se opakuje, dokud je podmínka splněna. vypíše: 0 1 2 3 """ x = 0 while x < 4: print(x) x += 1 # Zkrácený zápis x = x + 1. Pozor, žádné x++ neexisuje. # Výjimky lze ošetřit pomocí bloku try/except(/else/finally) try: # Pro vyhození výjimky použijte raise raise IndexError("Přistoupil jste k neexistujícímu prvku v seznamu.") except IndexError as e: print("Nastala chyba: {}".format(e)) # Vypíše: Nastala chyba: Přistoupil jste k neexistujícímu prvku v seznamu. except (TypeError, NameError): # Více výjimek lze zachytit najednou pass # Pass znamená nedělej nic - nepříliš vhodný způsob ošetření chyb else: # Volitelný blok else musí být až za bloky except print("OK!") # Vypíše OK! v případě, že nenastala žádná výjimka finally: # Blok finally se spustí nakonec za všech okolností print("Uvolníme zdroje, uzavřeme soubory...") # Místo try/finally lze použít with pro automatické uvolnění zdrojů with open("soubor.txt") as soubor: for radka in soubor: print(radka) # Python běžně používá iterovatelné objekty, což je prakticky cokoliv, # co lze považovat za sekvenci. Například to, co vrací metoda range(), # nebo otevřený soubor, jsou iterovatelné objekty. slovnik = {"jedna": 1, "dva": 2, "tři": 3} iterovatelny_objekt = slovnik.keys() print(iterovatelny_objekt) # => dict_keys(["jedna", "dva", "tři"]). Toto je iterovatelný objekt. # Můžeme použít cyklus for na jeho projití for klic in iterovatelny_objekt: print(klic) # vypíše postupně: jedna, dva, tři # Ale nelze přistupovat k prvkům pod jejich indexem iterovatelny_objekt[1] # Vyhodí TypeError # Všechny položky iterovatelného objektu lze získat jako seznam pomocí list() list(slovnik.keys()) # => ["jedna", "dva", "tři"] # Z iterovatelného objektu lze vytvořit iterátor iterator = iter(iterovatelny_objekt) # Iterátor je objekt, který si pamatuje stav v rámci svého iterovatelného objektu # Další hodnotu dostaneme voláním next() next(iterator) # => "jedna" # Iterátor si udržuje svůj stav v mezi jednotlivými voláními next() next(iterator) # => "dva" next(iterator) # => "tři" # Jakmile interátor vrátí všechna svá data, vyhodí výjimku StopIteration next(iterator) # Vyhodí StopIteration #################################################### ## 4. Funkce #################################################### # Pro vytvoření nové funkce použijte klíčové slovo def def secist(x, y): print("x je {} a y je {}".format(x, y)) return x + y # Hodnoty se vrací pomocí return # Volání funkce s parametry secist(5, 6) # => Vypíše "x je 5 a y je 6" a vrátí 11 # Jiný způsob, jak volat funkci, je použít pojmenované argumenty secist(y=6, x=5) # Pojmenované argumenty můžete předat v libovolném pořadí # Lze definovat funkce s proměnným počtem (pozičních) argumentů def vrat_argumenty(*argumenty): return argumenty vrat_argumenty(1, 2, 3) # => (1, 2, 3) # Lze definovat také funkce s proměnným počtem pojmenovaných argumentů def vrat_pojmenovane_argumenty(**pojmenovane_argumenty): return pojmenovane_argumenty vrat_pojmenovane_argumenty(kdo="se bojí", nesmi="do lesa") # => {"kdo": "se bojí", "nesmi": "do lesa"} # Pokud chcete, lze použít obojí najednou # Konvence je používat pro tyto účely názvy *args a **kwargs def vypis_vse(*args, **kwargs): print(args, kwargs) # print() vypíše všechny své parametry oddělené mezerou vypis_vse(1, 2, a=3, b=4) # Vypíše: (1, 2) {"a": 3, "b": 4} # * nebo ** lze použít k rozbalení N-tic nebo slovníků! ntice = (1, 2, 3, 4) slovnik = {"a": 3, "b": 4} vypis_vse(ntice) # Vyhodnotí se jako vypis_vse((1, 2, 3, 4)) – jeden parametr, N-tice vypis_vse(*ntice) # Vyhodnotí se jako vypis_vse(1, 2, 3, 4) vypis_vse(**slovnik) # Vyhodnotí se jako vypis_vse(a=3, b=4) vypis_vse(*ntice, **slovnik) # Vyhodnotí se jako vypis_vse(1, 2, 3, 4, a=3, b=4) # Viditelnost proměnných - vytvořme si globální proměnnou x x = 5 def nastavX(cislo): # Lokální proměnná x překryje globální x x = cislo # => 43 print(x) # => 43 def nastavGlobalniX(cislo): global x print(x) # => 5 x = cislo # Nastaví globální proměnnou x na 6 print(x) # => 6 nastavX(43) nastavGlobalniX(6) # Funkce jsou first-class objekty def vyrobit_scitacku(pricitane_cislo): def scitacka(x): return x + pricitane_cislo return scitacka pricist_10 = vyrobit_scitacku(10) pricist_10(3) # => 13 # Klíčové slovo lambda vytvoří anonymní funkci (lambda parametr: parametr > 2)(3) # => True # Lze použít funkce map() a filter() z funkcionálního programování map(pricist_10, [1, 2, 3]) # => - iterovatelný objekt s obsahem: [11, 12, 13] filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => - iterovatelný objekt s obsahem: [6, 7] # S generátorovou notací lze dosáhnout podobných výsledků, ale vrací seznam [pricist_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # Generátorová notace funguje i pro slovníky {x: x**2 for x in range(1, 5)} # => {1: 1, 2: 4, 3: 9, 4: 16} # A také pro množiny {pismeno for pismeno in "abeceda"} # => {"d", "a", "c", "e", "b"} #################################################### ## 5. Třídy #################################################### # Třída Clovek je potomkem (dědí od) třídy object class Clovek(object): # Atribut třídy - je sdílený všemi instancemi druh = "H. sapiens" # Toto je kostruktor. Je volán, když vytváříme instanci třídy. Dvě # podtržítka na začátku a na konci značí, že se jedná o atribut nebo # objekt využívaný Pythonem ke speciálním účelům, ale můžete sami # definovat jeho chování. Metody jako __init__, __str__, __repr__ # a další se nazývají "magické metody". Nikdy nepoužívejte toto # speciální pojmenování pro běžné metody. def __init__(self, jmeno): # Přiřazení parametru do atributu instance jmeno self.jmeno = jmeno # Metoda instance - všechny metody instance mají "self" jako první parametr def rekni(self, hlaska): return "{jmeno}: {hlaska}".format(jmeno=self.jmeno, hlaska=hlaska) # Metoda třídy - sdílená všemi instancemi # Dostává jako první parametr třídu, na které je volána @classmethod def vrat_druh(cls): return cls.druh # Statická metoda je volána bez reference na třídu nebo instanci @staticmethod def odkaslej_si(): return "*ehm*" # Vytvoření instance d = Clovek(jmeno="David") a = Clovek("Adéla") print(d.rekni("ahoj")) # Vypíše: "David: ahoj" print(a.rekni("nazdar")) # Vypíše: "Adéla: nazdar" # Volání třídní metody d.vrat_druh() # => "H. sapiens" # Změna atributu třídy Clovek.druh = "H. neanderthalensis" d.vrat_druh() # => "H. neanderthalensis" a.vrat_druh() # => "H. neanderthalensis" # Volání statické metody Clovek.odkaslej_si() # => "*ehm*" #################################################### ## 6. Moduly #################################################### # Lze importovat moduly import math print(math.sqrt(16.0)) # => 4.0 # Lze také importovat pouze vybrané funkce z modulu from math import ceil, floor print(ceil(3.7)) # => 4.0 print(floor(3.7)) # => 3.0 # Můžete také importovat všechny funkce z modulu, ale radši to nedělejte from math import * # Můžete si přejmenovat modul při jeho importu import math as m math.sqrt(16) == m.sqrt(16) # => True # Modul v Pythonu není nic jiného, než obyčejný soubor .py # Můžete si napsat vlastní a prostě ho importovat podle jména from muj_modul import moje_funkce # Nyní vyhodí ImportError - muj_modul neexistuje # Funkcí dir() lze zjistit, co modul obsahuje import math dir(math) #################################################### ## 7. Pokročilé #################################################### # Generátory jsou funkce, které místo return obsahují yield def nasobicka_2(sekvence): for i in sekvence: print("Zpracovávám číslo {}".format(i)) yield 2 * i # Generátor generuje hodnoty postupně, jak jsou potřeba. Místo toho, aby vrátil # celou sekvenci s prvky vynásobenými dvěma, provádí jeden výpočet v každé iteraci. for nasobek in nasobicka_2([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]): # Vypíše postupně: "Zpracovávám číslo 1", ..., "Zpracovávám číslo 5" if nasobek >= 10: break # Funkce range() je také generátor - vytváření seznamu 900000000 prvků by zabralo # hodně času i paměti, proto se místo toho čísla generují postupně. for nasobek in nasobicka_2(range(900000000)): # Vypíše postupně: "Zpracovávám číslo 1", ..., "Zpracovávám číslo 5" if nasobek >= 10: break # Dekorátory jsou funkce, které se používají pro obalení jiné funkce, čímž mohou # přidávat nebo měnit její stávající chování. Funkci dostávají jako parametr # a typicky místo ní vrací jinou, která uvnitř volá tu původní. def nekolikrat(puvodni_funkce): def opakovaci_funkce(*args, **kwargs): for i in range(3): puvodni_funkce(*args, **kwargs) return opakovaci_funkce @nekolikrat def pozdrav(jmeno): print("Měj se {}!".format(jmeno)) pozdrav("Pepo") # Vypíše 3x: "Měj se Pepo!" ``` ## Co dál? Spoustu odkazů na české i anglické materiály najdete na [webu české Python komunity](http://python.cz/). Můžete také přijít na Pyvo, kde to společně probereme. ================================================ FILE: cs/sass.md ================================================ --- contributors: - ["Laura Kyle", "https://github.com/LauraNK"] - ["Sean Corrales", "https://github.com/droidenator"] translators: - ["Michal Martinek", "https://github.com/MichalMartinek"] --- Sass je rozšíření jazyka CSS, který přidává nové vlastnosti jako proměnné, zanořování, mixiny a další. Sass (a další preprocesory, jako [Less](http://lesscss.org/)) pomáhají vývojářům psát udržovatelný a neopakující (DRY) kód. Sass nabízí dvě možnosti syntaxe. SCSS, které je stejná jako CSS, akorát obsahuje nové vlastnosti Sassu. Nebo Sass, který používá odsazení místo složených závorek a středníků. Tento tutoriál bude používat syntaxi CSS. Pokud jste již obeznámeni s CSS3, budete schopni používat Sass relativně rychle. Nezprostředkovává nějaké úplně nové stylové možnosti, spíše nátroje, jak psát Vás CSS kód více efektivně, udržitelně a jednoduše. ```scss //Jednořádkové komentáře jsou ze Sassu při kompilaci vymazány /*Víceřádkové komentáře jsou naopak zachovány */ /*Proměnné ==============================*/ /* Můžete uložit CSS hodnotu (jako třeba barvu) do proměnné. Použijte symbol '$' k jejímu vytvoření. */ $hlavni-barva: #A3A4FF; $sekundarni-barva: #51527F; $body-font: 'Roboto', sans-serif; /* Můžete používat proměnné napříč vaším souborem. Teď, když chcete změnit barvu, stačí ji změnit pouze jednou.*/ body { background-color: $hlavni-barva; color: $sekundarni-barva; font-family: $body-font; } /* Toto se zkompiluje do: */ body { background-color: #A3A4FF; color: #51527F; font-family: 'Roboto', sans-serif; } /* Toto je o hodně více praktické, než měnit každý výskyt barvy. */ /*Mixiny ==============================*/ /* Pokud zjistíte, že píšete kód pro více než jeden element, můžete jej uložit do mixinu. Použijte '@mixin' direktivu, plus jméno vašeho mixinu.*/ @mixin na-stred { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; } /* Mixin vložíte pomocí '@include' a jména mixinu */ div { @include na-stred; background-color: $hlavni-barva; } /*Což se zkompiluje do: */ div { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; background-color: #A3A4FF; } /* Můžete využít mixiny i třeba pro takovéto ušetření práce: */ @mixin velikost($sirka, $vyska) { width: $sirka; height: $vyska; } /*Stačí vložit argumenty: */ .obdelnik { @include velikost(100px, 60px); } .ctverec { @include velikost(40px, 40px); } /* Toto se zkompiluje do: */ .obdelnik { width: 100px; height: 60px; } .ctverec { width: 40px; height: 40px; } /*Funkce ==============================*/ /* Sass obsahuje funkce, které vám pomůžou splnit různé úkoly. */ /* Funkce se spouštějí pomocí jejich jména, které následuje seznam argumentů uzavřený v kulatých závorkách. */ body { width: round(10.25px); } .footer { background-color: fade_out(#000000, 0.25) } /* Se zkompiluje do: */ body { width: 10px; } .footer { background-color: rgba(0, 0, 0, 0.75); } /* Můžete také definovat vlastní funkce. Funkce jsou velmi podobné mixinům. Když se snažíte vybrat mezi funkcí a mixinem, mějte na paměti, že mixiny jsou lepší pro generování CSS kódu, zatímco funkce jsou lepší pro logiku. Příklady ze sekce Matematické operátory jsou skvělí kandidáti na znovupoužitelné funkce. */ /* Tato funkce vrací poměr k velikosti rodiče v procentech. @function vypocitat-pomer($velikost, $velikost-rodice) { @return $velikost / $velikost-rodice * 100%; } $hlavni obsah: vypocitat-pomer(600px, 960px); .hlavni-obsah { width: $hlavni-obsah; } .sloupec { width: vypocitat-pomer(300px, 960px); } /* Zkompiluje do: */ .hlavni-obsah { width: 62.5%; } .sloupec { width: 31.25%; } /*Dědění ==============================*/ /*Dědění je způsob jak používat vlastnosti pro jeden selektor ve druhém. */ .oznameni { @include velikost(5em, 5em); border: 5px solid $sekundarni-barva; } .oznameni-uspech { @extend .oznameni; border-color: #22df56; } /* Zkompiluje do: */ .oznameni, .oznameni-uspech { width: 5em; height: 5em; border: 5px solid #51527F; } .oznameni-uspech { border-color: #22df56; } /* Dědění CSS výrazů je preferováno před vytvořením mixinu kvůli způsobu, jakým způsobem Sass dává dohromady třídy, které sdílejí stejný kód. Kdyby to bylo udělané pomocí mixinu, tak výška, šířka, rámeček by byl v každém výrazu, který by volal mixin. I když tohle neovlivní vaše workflow, přidá to kód navíc do souborů. */ /*Zanořování ==============================*/ /*Sass vám umožňuje zanořovat selektory do selektorů */ ul { list-style-type: none; margin-top: 2em; li { background-color: #FF0000; } } /* '&' nahradí rodičovský element. */ /* Můžete také zanořovat pseudo třídy. */ /* Pamatujte, že moc velké zanoření do hloubky snižuje čitelnost. Doporučuje se používat maximálně trojité zanoření. Na příklad: */ ul { list-style-type: none; margin-top: 2em; li { background-color: red; &:hover { background-color: blue; } a { color: white; } } } /* Zkompiluje do: */ ul { list-style-type: none; margin-top: 2em; } ul li { background-color: red; } ul li:hover { background-color: blue; } ul li a { color: white; } /*Částečné soubory a importy ==============================*/ /* Sass umožňuje vytvářet částečné soubory. Tyto soubory pomahájí udržovat váš kód modulární. Tyto soubory by měli začínat vždy '_', např. _reset.css. Částečné soubory se nepřevádí do CSS. */ /* Toto je kód, který si uložíme do souboru _reset.css */ html, body, ul, ol { margin: 0; padding: 0; } /* Sass obsahuje @import, které může být použit pro import částečných souborů. Toto se liší od klasického CSS @import, který dělá HTTP požadavek na stáhnutí souboru. Sass vezme importovaný soubor a vloží ho do kompilovaného kódu. */ @import 'reset'; body { font-size: 16px; font-family: Helvetica, Arial, Sans-serif; } /* Zkompiluje do: */ html, body, ul, ol { margin: 0; padding: 0; } body { font-size: 16px; font-family: Helvetica, Arial, Sans-serif; } /*Zástupné selektory ==============================*/ /* Zástupné selektory jsou užitečné, když vytváříte CSS výraz, ze kterého chcete později dědit. Když chcete vytvořit výraz, ze kterého je možné pouze dědit pomocí @extend, vytvořte zástupný selektor s CSS výrazem. Ten začíná symbolem '%' místo '.' nebo '#'. Tyto výrazy se neobjeví ve výsledném CSS */ %okno-obsahu { font-size: 14px; padding: 10px; color: #000; border-radius: 4px; } .okno-zpravy { @extend %okno-obsahu; background-color: #0000ff; } /* Zkompiluje do: */ .okno-zpravy { font-size: 14px; padding: 10px; color: #000; border-radius: 4px; } .okno-zpravy { background-color: #0000ff; } /*Matematické operace ==============================*/ /* Sass obsahuje následující operátory: +, -, *, /, and %. Tyto operátory můžou být velmi užitečné pro počítání hodnot přímo ve vašem souboru Sass. Níže je příklad, jak udělat jednoduchý dvousloupcový layout. */ $oblast-obsahu: 960px; $hlavni-obsah: 600px; $vedlejsi-sloupec: 300px; $obsah-velikost: $hlavni-obsah / $oblast-obsahu * 100%; $vedlejsi-sloupec-velikost: $vedlejsi-sloupec / $oblast-obsahu * 100%; $zbytek-velikost: 100% - ($main-size + $vedlejsi-sloupec-size); body { width: 100%; } .hlavni-obsah { width: $obsah-velikost; } .vedlejsi-sloupec { width: $vedlejsi-sloupec-velikost; } .zbytek { width: $zbytek-velikost; } /* Zkompiluje do: */ body { width: 100%; } .hlavni-obsah { width: 62.5%; } .vedlejsi-sloupec { width: 31.25%; } .gutter { width: 6.25%; } ``` ## SASS nebo Sass? Divili jste se někdy, jestli je Sass zkratka nebo ne? Pravděpodobně ne, ale řeknu vám to stejně. Jméno tohoto jazyka je slovo, "Sass", a ne zkratka. Protože to lidé konstatně píší jako "SASS", nazval ho autor jazyka jako "Syntactically Awesome StyleSheets" (Syntaktický úžasně styly). ## Procvičování Sassu Pokud si chcete hrát se Sassem ve vašem prohlížeči, navštivte [SassMeister](http://sassmeister.com/). Můžete používát oba dva způsoby zápisu, stačí si vybrat v nastavení SCSS nebo SASS. ## Kompatibilita Sass může být použit v jakémkoliv projektu, jakmile máte program, pomocí kterého ho zkompilujete do CSS. Pokud si chcete ověřit, že CSS, které Sass produkuje je kompatibilní s prohlížeči: [QuirksMode CSS](http://www.quirksmode.org/css/) a [CanIUse](http://caniuse.com) jsou skvělé stránky pro kontrolu kompatibility. ## Kam dál? * [Oficiální dokumentace](http://sass-lang.com/documentation/file.SASS_REFERENCE.html) * [The Sass Way](http://thesassway.com/) obsahuje tutoriál a řadu skvělých článků ================================================ FILE: csharp.md ================================================ --- name: C# contributors: - ["Irfan Charania", "https://github.com/irfancharania"] - ["Max Yankov", "https://github.com/golergka"] - ["Melvyn Laïly", "http://x2a.yt"] - ["Shaun McCarthy", "http://www.shaunmccarthy.com"] - ["Wouter Van Schandevijl", "http://github.com/laoujin"] - ["Jo Pearce", "http://github.com/jdpearce"] - ["Chris Zimmerman", "https://github.com/chriszimmerman"] - ["Shawn McGuire", "https://github.com/bigbash"] filename: LearnCSharp.cs --- C# is an elegant and type-safe object-oriented language that enables developers to build a variety of secure and robust applications that run on the cross-platform .NET framework. [Read more here.](https://docs.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/) ```c# // Single-line comments start with // /* Multi-line comments look like this */ /// /// This is an XML documentation comment which can be used to generate external /// documentation or provide context help within an IDE /// /// This is some parameter documentation for firstParam /// Information on the returned value of a function public void MethodOrClassOrOtherWithParsableHelp(string firstParam) { } // Specify the namespaces this source code will be using // The namespaces below are all part of the standard .NET Framework Class Library using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Net; using System.Threading.Tasks; using System.IO; // But this one is not: using System.Data.Entity; // In order to be able to use it, you need to add a dll reference // This can be done with the NuGet package manager: `Install-Package EntityFramework` // Namespaces define scope to organize code into "packages" or "modules" // Using this code from another source file: using Learning.CSharp; // You can also do this in C# 10, it is called file-scoped namespaces. // namespace Learning.CSharp; namespace Learning.CSharp { // Each .cs file should at least contain a class with the same name as the file. // You're allowed to do otherwise, but shouldn't for sanity. public class LearnCSharp { // BASIC SYNTAX - skip to INTERESTING FEATURES if you have used Java or C++ before public static void Syntax() { // Use Console.WriteLine to print lines Console.WriteLine("Hello World"); Console.WriteLine( "Integer: " + 10 + " Double: " + 3.14 + " Boolean: " + true); // To print without a new line, use Console.Write Console.Write("Hello "); Console.Write("World"); /////////////////////////////////////////////////// // Types & Variables // // Declare a variable using /////////////////////////////////////////////////// // Sbyte - Signed 8-bit integer // (-128 <= sbyte <= 127) sbyte fooSbyte = 100; // Byte - Unsigned 8-bit integer // (0 <= byte <= 255) byte fooByte = 100; // Short - 16-bit integer // Signed - (-32,768 <= short <= 32,767) // Unsigned - (0 <= ushort <= 65,535) short fooShort = 10000; ushort fooUshort = 10000; // Integer - 32-bit integer int fooInt = 1; // (-2,147,483,648 <= int <= 2,147,483,647) uint fooUint = 1; // (0 <= uint <= 4,294,967,295) // Long - 64-bit integer long fooLong = 100000L; // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) ulong fooUlong = 100000L; // (0 <= ulong <= 18,446,744,073,709,551,615) // Numbers default to being int or uint depending on size. // L is used to denote that this variable value is of type long or ulong // Double - Double-precision 64-bit IEEE 754 Floating Point double fooDouble = 123.4; // Precision: 15-16 digits // Float - Single-precision 32-bit IEEE 754 Floating Point float fooFloat = 234.5f; // Precision: 7 digits // f is used to denote that this variable value is of type float // Decimal - a 128-bits data type, with more precision than other floating-point types, // suited for financial and monetary calculations decimal fooDecimal = 150.3m; // Boolean - true & false bool fooBoolean = true; // or false // Char - A single 16-bit Unicode character char fooChar = 'A'; // Strings -- unlike the previous base types which are all value types, // a string is a reference type. That is, you can set it to null string fooString = "\"escape\" quotes and add \n (new lines) and \t (tabs)"; Console.WriteLine(fooString); // You can access each character of the string with an indexer: char charFromString = fooString[1]; // => 'e' // Strings are immutable: you can't do fooString[1] = 'X'; // Compare strings with current culture, ignoring case string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase); // Formatting, based on sprintf string fooFs = string.Format("Check Check, {0} {1}, {0} {1:0.0}", 1, 2); // Dates & Formatting DateTime fooDate = DateTime.Now; Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy")); // Verbatim String // You can use the @ symbol before a string literal to escape all characters in the string string path = "C:\\Users\\User\\Desktop"; string verbatimPath = @"C:\Users\User\Desktop"; Console.WriteLine(path == verbatimPath); // => true // You can split a string over two lines with the @ symbol. To escape " use "" string bazString = @"Here's some stuff on a new line! ""Wow!"", the masses cried"; // Use const or read-only to make a variable immutable // const values are calculated at compile time const int HoursWorkPerWeek = 9001; /////////////////////////////////////////////////// // Data Structures /////////////////////////////////////////////////// // Arrays - zero indexed // The array size must be decided upon declaration // The format for declaring an array is // [] = new []; int[] intArray = new int[10]; // Another way to declare & initialize an array int[] y = { 9000, 1000, 1337 }; // Indexing an array - Accessing an element Console.WriteLine("intArray @ 0: " + intArray[0]); // Arrays are mutable. intArray[1] = 1; // Lists // Lists are used more frequently than arrays as they are more flexible // The format for declaring a list is // List = new List(); List intList = new List(); List stringList = new List(); List z = new List { 9000, 1000, 1337 }; // initialize // The <> are for generics - Check out the cool stuff section // Lists don't default to a value; // A value must be added before accessing the index intList.Add(1); Console.WriteLine("intList at 0: " + intList[0]); // Other data structures to check out: // Stack/Queue // Dictionary (an implementation of a hash map) // HashSet // Read-only Collections // Tuple (.NET 4+) /////////////////////////////////////// // Operators /////////////////////////////////////// Console.WriteLine("\n->Operators"); int i1 = 1, i2 = 2; // Shorthand for multiple declarations // Arithmetic is straightforward Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3 // Modulo Console.WriteLine("11%3 = " + (11 % 3)); // => 2 // Comparison operators Console.WriteLine("3 == 2? " + (3 == 2)); // => false Console.WriteLine("3 != 2? " + (3 != 2)); // => true Console.WriteLine("3 > 2? " + (3 > 2)); // => true Console.WriteLine("3 < 2? " + (3 < 2)); // => false Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true // Bitwise operators! /* ~ Unary bitwise complement << Signed left shift >> Signed right shift & Bitwise AND ^ Bitwise exclusive OR | Bitwise inclusive OR */ // Incrementing int i = 0; Console.WriteLine("\n->Inc/Dec-rement"); Console.WriteLine(i++); //Prints "0", i = 1. Post-Increment Console.WriteLine(++i); //Prints "2", i = 2. Pre-Increment Console.WriteLine(i--); //Prints "2", i = 1. Post-Decrement Console.WriteLine(--i); //Prints "0", i = 0. Pre-Decrement /////////////////////////////////////// // Control Structures /////////////////////////////////////// Console.WriteLine("\n->Control Structures"); // If statements are C-like int j = 10; if (j == 10) { Console.WriteLine("I get printed"); } else if (j > 10) { Console.WriteLine("I don't"); } else { Console.WriteLine("I also don't"); } // Ternary operators // A simple if/else can be written as follows // ? : int toCompare = 17; string isTrue = toCompare == 17 ? "True" : "False"; // While loop int fooWhile = 0; while (fooWhile < 100) { // Iterated 100 times, fooWhile 0->99 fooWhile++; } // Do While Loop int fooDoWhile = 0; do { // Start iteration 100 times, fooDoWhile 0->99 if (false) continue; // skip the current iteration fooDoWhile++; if (fooDoWhile == 50) break; // breaks from the loop completely } while (fooDoWhile < 100); // for loop structure => for(; ; ) for (int fooFor = 0; fooFor < 10; fooFor++) { // Iterated 10 times, fooFor 0->9 } // For Each Loop // foreach loop structure => foreach( in ) // The foreach loop loops over any object implementing IEnumerable or IEnumerable // All the collection types (Array, List, Dictionary...) in the .NET framework // implement one or both of these interfaces. // (The ToCharArray() could be removed, because a string also implements IEnumerable) foreach (char character in "Hello World".ToCharArray()) { // Iterated over all the characters in the string } // Switch Case // A switch works with byte, short, char, and int data types. // It also works with enumerated types (discussed in Enum Types), // the String class, and a few special classes that wrap // primitive types: Character, Byte, Short, and Integer. int month = 3; string monthString; switch (month) { case 1: monthString = "January"; break; case 2: monthString = "February"; break; case 3: monthString = "March"; break; // You can assign more than one case to an action // But you can't add an action without a break before another case // (if you want to do this, you would have to explicitly add a goto case x) case 6: case 7: case 8: monthString = "Summer time!!"; break; default: monthString = "Some other month"; break; } /////////////////////////////////////// // Converting Data Types And Typecasting /////////////////////////////////////// // Converting data // Convert String To Integer // this will throw a FormatException on failure int.Parse("123"); // returns an integer version of "123" // TryParse will default to the type's default value on failure // in this case 0 int tryInt; if (int.TryParse("123", out tryInt)) // Function is boolean Console.WriteLine(tryInt); // 123 // Convert Integer To String // The Convert class has a number of methods to facilitate conversions // String to int // Better bool result = int.TryParse(string, out var integer) int.Parse(string); // Not recommended Convert.ToString(123); // Int to string tryInt.ToString(); // Casting // Cast decimal 15 to an int // and then implicitly cast to long long x = (int) 15M; } /////////////////////////////////////// // CLASSES - see definitions at end of file /////////////////////////////////////// public static void Classes() { // See Declaration of objects at end of file // Use new to instantiate a class Bicycle trek = new Bicycle(); // Call object methods trek.SpeedUp(3); // You should always use setter and getter methods trek.Cadence = 100; // ToString is a convention to display the value of this Object. Console.WriteLine("trek info: " + trek.Info()); // Instantiate a new Penny Farthing PennyFarthing funbike = new PennyFarthing(1, 10); Console.WriteLine("funbike info: " + funbike.Info()); Console.Read(); } // End main method // Available in C# 9 and later, this is basically syntactic sugar for a class. Records are immutable*. public record ARecord(string Csharp); // CONSOLE ENTRY - A console application must have a main method as an entry point public static void Main(string[] args) { OtherInterestingFeatures(); } // // INTERESTING FEATURES // // DEFAULT METHOD SIGNATURES public // Visibility static // Allows for direct call on class without object int // Return Type, MethodSignatures( int maxCount, // First variable, expects an int int count = 0, // will default the value to 0 if not passed in int another = 3, params string[] otherParams // captures all other parameters passed to method ) { return -1; } // Methods can have the same name, as long as the signature is unique // A method that differs only in return type is not unique public static void MethodSignatures( ref int maxCount, // Pass by reference out int count) { // the argument passed in as 'count' will hold the value of 15 outside of this function count = 15; // out param must be assigned before control leaves the method } // GENERICS // The classes for TKey and TValue is specified by the user calling this function. // This method emulates Python's dict.setdefault() public static TValue SetDefault( IDictionary dictionary, TKey key, TValue defaultItem) { TValue result; if (!dictionary.TryGetValue(key, out result)) return dictionary[key] = defaultItem; return result; } // You can narrow down the objects that are passed in public static void IterateAndPrint(T toPrint) where T: IEnumerable { // We can iterate, since T is a IEnumerable foreach (var item in toPrint) // Item is an int Console.WriteLine(item.ToString()); } // YIELD // Usage of the "yield" keyword indicates that the method it appears in is an Iterator // (this means you can use it in a foreach loop) public static IEnumerable YieldCounter(int limit = 10) { for (var i = 0; i < limit; i++) yield return i; } // which you would call like this : public static void PrintYieldCounterToConsole() { foreach (var counter in YieldCounter()) Console.WriteLine(counter); } // you can use more than one "yield return" in a method public static IEnumerable ManyYieldCounter() { yield return 0; yield return 1; yield return 2; yield return 3; } // you can also use "yield break" to stop the Iterator // this method would only return half of the values from 0 to limit. public static IEnumerable YieldCounterWithBreak(int limit = 10) { for (var i = 0; i < limit; i++) { if (i > limit/2) yield break; yield return i; } } public static void OtherInterestingFeatures() { // OPTIONAL PARAMETERS MethodSignatures(3, 1, 3, "Some", "Extra", "Strings"); MethodSignatures(3, another: 3); // explicitly set a parameter, skipping optional ones // BY REF AND OUT PARAMETERS int maxCount = 0, count; // ref params must have value MethodSignatures(ref maxCount, out count); // EXTENSION METHODS int i = 3; i.Print(); // Defined below // NULLABLE TYPES - great for database interaction / return values // any value type (i.e. not a class) can be made nullable by suffixing a ? // ? = int? nullable = null; // short hand for Nullable Console.WriteLine("Nullable variable: " + nullable); bool hasValue = nullable.HasValue; // true if not null // ?? is syntactic sugar for specifying default value (coalesce) // in case variable is null int notNullable = nullable ?? 0; // 0 // ?. is an operator for null-propagation - a shorthand way of checking for null nullable?.Print(); // Use the Print() extension method if nullable isn't null // IMPLICITLY TYPED VARIABLES - you can let the compiler work out what the type is: var magic = "magic is a string, at compile time, so you still get type safety"; // magic = 9; will not work as magic is a string, not an int // GENERICS // var phonebook = new Dictionary() { {"Sarah", "212 555 5555"} // Add some entries to the phone book }; // Calling SETDEFAULT defined as a generic above Console.WriteLine(SetDefault(phonebook, "Shaun", "No Phone")); // No Phone // nb, you don't need to specify the TKey and TValue since they can be // derived implicitly Console.WriteLine(SetDefault(phonebook, "Sarah", "No Phone")); // 212 555 5555 // LAMBDA EXPRESSIONS - allow you to write code in line Func square = (x) => x * x; // Last T item is the return value Console.WriteLine(square(3)); // 9 // ERROR HANDLING - coping with an uncertain world try { var funBike = PennyFarthing.CreateWithGears(6); // will no longer execute because CreateWithGears throws an exception string some = ""; if (true) some = null; some.ToLower(); // throws a NullReferenceException } catch (NotSupportedException) { Console.WriteLine("Not so much fun now!"); } catch (Exception ex) // catch all other exceptions { throw new ApplicationException("It hit the fan", ex); // throw; // A rethrow that preserves the callstack } // catch { } // catch-all without capturing the Exception finally { // executes after try or catch } // DISPOSABLE RESOURCES MANAGEMENT - let you handle unmanaged resources easily. // Most of objects that access unmanaged resources (file handle, device contexts, etc.) // implement the IDisposable interface. The using statement takes care of // cleaning those IDisposable objects for you. using (StreamWriter writer = new StreamWriter("log.txt")) { writer.WriteLine("Nothing suspicious here"); // At the end of scope, resources will be released. // Even if an exception is thrown. } // PARALLEL FRAMEWORK // https://devblogs.microsoft.com/csharpfaq/parallel-programming-in-net-framework-4-getting-started/ var words = new List {"dog", "cat", "horse", "pony"}; Parallel.ForEach(words, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, word => { Console.WriteLine(word); } ); // Running this will produce different outputs // since each thread finishes at different times. // Some example outputs are: // cat dog horse pony // dog horse pony cat // DYNAMIC OBJECTS (great for working with other languages) dynamic student = new ExpandoObject(); student.FirstName = "First Name"; // No need to define class first! // You can even add methods (returns a string, and takes in a string) student.Introduce = new Func( (introduceTo) => string.Format("Hey {0}, this is {1}", student.FirstName, introduceTo)); Console.WriteLine(student.Introduce("Beth")); // IQUERYABLE - almost all collections implement this, which gives you a lot of // very useful Map / Filter / Reduce style methods var bikes = new List(); bikes.Sort(); // Sorts the array bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); // Sorts based on wheels var result = bikes .Where(b => b.Wheels > 3) // Filters - chainable (returns IQueryable of previous type) .Where(b => b.IsBroken && b.HasTassles) .Select(b => b.ToString()); // Map - we only this selects, so result is a IQueryable var sum = bikes.Sum(b => b.Wheels); // Reduce - sums all the wheels in the collection // Create a list of IMPLICIT objects based on some parameters of the bike var bikeSummaries = bikes.Select(b=>new { Name = b.Name, IsAwesome = !b.IsBroken && b.HasTassles }); // Hard to show here, but you get type ahead completion since the compiler can implicitly work // out the types above! foreach (var bikeSummary in bikeSummaries.Where(b => b.IsAwesome)) Console.WriteLine(bikeSummary.Name); // ASPARALLEL // And this is where things get wicked - combine linq and parallel operations var threeWheelers = bikes.AsParallel().Where(b => b.Wheels == 3).Select(b => b.Name); // this will happen in parallel! Threads will automagically be spun up and the // results divvied amongst them! Amazing for large datasets when you have lots of // cores // LINQ - maps a store to IQueryable objects, with delayed execution // e.g. LinqToSql - maps to a database, LinqToXml maps to an xml document var db = new BikeRepository(); // execution is delayed, which is great when querying a database var filter = db.Bikes.Where(b => b.HasTassles); // no query run if (42 > 6) // You can keep adding filters, even conditionally - great for "advanced search" functionality filter = filter.Where(b => b.IsBroken); // no query run var query = filter .OrderBy(b => b.Wheels) .ThenBy(b => b.Name) .Select(b => b.Name); // still no query run // Now the query runs, but opens a reader, so only populates as you iterate through foreach (string bike in query) Console.WriteLine(result); } } // End LearnCSharp class // You can include other classes in a .cs file public static class Extensions { // EXTENSION METHODS public static void Print(this object obj) { Console.WriteLine(obj.ToString()); } } // DELEGATES AND EVENTS public class DelegateTest { public static int count = 0; public static int Increment() { // increment count then return it return ++count; } // A delegate is a reference to a method. // To reference the Increment method, // first declare a delegate with the same signature, // i.e. takes no arguments and returns an int public delegate int IncrementDelegate(); // An event can also be used to trigger delegates // Create an event with the delegate type public static event IncrementDelegate MyEvent; static void Main(string[] args) { // Refer to the Increment method by instantiating the delegate // and passing the method itself in as an argument IncrementDelegate inc = new IncrementDelegate(Increment); Console.WriteLine(inc()); // => 1 // Delegates can be composed with the + operator IncrementDelegate composedInc = inc; composedInc += inc; composedInc += inc; // composedInc will run Increment 3 times Console.WriteLine(composedInc()); // => 4 // Subscribe to the event with the delegate MyEvent += new IncrementDelegate(Increment); MyEvent += new IncrementDelegate(Increment); // Trigger the event // ie. run all delegates subscribed to this event Console.WriteLine(MyEvent()); // => 6 } } // Class Declaration Syntax: // class { // //data fields, constructors, functions all inside. // //functions are called as methods in Java. // } public class Bicycle { // Bicycle's Fields/Variables public int Cadence // Public: Can be accessed from anywhere { get // get - define a method to retrieve the property { return _cadence; } set // set - define a method to set a property { _cadence = value; // Value is the value passed in to the setter } } private int _cadence; protected virtual int Gear // Protected: Accessible from the class and subclasses { get; // creates an auto property so you don't need a member field set; } internal int Wheels // Internal: Accessible from within the assembly { get; private set; // You can set modifiers on the get/set methods } int _speed; // Everything is private by default: Only accessible from within this class. // can also use keyword private public string Name { get; set; } // Properties also have a special syntax for when you want a readonly property // that simply returns the result of an expression public string LongName => Name + " " + _speed + " speed"; // Enum is a value type that consists of a set of named constants // It is really just mapping a name to a value (an int, unless specified otherwise). // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong. // An enum can't contain the same value twice. public enum BikeBrand { AIST, BMC, Electra = 42, //you can explicitly set a value to a name Gitane // 43 } // We defined this type inside a Bicycle class, so it is a nested type // Code outside of this class should reference this type as Bicycle.BikeBrand public BikeBrand Brand; // After declaring an enum type, we can declare the field of this type // Decorate an enum with the FlagsAttribute to indicate that multiple values can be switched on // Any class derived from Attribute can be used to decorate types, methods, parameters etc // Bitwise operators & and | can be used to perform and/or operations [Flags] public enum BikeAccessories { None = 0, Bell = 1, MudGuards = 2, // need to set the values manually! Racks = 4, Lights = 8, FullPackage = Bell | MudGuards | Racks | Lights } // Usage: aBike.Accessories.HasFlag(Bicycle.BikeAccessories.Bell) // Before .NET 4: (aBike.Accessories & Bicycle.BikeAccessories.Bell) == Bicycle.BikeAccessories.Bell public BikeAccessories Accessories { get; set; } // Static members belong to the type itself rather than specific object. // You can access them without a reference to any object: // Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated); public static int BicyclesCreated { get; set; } // readonly values are set at run time // they can only be assigned upon declaration or in a constructor readonly bool _hasCardsInSpokes = false; // read-only private // Constructors are a way of creating classes // This is a default constructor public Bicycle() { this.Gear = 1; // you can access members of the object with the keyword this Cadence = 50; // but you don't always need it _speed = 5; Name = "Bontrager"; Brand = BikeBrand.AIST; BicyclesCreated++; } // This is a specified constructor (it contains arguments) public Bicycle(int startCadence, int startSpeed, int startGear, string name, bool hasCardsInSpokes, BikeBrand brand) : base() // calls base first { Gear = startGear; Cadence = startCadence; _speed = startSpeed; Name = name; _hasCardsInSpokes = hasCardsInSpokes; Brand = brand; } // Constructors can be chained public Bicycle(int startCadence, int startSpeed, BikeBrand brand) : this(startCadence, startSpeed, 0, "big wheels", true, brand) { } // Function Syntax: // () // classes can implement getters and setters for their fields // or they can implement properties (this is the preferred way in C#) // Method parameters can have default values. // In this case, methods can be called with these parameters omitted public void SpeedUp(int increment = 1) { _speed += increment; } public void SlowDown(int decrement = 1) { _speed -= decrement; } // properties get/set values // when only data needs to be accessed, consider using properties. // properties may have either get or set, or both private bool _hasTassles; // private variable public bool HasTassles // public accessor { get { return _hasTassles; } set { _hasTassles = value; } } // You can also define an automatic property in one line // this syntax will create a backing field automatically. // You can set an access modifier on either the getter or the setter (or both) // to restrict its access: public bool IsBroken { get; private set; } // Properties can be auto-implemented public int FrameSize { get; // you are able to specify access modifiers for either get or set // this means only Bicycle class can call set on Framesize private set; } // It's also possible to define custom Indexers on objects. // Although this is not entirely useful in this example, you // could do bicycle[0] which returns "chris" to get the first passenger or // bicycle[1] = "lisa" to set the passenger. (of this apparent quattrocycle) private string[] passengers = { "chris", "phil", "darren", "regina" }; public string this[int i] { get { return passengers[i]; } set { passengers[i] = value; } } // Method to display the attribute values of this Object. public virtual string Info() { return "Gear: " + Gear + " Cadence: " + Cadence + " Speed: " + _speed + " Name: " + Name + " Cards in Spokes: " + (_hasCardsInSpokes ? "yes" : "no") + "\n------------------------------\n" ; } // Methods can also be static. It can be useful for helper methods public static bool DidWeCreateEnoughBicycles() { // Within a static method, we only can reference static class members return BicyclesCreated > 9000; } // If your class only needs static members, consider marking the class itself as static. } // end class Bicycle // PennyFarthing is a subclass of Bicycle class PennyFarthing : Bicycle { // (Penny Farthings are those bicycles with the big front wheel. // They have no gears.) // calling parent constructor public PennyFarthing(int startCadence, int startSpeed) : base(startCadence, startSpeed, 0, "PennyFarthing", true, BikeBrand.Electra) { } protected override int Gear { get { return 0; } set { throw new InvalidOperationException("You can't change gears on a PennyFarthing"); } } public static PennyFarthing CreateWithGears(int gears) { var penny = new PennyFarthing(1, 1); penny.Gear = gears; // Oops, can't do this! return penny; } public override string Info() { string result = "PennyFarthing bicycle "; result += base.ToString(); // Calling the base version of the method return result; } } // Interfaces only contain signatures of the members, without the implementation. interface IJumpable { void Jump(int meters); // all interface members are implicitly public } interface IBreakable { bool Broken { get; } // interfaces can contain properties as well as methods & events } // Classes can inherit only one other class, but can implement any amount of interfaces, // however the base class name must be the first in the list and all interfaces follow class MountainBike : Bicycle, IJumpable, IBreakable { int damage = 0; public void Jump(int meters) { damage += meters; } public bool Broken { get { return damage > 100; } } } /// /// Used to connect to DB for LinqToSql example. /// EntityFramework Code First is awesome (similar to Ruby's ActiveRecord, but bidirectional) /// https://docs.microsoft.com/ef/ef6/modeling/code-first/workflows/new-database /// public class BikeRepository : DbContext { public BikeRepository() : base() { } public DbSet Bikes { get; set; } } // Classes can be split across multiple .cs files // A1.cs public partial class A { public static void A1() { Console.WriteLine("Method A1 in class A"); } } // A2.cs public partial class A { public static void A2() { Console.WriteLine("Method A2 in class A"); } } // Program using the partial class "A" public class Program { static void Main() { A.A1(); A.A2(); } } // String interpolation by prefixing the string with $ // and wrapping the expression you want to interpolate with { braces } // You can also combine both interpolated and verbatim strings with $@ public class Rectangle { public int Length { get; set; } public int Width { get; set; } } class Program { static void Main(string[] args) { Rectangle rect = new Rectangle { Length = 5, Width = 3 }; Console.WriteLine($"The length is {rect.Length} and the width is {rect.Width}"); string username = "User"; Console.WriteLine($@"C:\Users\{username}\Desktop"); } } // New C# 6 features class GlassBall : IJumpable, IBreakable { // Autoproperty initializers public int Damage { get; private set; } = 0; // Autoproperty initializers on getter-only properties public string Name { get; } = "Glass ball"; // Getter-only autoproperty that is initialized in constructor public string GenieName { get; } public GlassBall(string genieName = null) { GenieName = genieName; } public void Jump(int meters) { if (meters < 0) // New nameof() expression; compiler will check that the identifier exists // nameof(x) == "x" // Prevents e.g. parameter names changing but not updated in error messages throw new ArgumentException("Cannot jump negative amount!", nameof(meters)); Damage += meters; } // Expression-bodied properties ... public bool Broken => Damage > 100; // ... and methods public override string ToString() // Interpolated string => $"{Name}. Damage taken: {Damage}"; public string SummonGenie() // Null-conditional operators // x?.y will return null immediately if x is null; y is not evaluated => GenieName?.ToUpper(); } static class MagicService { private static bool LogException(Exception ex) { // log exception somewhere return false; } public static bool CastSpell(string spell) { try { // Pretend we call API here throw new MagicServiceException("Spell failed", 42); // Spell succeeded return true; } // Only catch if Code is 42 i.e. spell failed catch(MagicServiceException ex) when (ex.Code == 42) { // Spell failed return false; } // Other exceptions, or MagicServiceException where Code is not 42 catch(Exception ex) when (LogException(ex)) { // Execution never reaches this block // The stack is not unwound } return false; // Note that catching a MagicServiceException and rethrowing if Code // is not 42 or 117 is different, as then the final catch-all block // will not catch the rethrown exception } } public class MagicServiceException : Exception { public int Code { get; } public MagicServiceException(string message, int code) : base(message) { Code = code; } } public static class PragmaWarning { // Obsolete attribute [Obsolete("Use NewMethod instead", false)] public static void ObsoleteMethod() { // obsolete code } public static void NewMethod() { // new code } public static void Main() { ObsoleteMethod(); // CS0618: 'ObsoleteMethod is obsolete: Use NewMethod instead' #pragma warning disable CS0618 ObsoleteMethod(); // no warning #pragma warning restore CS0618 ObsoleteMethod(); // CS0618: 'ObsoleteMethod is obsolete: Use NewMethod instead' } } } // End Namespace using System; // C# 6, static using using static System.Math; namespace Learning.More.CSharp { class StaticUsing { static void Main() { // Without a static using statement.. Console.WriteLine("The square root of 4 is {}.", Math.Sqrt(4)); // With one Console.WriteLine("The square root of 4 is {}.", Sqrt(4)); } } } // New C# 7 Feature // Install Microsoft.Net.Compilers Latest from Nuget // Install System.ValueTuple Latest from Nuget using System; namespace Csharp7 { // TUPLES, DECONSTRUCTION AND DISCARDS class TuplesTest { public (string, string) GetName() { // Fields in tuples are by default named Item1, Item2... var names1 = ("Peter", "Parker"); Console.WriteLine(names1.Item2); // => Parker // Fields can instead be explicitly named // Type 1 Declaration (string FirstName, string LastName) names2 = ("Peter", "Parker"); // Type 2 Declaration var names3 = (First:"Peter", Last:"Parker"); Console.WriteLine(names2.FirstName); // => Peter Console.WriteLine(names3.Last); // => Parker return names3; } public string GetLastName() { var fullName = GetName(); // Tuples can be deconstructed (string firstName, string lastName) = fullName; // Fields in a deconstructed tuple can be discarded by using _ var (_, last) = fullName; return last; } // Any type can be deconstructed in the same way by // specifying a Deconstruct method public int randomNumber = 4; public int anotherRandomNumber = 10; public void Deconstruct(out int randomNumber, out int anotherRandomNumber) { randomNumber = this.randomNumber; anotherRandomNumber = this.anotherRandomNumber; } static void Main(string[] args) { var tt = new TuplesTest(); (int num1, int num2) = tt; Console.WriteLine($"num1: {num1}, num2: {num2}"); // => num1: 4, num2: 10 Console.WriteLine(tt.GetLastName()); } } // PATTERN MATCHING class PatternMatchingTest { public static (string, int)? CreateLogMessage(object data) { switch(data) { // Additional filtering using when case System.Net.Http.HttpRequestException h when h.Message.Contains("404"): return (h.Message, 404); case System.Net.Http.HttpRequestException h when h.Message.Contains("400"): return (h.Message, 400); case Exception e: return (e.Message, 500); case string s: return (s, s.Contains("Error") ? 500 : 200); case null: return null; default: return (data.ToString(), 500); } } } // REFERENCE LOCALS // Allow you to return a reference to an object instead of just its value class RefLocalsTest { // note ref in return public static ref string FindItem(string[] arr, string el) { for(int i=0; i apple } } // LOCAL FUNCTIONS class LocalFunctionTest { private static int _id = 0; public int id; public LocalFunctionTest() { id = generateId(); // This local function can only be accessed in this scope int generateId() { return _id++; } } public static void AnotherMethod() { var lf1 = new LocalFunctionTest(); var lf2 = new LocalFunctionTest(); Console.WriteLine($"{lf1.id}, {lf2.id}"); // => 0, 1 int id = generateId(); // error CS0103: The name 'generateId' does not exist in the current context } } } ``` ## Topics Not Covered ✨ New, 👍 Old, 🎈 LTS, 🔥 Cross-platform, 🎁 Windows-only * Attributes * Asynchronous Programming * Web Development * ASP.NET Core ✨ * Desktop Development * Windows Presentation Foundation 👍 🎈 🎁 * Universal Windows Platform ✨ 🎁 * Uno Platform 🔥 ✨ * WinForms 👍 🎈 🎁 * Avalonia 🔥 ✨ * WinUI ✨ 🎁 * Cross-platform Development * Xamarin.Forms 👍 * MAUI ✨ ## Further Reading * [C# language reference](https://docs.microsoft.com/dotnet/csharp/language-reference/) * [Learn .NET](https://dotnet.microsoft.com/learn) * [C# Coding Conventions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions) * [DotNetPerls](http://www.dotnetperls.com) * [C# in Depth](http://manning.com/skeet2) * [Programming C# 5.0](http://shop.oreilly.com/product/0636920024064.do) * [LINQ Pocket Reference](http://shop.oreilly.com/product/9780596519254.do) * [Windows Forms Programming in C#](http://www.amazon.com/Windows-Forms-Programming-Chris-Sells/dp/0321116208) * [freeCodeCamp - C# Tutorial for Beginners](https://www.youtube.com/watch?v=GhQdlIFylQ8) ================================================ FILE: css.md ================================================ --- name: CSS contributors: - ["Mohammad Valipour", "https://github.com/mvalipour"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["Geoffrey Liu", "https://github.com/g-liu"] - ["Connor Shea", "https://github.com/connorshea"] - ["Deepanshu Utkarsh", "https://github.com/duci9y"] - ["Brett Taylor", "https://github.com/glutnix"] - ["Tyler Mumford", "https://tylermumford.com"] filename: learncss.css --- Web pages are built with HTML, which specifies the content of a page. CSS (Cascading Style Sheets) is a separate language which specifies a page's **appearance**. CSS code is made of static *rules*. Each rule takes one or more *selectors* and gives specific *values* to a number of visual *properties*. Those properties are then applied to the page elements indicated by the selectors. This guide has been written with CSS 2 in mind, which is extended by the new features of CSS 3. **NOTE:** Because CSS produces visual results, in order to learn it, you need to try everything in a CSS playground like [dabblet](http://dabblet.com/). The main focus of this article is on the syntax and some general tips. ## Syntax ```css /* comments appear inside slash-asterisk, just like this line! there are no "one-line comments"; this is the only comment style */ /* #################### ## SELECTORS #################### */ /* the selector is used to target an element on a page. */ selector { property: value; /* more properties...*/ } /* Here is an example element:
*/ /* You can target it using one of its CSS classes */ .class1 { } /* or both classes! */ .class1.class2 { } /* or its name */ div { } /* or its id */ #anID { } /* or using the fact that it has an attribute! */ [attr] { font-size:smaller; } /* or that the attribute has a specific value */ [attr='value'] { font-size:smaller; } /* starts with a value (CSS 3) */ [attr^='val'] { font-size:smaller; } /* or ends with a value (CSS 3) */ [attr$='ue'] { font-size:smaller; } /* or contains a value (CSS 3) */ [attr*='foo'] { } /* or contains a value in a space-separated list */ [otherAttr~='foo'] { } [otherAttr~='bar'] { } /* or contains a value in a dash-separated list, e.g., "-" (U+002D) */ [otherAttr|='en'] { font-size:smaller; } /* You can combine different selectors to create a more focused selector. Don't put spaces between them. */ div.some-class[attr$='ue'] { } /* You can select an element which is a child of another element */ div.some-parent > .class-name { } /* or a descendant of another element. Children are the direct descendants of their parent element, only one level down the tree. Descendants can be any level down the tree. */ div.some-parent .class-name { } /* Warning: the same selector without a space has another meaning. Can you guess what? */ div.some-parent.class-name { } /* You may also select an element based on its adjacent sibling */ .i-am-just-before + .this-element { } /* or any sibling preceding it */ .i-am-any-element-before ~ .this-element { } /* There are some selectors called pseudo classes that can be used to select an element only when it is in a particular state */ /* for example, when a link hasn't been visited */ selected:link { } /* or a link has been visited */ selector:visited { } /* or an element is in focus */ selected:focus { } /* or when the cursor hovers over an element */ selector:hover { } /* or when a link is clicked on */ selector:active { } /* These pseudo classes regarding links should always be written in the above order or the code might not work as expected */ /* Any element that is the first child of its parent */ selector:first-child {} /* any element that is the last child of its parent */ selector:last-child {} /* Select the nth child of selector parent (CSS 3) */ selector:nth-child(n) { } /* Just like pseudo classes, pseudo elements allow you to style certain parts of a document */ /* matches a virtual first child of the selected element */ selector::before {} /* matches a virtual last child of the selected element */ selector::after {} /* At appropriate places, an asterisk may be used as a wildcard to select every element */ * { } /* all elements */ .parent * { } /* all descendants */ .parent > * { } /* all children */ /* Group any number of selectors to define styles that affect all selectors in the group */ selector1, selector2 { } /* Select elements that do not have a certain state (CSS 3) */ /* Here, we select div with no id attribute. */ div:not([id]) { background-color: red; } /* #################### ## PROPERTIES #################### */ selector { /* Units of length can be absolute or relative. */ /* Relative units */ width: 50%; /* percentage of parent element width */ font-size: 2em; /* multiples of element's original font-size */ font-size: 2rem; /* or the root element's font-size */ font-size: 2vw; /* multiples of 1% of the viewport's width (CSS 3) */ font-size: 2vh; /* or its height */ font-size: 2vmin; /* whichever of a vh or a vw is smaller */ font-size: 2vmax; /* or greater */ /* Absolute units */ width: 200px; /* pixels */ font-size: 20pt; /* points */ width: 5cm; /* centimeters */ min-width: 50mm; /* millimeters */ max-width: 5in; /* inches */ /* Colors */ color: #F6E; /* short hex format */ color: #FF66EE; /* long hex format */ color: tomato; /* a named color */ color: rgb(255, 255, 255); /* as rgb values */ color: rgb(10%, 20%, 50%); /* as rgb percentages */ color: rgba(255, 0, 0, 0.3); /* as rgba values (CSS 3) Note: 0 <= a <= 1 */ color: transparent; /* equivalent to setting the alpha to 0 */ color: hsl(0, 100%, 50%); /* as hsl percentages (CSS 3) */ color: hsla(0, 100%, 50%, 0.3); /* as hsl percentages with alpha */ /* Borders */ border-width:5px; border-style:solid; border-color:red; /* similar to how background-color is set */ border: 5px solid red; /* this is a short hand approach for the same */ border-radius:20px; /* this is a CSS3 property */ /* Images as backgrounds of elements */ background-image: url(/img-path/img.jpg); /* quotes inside url() optional */ /* Fonts */ font-family: Arial; /* if the font family name has a space, it must be quoted */ font-family: "Courier New"; /* if the first one is not found, the browser uses the next, and so on */ font-family: "Courier New", Trebuchet, Arial, sans-serif; } /* Custom CSS properties using variables (CSS 3) */ :root { --main-bg-color: whitesmoke; } body { background-color: var(--main-bg-color) } /* Perform a calculation (CSS 3) */ body { width: calc(100vw - 100px) } /* Nest style rule inside another (CSS 3) */ .main { .bgred { /* same as: .main .bgred { } */ background: red; } & .bggreen { /* same as: .main .bggreen { } */ background: green; } &.bgblue { /* (without space) same as: .main.bgblue { } */ background: blue; } } /* Design responsive layout using flexbox (CSS 3) */ .container { display: flex; flex-direction: row; /* in which direction stack the flex items */ flex-wrap: wrap; /* whether or not flex items should wrap */ justify-content: center; /* how to align flex items horizontally */ align-items: center; /* how to align flex items vertically */ } ``` ## Usage Save a CSS stylesheet with the extension `.css`. ```html
``` ## Precedence or Cascade An element may be targeted by multiple selectors and may have a property set on it in more than once. In these cases, one of the rules takes precedence over others. Rules with a more specific selector take precedence over a less specific one, and a rule occurring later in the stylesheet overwrites a previous one (which also means that if two different linked stylesheets contain rules for an element and if the rules are of the same specificity, then order of linking would take precedence and the sheet linked latest would govern styling) . This process is called cascading, hence the name Cascading Style Sheets. Given the following CSS: ```css /* A */ p.class1[attr='value'] /* B */ p.class1 { } /* C */ p.class2 { } /* D */ p { } /* E */ p { property: value !important; } ``` and the following markup: ```html

``` The precedence of style is as follows. Remember, the precedence is for each **property**, not for the entire block. * `E` has the highest precedence because of the keyword `!important`. It is recommended that you avoid its usage. * `F` is next, because it is an inline style. * `A` is next, because it is more "specific" than anything else. It has 3 specifiers: The name of the element `p`, its class `class1`, an attribute `attr='value'`. * `C` is next, even though it has the same specificity as `B`. This is because it appears after `B`. * `B` is next. * `D` is the last one. ## Media Queries CSS Media Queries are a feature in CSS 3 which allows you to specify when certain CSS rules should be applied, such as when printed, or when on a screen with certain dimensions or pixel density. They do not add to the selector's specificity. ```css /* A rule that will be used on all devices */ h1 { font-size: 2em; color: white; background-color: black; } /* change the h1 to use less ink on a printer */ @media print { h1 { color: black; background-color: white; } } /* make the font bigger when shown on a screen at least 480px wide */ @media screen and (min-width: 480px) { h1 { font-size: 3em; font-weight: normal; } } ``` Media queries can include these features: `width`, `height`, `device-width`, `device-height`, `orientation`, `aspect-ratio`, `device-aspect-ratio`, `color`, `color-index`, `monochrome`, `resolution`, `scan`, `grid`. Most of these features can be prefixed with `min-` or `max-`. The `resolution` feature is not supported by older devices, instead use `device-pixel-ratio`. Many smartphones and tablets will attempt to render the page as if it were on a desktop unless you provide a `viewport` meta-tag. ```html ``` ## Compatibility Most of the features in CSS 2 (and many in CSS 3) are available across all browsers and devices. But it's always good practice to check before using a new feature. ## Resources * [CanIUse](http://caniuse.com) (Detailed compatibility info) * [Dabblet](http://dabblet.com/) (CSS playground) * [Mozilla Developer Network's CSS documentation](https://developer.mozilla.org/en-US/docs/Web/CSS) (Tutorials and reference) * [Codrops' CSS Reference](http://tympanus.net/codrops/css_reference/) (Reference) * [DevTips' CSS Basics](https://www.youtube.com/playlist?list=PLqGj3iMvMa4IOmy04kDxh_hqODMqoeeCy) (Tutorials) ## Further Reading * [Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade](http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/) * [Selecting elements using attributes](https://css-tricks.com/almanac/selectors/a/attribute/) * [QuirksMode CSS](http://www.quirksmode.org/css/) * [Z-Index - The stacking context](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context) * [SASS](http://sass-lang.com/) and [LESS](http://lesscss.org/) for CSS pre-processing * [CSS-Tricks](https://css-tricks.com) ================================================ FILE: csv.md ================================================ --- name: CSV contributors: - [Timon Erhart, 'https://github.com/turbotimon/'] --- CSV (Comma-Separated Values) is a lightweight file format used to store tabular data in plain text, designed for easy data exchange between programs, particularly spreadsheets and databases. Its simplicity and human readability have made it a cornerstone of data interoperability. It is often used for moving data between programs with incompatible or proprietary formats. While RFC 4180 provides a standard for the format, in practice, the term "CSV" is often used more broadly to refer to any text file that: - Can be interpreted as tabular data - Uses a delimiter to separate fields (columns) - Uses line breaks to separate records (rows) - Optionally includes a header in the first row ```csv Name, Age, DateOfBirth Alice, 30, 1993-05-14 Bob, 25, 1998-11-02 Charlie, 35, 1988-03-21 ``` ## Delimiters for Rows and Columns Rows are typically separated by line breaks (`\n` or `\r\n`), while columns (fields) are separated by a specific delimiter. Although commas are the most common delimiter for fields, other characters, such as semicolons (`;`), are commonly used in regions where commas are decimal separators (e.g., Germany). Tabs (`\t`) are also used as delimiters in some cases, with such files often referred to as "TSV" (Tab-Separated Values). Example using semicolons as delimiter and comma for decimal separator: ```csv Name; Age; Grade Alice; 30; 50,50 Bob; 25; 45,75 Charlie; 35; 60,00 ``` ## Data Types CSV files do not inherently define data types. Numbers and dates are stored as plain text, and their interpretation depends on the software importing the file. Typically, data is interpreted as follows: ```csv Data, Comment 100, Interpreted as a number (integer) 100.00, Interpreted as a number (floating-point) 2024-12-03, Interpreted as a date or a string (depending on the parser) Hello World, Interpreted as text (string) "1234", Interpreted as text instead of a number ``` ## Quoting Strings and Special Characters Quoting strings is only required if the string contains the delimiter, special characters, or otherwise could be interpreted as a number. However, it is often considered good practice to quote all strings to enhance readability and robustness. ```csv Quoting strings examples, Unquoted string, "Optionally quoted string (good practice)", "If it contains the delimiter, it needs to be quoted", "Also, if it contains special characters like \n newlines or \t tabs", "The quoting "" character itself typically is escaped by doubling the quote ("")", "or in some systems with a backslash \" (like other escapes)", ``` However, make sure that for one document, the quoting method is consistent. For example, the last two examples of quoting with either "" or \" would not be consistent and could cause problems. ## Encoding Different encodings are used. Most modern CSV files use UTF-8 encoding, but older systems might use others like ASCII or ISO-8859. If the file is transferred or shared between different systems, it is a good practice to explicitly define the encoding used, to avoid issues with character misinterpretation. ## More Resources + [Wikipedia](https://en.wikipedia.org/wiki/Comma-separated_values) + [RFC 4180](https://datatracker.ietf.org/doc/html/rfc4180) ================================================ FILE: cue.md ================================================ --- name: CUE filename: learncue.cue contributors: - ["Daniel Cox", "https://github.com/danielpcox"] - ["Coleman McFarland", "https://github.com/dontlaugh"] --- CUE is an expressive (but not Turing-complete) JSON superset, exportable to JSON or YAML. It supports optional types and many other conveniences for working with large configuration sets. The unification engine has roots in logic programming, and as such it provides a ready solution to modern configuration management problems. When CUE is exported to JSON, values from every processed file are unified into one giant object. Consider these two files: ```yaml //name.cue name: "Daniel" ``` ```yaml //disposition.cue disposition: "oblivious" ``` Now we can unify and export to JSON: ```bash % cue export name.cue disposition.cue { "name": "Daniel", "disposition": "oblivious" } ``` Or YAML: ```bash % cue export --out yaml name.cue disposition.cue name: Daniel disposition: oblivious ``` Notice the C-style comments are not in the output. Also notice that the keys in CUE syntax did not require quotes. Some special characters do require quotes: ```yaml works_fine: true "needs-quotes": true ``` Unification doesn't just unify across files, it is also a *global merge* of all types and values. The following fails, because the *types* are different. ```yaml //string_value.cue foo: "baz" ``` ```yaml //integer_value.cue foo: 100 ``` ```bash % cue export string_value.cue integer_value.cue foo: conflicting values "baz" and 100 (mismatched types string and int): integer_value.cue:1:6 string_value.cue:1:6 ``` But even if we quote the integer, it still fails, because the *values* conflict and there is no way to unify everything into a top-level object. ```yaml //string_value.cue foo: "baz" ``` ```yaml //integer_value.cue foo: "100" // a string now ``` ```bash % cue export string_value.cue integer_value.cue foo: conflicting values "100" and "baz": integer_value.cue:1:6 string_value.cue:1:6 ``` Types in CUE *are* values; special ones that the unification engine knows have certain behavior relative to other values. During unification it requires that values match the specified types, and when concrete values are required, you will get an error if there's only a type. So this is fine: ```yaml street: "1 Infinite Loop" street: string ``` While `cue export` produces YAML or JSON, `cue eval` produces CUE. This is useful for converting YAML or JSON to CUE, or for inspecting the unified output in CUE itself. It's fine to be missing concrete values in CUE (though it prefers concrete values when emitting CUE when both are available and match), ```yaml //type-only.cue amount: float ``` ```bash % cue eval type-only.cue amount: float ``` but you *need* concrete values if you want to export (or if you tell `eval` to require them with `-c`): ```bash % cue export type-only.cue amount: incomplete value float ``` Give it a value that unifies with the type, and all is well. ```yaml //concrete-value.cue amount: 3.14 ``` ```bash % cue export type-only.cue concrete-value.cue { "amount": 3.14 } ``` The method of unifying concrete values with types that share a common syntax is very powerful, and much more compact than, e.g., JSON Schema. This way, schema, defaults, and data are all expressible in CUE. Default values may be supplied with a type using an asterisk: ```yaml // default-port.cue port: int | *8080 ``` ```bash % cue eval default-port.cue port: 8080 ``` Enum-style options ("disjunctions" in CUE) may be specified with an `|` separator: ```yaml //severity-enum.cue severity: "high" | "medium" | "low" severity: "unknown" ``` ```bash % cue eval severity-enum.cue severity: 3 errors in empty disjunction: severity: conflicting values "high" and "unknown": ./severity-enum.cue:1:11 ./severity-enum.cue:1:48 severity: conflicting values "low" and "unknown": ./severity-enum.cue:1:31 ./severity-enum.cue:1:48 severity: conflicting values "medium" and "unknown": ./severity-enum.cue:1:20 ./severity-enum.cue:1:48 ``` You can even have disjunctions of structs (not shown, but it works like you'd expect). CUE has "definitions", and you can use them like you would variable declarations in other languages. They are also for defining struct types. You can apply a struct of type definitions to some concrete value(s) with `&`. Also notice you can say "a list with type #Whatever" using `[...#Whatever]`. ```yaml // definitions.cue #DashboardPort: 1337 configs: { host: "localhost" port: #DashboardPort } #Address: { street: string city: string zip?: int // ? makes zip optional } some_address: #Address & { street: "1 Rocket Rd" city: "Hawthorne" } more_addresses: [...#Address] & [ {street: "1600 Amphitheatre Parkway", city: "Mountain View", zip: "94043"}, {street: "1 Hacker Way", city: "Menlo Park"} ] ``` ```bash % cue export --out yaml definitions.cue configs: host: localhost port: 1337 some_address: street: 1 Rocket Rd city: Hawthorne more_addresses: - street: 1600 Amphitheatre Parkway city: Mountain View zip: "94043" - street: 1 Hacker Way city: Menlo Park ``` CUE supports more complex values and validation: ```yaml #Country: { name: =~"^\\p{Lu}" // Must start with an upper-case letter pop: >800 & <9_000_000_000 // More than 800, fewer than 9 billion } vatican_city: #Country & { name: "Vatican City" pop: 825 } ``` CUE may save you quite a bit of time with all the sugar it provides on top of mere JSON. Here we're defining, "modifying", and validating a nested structure in three lines: (Notice the `[]` syntax used around `string` to signal to the engine that `string` is a constraint, not a string in this case.) ```yaml //paths.cue // path-value pairs outer: middle1: inner: 3 outer: middle2: inner: 7 // collection-constraint pair outer: [string]: inner: int ``` ```bash % cue export paths.cue { "outer": { "middle1": { "inner": 3 }, "middle2": { "inner": 7 } } } ``` In the same vein, CUE supports "templates", which are a bit like functions of a single argument. Here `Name` is bound to each string key immediately under `container` while the struct underneath *that* is evaluated. ```yaml //templates.cue container: [Name=_]: { name: Name replicas: uint | *1 command: string } container: sidecar: command: "envoy" container: service: { command: "fibonacci" replicas: 2 } ``` ```bash % cue eval templates.cue container: { sidecar: { name: "sidecar" replicas: 1 command: "envoy" } service: { name: "service" command: "fibonacci" replicas: 2 } } ``` And while we're talking about references like that, CUE supports scoped references. ```yaml //scopes-and-references.cue v: "top-level v" b: v // a reference a: { b: v // matches the top-level v } let V = v a: { v: "a's inner v" c: v // matches the inner v d: V // matches the top-level v now shadowed by a.v } av: a.v // matches a's v ``` ```bash % cue eval --out yaml scopes-and-references.cue ``` ```yaml v: top-level v b: top-level v a: b: top-level v v: a's inner v c: a's inner v d: top-level v av: a's inner v ``` I changed the order of the keys in the output for clarity. Order doesn't actually matter, and notice that duplicate keys at a given level are *all* unified. You can hide fields be prefixing them with `_` (quote the field if you need a `_` prefix in an emitted field) ```yaml //hiddens.cue "_foo": 2 _foo: 3 foo: 4 _#foo: 5 #foo : 6 ``` ```bash % cue eval hiddens.cue "_foo": 2 foo: 4 #foo: 6 % cue export hiddens.cue { "_foo": 2, "foo": 4 } ``` Notice the difference between `eval` and `export` with respect to definitions. If you want to hide a definition in CUE, you can prefix *that* with `_`. Interpolation of values and fields: ```yaml //interpolation.cue #expense: 90 #revenue: 100 message: "Your profit was $\( #revenue - #expense)" cat: { type: "Cuddly" "is\(type)": true } ``` ```bash % cue export interpolation.cue { "message": "Your profit was $10", "cat": { "type": "Cuddly", "isCuddly": true } } ``` Operators, list comprehensions, conditionals, imports...: ```yaml //getting-out-of-hand-now.cue import "strings" // we'll come back to this // operators are nice g: 5 / 3 // CUE can do math h: 3 * "blah" // and Python-like string repetition i: 3 * [1, 2, 3] // with lists too j: 8 < 10 // and supports boolean ops // conditionals are also nice price: number // Require a justification if price is too high if price > 100 { justification: string } price: 200 justification: "impulse buy" // list comprehensions are powerful and compact #items: [ 1, 2, 3, 4, 5, 6, 7, 8, 9] comp: [ for x in #items if x rem 2 == 0 {x*x}] // and... well you can do this too #a: [ "Apple", "Google", "SpaceX"] for k, v in #a { "\( strings.ToLower(v) )": { pos: k + 1 name: v nameLen: len(v) } } ``` ```bash % cue export getting-out-of-hand-now.cue ``` ```json { "g": 1.66666666666666666666667, "h": "blahblahblah", "i": [1, 2, 3, 1, 2, 3, 1, 2, 3], "j": true, "apple": { "pos": 1, "name": "Apple", "nameLen": 5 }, "google": { "pos": 2, "name": "Google", "nameLen": 6 }, "price": 200, "justification": "impulse buy", "comp": [ 4, 16, 36, 64 ], "spacex": { "pos": 3, "name": "SpaceX", "nameLen": 6 } } ``` At this point it's worth mentioning that CUE may not be Turing-complete, but it *is* powerful enough for you to shoot yourself in the foot, so do try to keep it clear. It's easy to go off the deep end and make your config *harder* to work with if you're not careful. Make use of those comments, at least, and/or... To that end, CUE supports packages and modules. CUE files are standalone by default, but if you put a package clause at the top, you're saying that file is unifiable with other files "in" the same package. ```yaml //a.cue package config foo: 100 bar: int ``` ```yaml //b.cue package config bar: 200 ``` If you create these two files in a new directory and run `cue eval` (no arguments), it will unify them like you'd expect. It searches the current directory for .cue files, and if they all have the same package, they will be unified. Packages are more clear in the context of "modules". Modules are the *largest* unit of organization. Basically every time you have a project that spans multiple files, you should create a module and name it with something that looks like the domain and path of a URL, e.g., `example.com/something`. When you import anything from this module, even from *within* the module, you must do so using the fully-qualified module path which will be prefixed with this module name. You can create a new module like so: ```bash mkdir mymodule && cd mymodule cue mod init example.com/mymodule ``` This creates a `cue.mod/` subdirectory within that `mymodule` directory, and `cue.mod/` contains the following file and subdirectories: - `module.cue` (which defines your module name, in this case with `module: "example.com/mymodule"`) - pkg/ - gen/ - usr/ For a different perspective on this and details about what's in there, see [cuelang.org/docs/concepts/packages/](https://cuelang.org/docs/concepts/packages/). For my purposes here, I'll say you don't need to think about the contents of this directory *at all*, except that your module name will be the prefix for all imports within your module. Where will your module file hierarchy go? All files and directories for your module are rooted in `mymodule/`, the directory that also contains `cue.mod/`. If you want to import a package, you'll prefix it with `example.com/mymodule`, followed by a relative path rooted in `mymodule/`. To make it concrete, consider the following: ``` mymodule ├── config │ ├── a.cue │ └── b.cue ├── cue.mod │ ├── module.cue │ ├── pkg │ └── usr └── main.cue ``` `cue.mod/` and the files underneath it were created by `cue mod init example.com/mymodule`. I then created the `config/` subdirectory with `a.cue` and `b.cue` inside. Then I created `main.cue` to act as my top-level file to rule them all. Running `eval` (no arguments) checks to see if there's only one package in all .cue files in the current directory, and if so, it unifies them and outputs the result. In this case, there's only main.cue with package `main` (nothing special about "main" there, it just seemed appropriate), so that's the one. ```bash % cue eval configuredBar: 200 ``` The contents of `main.cue` is: ```yaml //main.cue package main import "example.com/mymodule/config" configuredBar: config.bar ``` `config/a.cue` and `config/b.cue` are files from earlier, except now they've both got `package config` at the top: ```yaml //a.cue package config foo: 100 bar: int ``` ```yaml //b.cue package config bar: 200 ``` So there you go. If you want to verify that it's actually unifying both files under `config/`, you can change `bar: int` to `bar: string` in `a.cue` and re-run `cue eval` to get a nice type error: ``` cue eval 2022-01-06 17:51:24 configuredBar: conflicting values string and 200 (mismatched types string and int): ./config/a.cue:4:6 ./config/b.cue:3:6 ./main.cue:5:16 ``` That's it for now. I understand there are more package management features coming in the future and the design decisions around `cue.mod` are looking ahead to that. Finally, CUE has built-in modules with powerful functionality. We saw one of these earlier, when we imported "strings" and used `strings.ToLower`. Imports without fully-qualified module names are assumed to be built-ins. The full list and documentation for each is here: [pkg.go.dev/cuelang.org/go/pkg](https://pkg.go.dev/cuelang.org/go/pkg) This has been a condensation of the official docs and tutorials, so go give the source material some love: [cuelang.org/docs/tutorials/](https://cuelang.org/docs/tutorials/) ================================================ FILE: cypher.md ================================================ --- name: Cypher filename: LearnCypher.cql contributors: - ["Théo Gauchoux", "https://github.com/TheoGauchoux"] --- Cypher is Neo4j's query language for easily manipulating graphs. It reuses syntax from SQL and mixes it with kind of an ASCII-art to represent graphs. This tutorial assumes that you already know graph concepts like nodes and relationships. ## Nodes represent a record in a graph `()` is an empty *node*, to indicate that there is a *node*, but it's not relevant for the query. `(n)` is a *node* referred by the variable `n`, reusable in the query. It begins with lowercase and uses camelCase. `(p:Person)` - you can add a *label* to your node, here `Person`. It's like a type/class/category. It begins with uppercase and uses camelCase. `(p:Person:Manager)` - a node can have many *labels*. `(p:Person {name : 'Théo Gauchoux', age : 22})` - a node can have some *properties*, here `name` and `age`. It begins with lowercase and uses camelCase. The types allowed in properties: - Numeric - Boolean - String - List of previous primitive types *Warning: there's no datetime properties in Cypher! You can use a String with a specific pattern or a Numeric from a specific date.* `p.name` - you can access a property with the dot style. ## Relationships (or Edges) connect two nodes `[:KNOWS]` is a *relationship* with the *label* `KNOWS`. It's a *label* as the node's label. It uses UPPER\_SNAKE\_CASE. `[k:KNOWS]` - the same *relationship*, referred by the variable `k`, reusable in the query, but it's not necessary. `[k:KNOWS {since:2017}]` - the same *relationship*, with *properties* (like *node*), here `since`. `[k:KNOWS*..4]` is structural information to use in a *path* (seen later). Here, `\*..4` says "Match the pattern, with the relationship `k` which can be repeated between 1 and 4 times. ## Paths - the way to mix nodes and relationships. `(a:Person)-[:KNOWS]-(b:Person)` - a path describing that `a` and `b` know each other. `(a:Person)-[:MANAGES]->(b:Person)` - a path can be directed. This path describes that `a` is the manager of `b`. `(a:Person)-[:KNOWS]-(b:Person)-[:KNOWS]-(c:Person)` - you can chain multiple relationships. This path describes the friend of a friend. `(a:Person)-[:MANAGES]->(b:Person)-[:MANAGES]->(c:Person)` - a chain can also be directed. This path describes that `a` is the boss of `b` and the big boss of `c`. Commonly used patterns (from Neo4j documentation): ```cypher // Friend-of-a-friend (user)-[:KNOWS]-(friend)-[:KNOWS]-(foaf) // Shortest path path = shortestPath( (user)-[:KNOWS*..5]-(other) ) // Collaborative filtering (user)-[:PURCHASED]->(product)<-[:PURCHASED]-()-[:PURCHASED]->(otherProduct) // Tree navigation (root)<-[:PARENT*]-(leaf:Category)-[:ITEM]->(data:Product) ``` ## Create queries Create a new node ```cypher CREATE (a:Person {name:"Théo Gauchoux"}) RETURN a ``` *`RETURN` allows to have a result after the query. It can be multiple, as `RETURN a, b`.* Create a new relationship (with 2 new nodes) ```cypher CREATE (a:Person)-[k:KNOWS]-(b:Person) RETURN a,k,b ``` ## Match queries Match all nodes ```cypher MATCH (n) RETURN n ``` Match nodes by label ```cypher MATCH (a:Person) RETURN a ``` Match nodes by label and property ```cypher MATCH (a:Person {name:"Théo Gauchoux"}) RETURN a ``` Match nodes according to relationships (undirected) ```cypher MATCH (a)-[:KNOWS]-(b) RETURN a,b ``` Match nodes according to relationships (directed) ```cypher MATCH (a)-[:MANAGES]->(b) RETURN a,b ``` Match nodes with a `WHERE` clause ```cypher MATCH (p:Person {name:"Théo Gauchoux"})-[s:LIVES_IN]->(city:City) WHERE s.since = 2015 RETURN p,state ``` You can use `MATCH WHERE` clause with `CREATE` clause ```cypher MATCH (a), (b) WHERE a.name = "Jacquie" AND b.name = "Michel" CREATE (a)-[:KNOWS]-(b) ``` ## Update queries Update a specific property of a node ```cypher MATCH (p:Person) WHERE p.name = "Théo Gauchoux" SET p.age = 23 ``` Replace all properties of a node ```cypher MATCH (p:Person) WHERE p.name = "Théo Gauchoux" SET p = {name: "Michel", age: 23} ``` Add new property to a node ```cypher MATCH (p:Person) WHERE p.name = "Théo Gauchoux" SET p += {studies: "IT Engineering"} ``` Add a label to a node ```cypher MATCH (p:Person) WHERE p.name = "Théo Gauchoux" SET p:Internship ``` ## Delete queries Delete a specific node (linked relationships must be deleted before) ```cypher MATCH (p:Person)-[relationship]-() WHERE p.name = "Théo Gauchoux" DELETE relationship, p ``` Remove a property in a specific node ```cypher MATCH (p:Person) WHERE p.name = "Théo Gauchoux" REMOVE p.age ``` *Pay attention to the `REMOVE` keyword, it's not `DELETE`!* Remove a label from a specific node ```cypher MATCH (p:Person) WHERE p.name = "Théo Gauchoux" DELETE p:Person ``` Delete entire database ```cypher MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n, r ``` *Seriously, it's the `rm -rf /` of Cypher!* ## Other useful clauses `PROFILE` - before a query, show its execution plan. `COUNT(e)` - count entities (nodes or relationships) matching `e`. `LIMIT x` - limit the result to the first `x` results. ## Special hints - Cypher only has single-line comments, using double-slashes: `// comment` - You can execute a Cypher script stored in a .cql file directly in Neo4j (it's an import). However, you can't have multiple statements in this file (separated by `;`). - Use the Neo4j shell to write Cypher, it's really awesome. - Cypher will be the standard query language for all graph databases (known as [openCypher](https://opencypher.org/)). Read more [here](https://neo4j.com/developer/cypher-query-language/). ================================================ FILE: d.md ================================================ --- name: D filename: learnd.d contributors: - ["Nick Papanastasiou", "www.nickpapanastasiou.github.io"] --- ```d // You know what's coming... module hello; import std.stdio; // args is optional void main(string[] args) { writeln("Hello, World!"); } ``` If you're like me and spend way too much time on the internet, odds are you've heard about [D](http://dlang.org/). The D programming language is a modern, general-purpose, multi-paradigm language with support for everything from low-level features to expressive high-level abstractions. D is actively developed by a large group of super-smart people and is spearheaded by [Walter Bright](https://en.wikipedia.org/wiki/Walter_Bright) and [Andrei Alexandrescu](https://en.wikipedia.org/wiki/Andrei_Alexandrescu). With all that out of the way, let's look at some examples! ```d import std.stdio; void main() { // Conditionals and loops work as expected. for(int i = 0; i < 10000; i++) { writeln(i); } // 'auto' can be used for inferring types. auto n = 1; // Numeric literals can use '_' as a digit separator for clarity. while(n < 10_000) { n += n; } do { n -= (n / 2); } while(n > 0); // For and while are nice, but in D-land we prefer 'foreach' loops. // The '..' creates a continuous range, including the first value // but excluding the last. foreach(n; 1..1_000_000) { if(n % 2 == 0) writeln(n); } // There's also 'foreach_reverse' when you want to loop backwards. foreach_reverse(n; 1..int.max) { if(n % 2 == 1) { writeln(n); } else { writeln("No!"); } } } ``` We can define new types with `struct`, `class`, `union`, and `enum`. Structs and unions are passed to functions by value (i.e. copied) and classes are passed by reference. Furthermore, we can use templates to parameterize all of these on both types and values! ```d // Here, 'T' is a type parameter. Think '' from C++/C#/Java. struct LinkedList(T) { T data = null; // Use '!' to instantiate a parameterized type. Again, think ''. LinkedList!(T)* next; } class BinTree(T) { T data = null; // If there is only one template parameter, we can omit the parentheses. BinTree!T left; BinTree!T right; } enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, } // Use alias to create abbreviations for types. alias IntList = LinkedList!int; alias NumTree = BinTree!double; // We can create function templates as well! T max(T)(T a, T b) { if(a < b) return b; return a; } // Use the ref keyword to ensure pass by reference. That is, even if 'a' and 'b' // are value types, they will always be passed by reference to 'swap()'. void swap(T)(ref T a, ref T b) { auto temp = a; a = b; b = temp; } // With templates, we can also parameterize on values, not just types. class Matrix(uint m, uint n, T = int) { T[m] rows; T[n] columns; } auto mat = new Matrix!(3, 3); // We've defaulted type 'T' to 'int'. ``` Speaking of classes, let's talk about properties for a second. A property is roughly a function that may act like an lvalue, so we can have the syntax of POD structures (`structure.x = 7`) with the semantics of getter and setter methods (`object.setX(7)`)! ```d // Consider a class parameterized on types 'T' & 'U'. class MyClass(T, U) { T _data; U _other; } // And "getter" and "setter" methods like so: class MyClass(T, U) { T _data; U _other; // Constructors are always named 'this'. this(T t, U u) { // This will call the setter methods below. data = t; other = u; } // getters @property T data() { return _data; } @property U other() { return _other; } // setters @property void data(T t) { _data = t; } @property void other(U u) { _other = u; } } // And we use them in this manner: void main() { auto mc = new MyClass!(int, string)(7, "seven"); // Import the 'stdio' module from the standard library for writing to // console (imports can be local to a scope). import std.stdio; // Call the getters to fetch the values. writefln("Earlier: data = %d, str = %s", mc.data, mc.other); // Call the setters to assign new values. mc.data = 8; mc.other = "eight"; // Call the getters again to fetch the new values. writefln("Later: data = %d, str = %s", mc.data, mc.other); } ``` With properties, we can add any amount of logic to our getter and setter methods, and keep the clean syntax of accessing members directly! Other object-oriented goodies at our disposal include interfaces, abstract classes, and overriding methods. D does inheritance just like Java: Extend one class, implement as many interfaces as you please. We've seen D's OOP facilities, but let's switch gears. D offers functional programming with first-class functions, `pure` functions, and immutable data. In addition, all of your favorite functional algorithms (map, filter, reduce and friends) can be found in the wonderful `std.algorithm` module! ```d import std.algorithm : map, filter, reduce; import std.range : iota; // builds an end-exclusive range import std.stdio; void main() { // We want to print the sum of a list of squares of even ints // from 1 to 100. Easy! // Just pass lambda expressions as template parameters! // You can pass any function you like, but lambdas are convenient here. auto num = iota(1, 101).filter!(x => x % 2 == 0) .map!(y => y ^^ 2) .reduce!((a, b) => a + b); writeln(num); } ``` Notice how we got to build a nice Haskellian pipeline to compute num? That's thanks to a D innovation know as Uniform Function Call Syntax (UFCS). With UFCS, we can choose whether to write a function call as a method or free function call! Walter wrote a nice article on this [here.](http://www.drdobbs.com/cpp/uniform-function-call-syntax/232700394) In short, you can call functions whose first parameter is of some type A on any expression of type A as a method. I like parallelism. Anyone else like parallelism? Sure you do. Let's do some! ```d // Let's say we want to populate a large array with the square root of all // consecutive integers starting from 1 (up until the size of the array), and we // want to do this concurrently taking advantage of as many cores as we have // available. import std.stdio; import std.parallelism : parallel; import std.math : sqrt; void main() { // Create your large array auto arr = new double[1_000_000]; // Use an index, access every array element by reference (because we're // going to change each element) and just call parallel on the array! foreach(i, ref elem; parallel(arr)) { elem = sqrt(i + 1.0); } } ``` ================================================ FILE: da/javascript.md ================================================ --- contributors: - ["Leigh Brenecki", "https://leigh.net.au"] - ["Ariel Krakowski", "http://www.learneroo.com"] translators: - ["Daniel Niemann Hjermitslev", "https://github.com/dnh33"] --- JavaScript-vejledning på dansk. JavaScript blev skabt af Brendan Eich i 1995, mens han arbejdede hos Netscape. Hans oprindelige intention var at skabe et simpelt sprog til websteder, som skulle supplere Java til mere komplekse applikationer. På grund af den tætte integration med websteder og standardunderstøttelse i moderne browsere er det blevet meget mere almindeligt til frontend-udvikling end Java. JavaScript er dog ikke kun begrænset til webbrowsere: Node.js, et projekt der giver et uafhængigt kørselsmiljø til Googles Chrome V8-motor, bliver mere og mere populært. ```javascript // Enkeltlinje kommentarer starter med to skråstreger. /* Flerlinje kommentarer starter med skråstreg-stjerne, og slutter med stjerne-skråstreg */ // Udsagn kan afsluttes med ; (semikolon) gørNoget(); // ... men semikoloner behøver ikke at være der, da semikoloner automatisk indsættes // hvor der er en ny linje, undtagen i visse tilfælde. gørNoget(); // Da disse tilfælde kan forårsage uventede resultater, vil vi fortsætte med at bruge // semikoloner i denne guide. /////////////////////////////////// // 1. Tal, Strenge og Operatorer // JavaScript har én taltype (som er en 64-bit IEEE 754 double). // Doubles har en 52-bit mantissa, hvilket er nok til at gemme heltal // op til omkring 9✕10¹⁵ præcist. 3; // = 3 1.5; // = 1.5 // Nogle grundlæggende aritmetiske operationer virker som du ville forvente. 1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 // Inklusiv ujævn division. 5 / 2; // = 2.5 // Og modulo division. 10 % 2; // = 0 30 % 4; // = 2 18.5 % 7; // = 4.5 // Bitvise operationer virker også; når du udfører en bitvis operation, konverteres din float // til et signeret heltal *op til* 32 bits. 1 << 2; // = 4 // Præcedens håndhæves med parenteser. (1 + 3) * 2; // = 8 // Der er tre specielle ikke-et-rigtigt-tal værdier: Infinity; // resultat af f.eks. 1/0 -Infinity; // resultat af f.eks. -1/0 NaN; // resultat af f.eks. 0/0, står for 'Not a Number' // Der er også en boolesk type. true; false; // Strenge oprettes med ' eller ". ("abc"); ("Hej, verden!"); // Negation bruger ! symbolet !true; // = false !false; // = true // Lighed er === 1 === 1; // = true 2 === 1; // = false // Ulighed er !== 1 !== 1; // = false 2 !== 1; // = true // Flere sammenligninger 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true // Strenge sammenkædes med + "Hej " + "verden!"; // = "Hej verden!" // ... hvilket virker med mere end bare strenge "1, 2, " + 3; // = "1, 2, 3" "Hej " + ["verden", "!"]; // = "Hej verden,!" // ... hvilket kan resultere i nogle underlige adfærd... 13 + !0; // 14 "13" + !0; // '13true' // og sammenlignes med < og > "a" < "b"; // = true // Type tvang udføres for sammenligninger med dobbelt lighedstegn... "5" == 5; // = true null == undefined; // = true // ... medmindre du bruger === "5" === 5; // = false null === undefined; // = false // Du kan tilgå tegn i en streng med `charAt` "Denne streng er god".charAt(0); // = 'D' // ... eller bruge `substring` for at få større dele. "Hej verden".substring(0, 3); // = "Hej" // `length` er en egenskab, så brug ikke (). "Hej".length; // = 3 // Der er også `null` og `undefined`. null; // bruges til at angive en bevidst ikke-værdi undefined; // bruges til at angive at en værdi ikke er til stede i øjeblikket (selvom // `undefined` faktisk er en værdi i sig selv) // false, null, undefined, NaN, 0 og "" er falsy; alt andet er truthy. // Bemærk at 0 er falsy og "0" er truthy, selvom 0 == "0". /////////////////////////////////// // 2. Variable, Arrays og Objekter // Variable deklareres med `var` nøgleordet. JavaScript er dynamisk // typet, så du behøver ikke at angive typen. Tildeling bruger et enkelt `=` // tegn. var nogleVar = 5; // Hvis du udelader var nøgleordet, får du ikke en fejl... andenVar = 10; // ... men din variabel vil blive oprettet i det globale scope, ikke i det scope // du definerede den i. // Variable deklareret uden at blive tildelt er sat til undefined. var tredjeVar; // = undefined // Hvis du vil deklarere et par variable, kan du bruge et komma // separator var fjerdeVar = 2, femteVar = 4; // Der er en kortform for at udføre matematiske operationer på variable: nogleVar += 5; // tilsvarende nogleVar = nogleVar + 5; nogleVar er nu 10 nogleVar *= 10; // nu er nogleVar 100 // og en endnu kortere form for at tilføje eller trække 1 nogleVar++; // nu er nogleVar 101 nogleVar--; // tilbage til 100 // Arrays er ordnede lister af værdier, af enhver type. var mitArray = ["Hej", 45, true]; // Deres medlemmer kan tilgås ved hjælp af firkantede parenteser subscript syntaks. // Array indekser starter ved nul. mitArray[1]; // = 45 // Arrays er mutable og af variabel længde. mitArray.push("Verden"); mitArray.length; // = 4 // Tilføj/Ændr ved specifik indeks mitArray[3] = "Hej"; // Tilføj og fjern element fra fronten eller bagsiden af et array mitArray.unshift(3); // Tilføj som det første element nogleVar = mitArray.shift(); // Fjern første element og returner det mitArray.push(3); // Tilføj som det sidste element nogleVar = mitArray.pop(); // Fjern sidste element og returner det // Sammenføj alle elementer i et array med semikolon var mitArray0 = [32, false, "js", 12, 56, 90]; mitArray0.join(";"); // = "32;false;js;12;56;90" // Få subarray af elementer fra indeks 1 (inkluderet) til 4 (ekskluderet) mitArray0.slice(1, 4); // = [false, "js", 12] // Fjern 4 elementer startende fra indeks 2, og indsæt der strenge // "hej", "ver" og "den"; returner fjernet subarray mitArray0.splice(2, 4, "hej", "ver", "den"); // = ["js", 12, 56, 90] // mitArray0 === [32, false, "hej", "ver", "den"] // JavaScripts objekter svarer til "ordbøger" eller "maps" i andre // sprog: en uordnet samling af nøgle-værdi par. var mitObj = { nøgle1: "Hej", nøgle2: "Verden" }; // Nøgler er strenge, men citationstegn er ikke påkrævet, hvis de er et gyldigt // JavaScript identifikator. Værdier kan være af enhver type. var mitObj = { minNøgle: "minVærdi", "min anden nøgle": 4 }; // Objektattributter kan også tilgås ved hjælp af subscript syntaks, mitObj["min anden nøgle"]; // = 4 // ... eller ved hjælp af punkt syntaks, forudsat at nøglen er et gyldigt identifikator. mitObj.minNøgle; // = "minVærdi" // Objekter er mutable; værdier kan ændres og nye nøgler tilføjes. mitObj.minTredjeNøgle = true; // Hvis du prøver at tilgå en værdi, der endnu ikke er sat, får du undefined. mitObj.minFjerdeNøgle; // = undefined /////////////////////////////////// // 3. Logik og Kontrolstrukturer // `if` strukturen virker som du ville forvente. var tæller = 1; if (tæller == 3) { // evalueres hvis tæller er 3 } else if (tæller == 4) { // evalueres hvis tæller er 4 } else { // evalueres hvis det ikke er enten 3 eller 4 } // Det samme gør `while`. while (true) { // En uendelig løkke! } // Do-while løkker er som while løkker, undtagen at de altid kører mindst én gang. var inddata; do { inddata = hentInddata(); } while (!erGyldig(inddata)); // `for` løkken er den samme som i C og Java: // initialisering; fortsættelsesbetingelse; iteration. for (var i = 0; i < 5; i++) { // vil køre 5 gange } // Breaking out of labeled loops is similar to Java ydre: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j == 5) { break ydre; // bryder ud af den ydre løkke i stedet for kun den indre } } } // for/in udsagnet tillader iteration over egenskaber i et objekt. var beskrivelse = ""; var person = { fornavn: "Paul", efternavn: "Ken", alder: 18 }; for (var x in person) { beskrivelse += person[x] + " "; } // beskrivelse = 'Paul Ken 18 ' // for/of udsagnet tillader iteration over iterable objekter (inklusive de indbyggede String, // Array, f.eks. de Array-lignende arguments eller NodeList objekter, TypedArray, Map og Set, // og brugerdefinerede iterables). var mineKæledyr = ""; var kæledyr = ["kat", "hund", "hamster", "pindsvin"]; for (var kæledyrItem of kæledyr) { mineKæledyr += kæledyrItem + " "; } // mineKæledyr = 'kat hund hamster pindsvin ' // && er logisk og, || er logisk eller if (hus.størrelse == "stor" && hus.farve == "blå") { hus.indeholder = "bjørn"; } if (farve == "rød" || farve == "blå") { // farve er enten rød eller blå } // && og || "kortslutter", hvilket er nyttigt til at sætte standardværdier. var navn = andetNavn || "standard"; // `switch` udsagnet checker for lighed med `===`. // Brug 'break' efter hver case // ellers vil cases efter den korrekte også blive udført. karakter = "B"; switch (karakter) { case "A": console.log("Godt arbejde"); break; case "B": console.log("OK arbejde"); break; case "C": console.log("Du kan gøre det bedre"); break; default: console.log("Åh nej"); break; } /////////////////////////////////// // 4. Funktioner, Scope og Closures // JavaScript funktioner deklareres med `function` nøgleordet. function minFunktion(ting) { return ting.toUpperCase(); } minFunktion("hej"); // = "HEJ" // Bemærk at værdien, der skal returneres, skal starte på samme linje som // `return` nøgleordet, ellers vil du altid returnere `undefined` på grund af // automatisk semikolonindsættelse. Vær opmærksom på dette ved brug af Allman stil. function andenFunktion() { return; // <- semikolon indsættes automatisk her { detteErEn: "objekt literal"; } } andenFunktion(); // = undefined // JavaScript funktioner er første klasses objekter, så de kan tildeles til // forskellige variabelnavne og sendes til andre funktioner som argumenter - for // eksempel, når man leverer en event handler: function tidFunktion() { // denne kode vil blive kaldt om 5 sekunder } setTimeout(tidFunktion, 5000); // Bemærk: setTimeout er ikke en del af JS sproget, men leveres af browsere // og Node.js. // En anden funktion leveret af browsere er setInterval function intervalFunktion() { // denne kode vil blive kaldt hvert 5. sekund } setInterval(intervalFunktion, 5000); // Funktionsobjekter behøver ikke engang at blive deklareret med et navn - du kan skrive // en anonym funktionsdefinition direkte i argumenterne til en anden. setTimeout(function () { // denne kode vil blive kaldt om 5 sekunder }, 5000); // JavaScript har funktionsscope; funktioner får deres eget scope, men andre blokke // gør ikke. if (true) { var i = 5; } i; // = 5 - ikke undefined som du ville forvente i et blok-scopet sprog // Dette har ført til et almindeligt mønster af "umiddelbart-udførende anonyme // funktioner", som forhindrer midlertidige variable i at lække ind i det globale // scope. (function () { var midlertidig = 5; // Vi kan tilgå det globale scope ved at tildele til "det globale objekt", som // i en webbrowser altid er `window`. Det globale objekt kan have et // andet navn i ikke-browser miljøer som Node.js. window.permanent = 10; })(); midlertidig; // rejser ReferenceError permanent; // = 10 // En af JavaScripts mest kraftfulde funktioner er closures. Hvis en funktion er // defineret inde i en anden funktion, har den indre funktion adgang til alle // den ydre funktions variable, selv efter den ydre funktion er afsluttet. function sigHejOmFemSekunder(navn) { var besked = "Hej, " + navn + "!"; // Indre funktioner placeres i det lokale scope som standard, som om de var // deklareret med `var`. function indre() { alert(besked); } setTimeout(indre, 5000); // setTimeout er asynkron, så sigHejOmFemSekunder funktionen vil // afslutte øjeblikkeligt, og setTimeout vil kalde indre bagefter. Men // fordi indre er "closed over" sigHejOmFemSekunder, har indre stadig // adgang til `besked` variablen, når den endelig kaldes. } sigHejOmFemSekunder("Adam"); // vil åbne en popup med "Hej, Adam!" om 5 sekunder /////////////////////////////////// // 5. Mere om Objekter; Konstruktører og Prototyper // Objekter kan indeholde funktioner. var mitObj = { minFunc: function () { return "Hej verden!"; }, }; mitObj.minFunc(); // = "Hej verden!" // Når funktioner tilknyttet et objekt kaldes, kan de tilgå objektet // de er tilknyttet ved hjælp af `this` nøgleordet. mitObj = { minStreng: "Hej verden!", minFunc: function () { return this.minStreng; }, }; mitObj.minFunc(); // = "Hej verden!" // Hvad `this` er sat til har at gøre med, hvordan funktionen kaldes, ikke hvor // den er defineret. Så vores funktion virker ikke, hvis den ikke kaldes i // konteksten af objektet. var minFunc = mitObj.minFunc; minFunc(); // = undefined // Omvendt kan en funktion tildeles til objektet og få adgang til det // gennem `this`, selvom den ikke var tilknyttet, da den blev defineret. var minAndenFunc = function () { return this.minStreng.toUpperCase(); }; mitObj.minAndenFunc = minAndenFunc; mitObj.minAndenFunc(); // = "HEJ VERDEN!" // Vi kan også specificere en kontekst for en funktion at udføre i, når vi kalder den // ved hjælp af `call` eller `apply`. var endnuEnFunc = function (s) { return this.minStreng + s; }; endnuEnFunc.call(mitObj, " Og hej måne!"); // = "Hej verden! Og hej måne!" // `apply` funktionen er næsten identisk, men tager et array som argumentliste. endnuEnFunc.apply(mitObj, [" Og hej sol!"]); // = "Hej verden! Og hej sol!" // Dette er nyttigt, når man arbejder med en funktion, der accepterer en sekvens af // argumenter, og du vil sende et array. Math.min(42, 6, 27); // = 6 Math.min([42, 6, 27]); // = NaN (uh-oh!) Math.min.apply(Math, [42, 6, 27]); // = 6 // Men `call` og `apply` er kun midlertidige. Når vi vil have det til at blive ved, kan vi // bruge `bind`. var bundetFunc = endnuEnFunc.bind(mitObj); bundetFunc(" Og hej Saturn!"); // = "Hej verden! Og hej Saturn!" // Når du kalder en funktion med `new` nøgleordet, oprettes et nyt objekt, og // gøres tilgængeligt for funktionen via `this` nøgleordet. Funktioner designet til at blive // kaldt sådan kaldes konstruktører. var MinKonstruktør = function () { this.mitTal = 5; }; mitNyeObj = new MinKonstruktør(); // = {mitTal: 5} mitNyeObj.mitTal; // = 5 // I modsætning til de fleste andre populære objektorienterede sprog har JavaScript ingen // begreb om 'instanser' oprettet fra 'klasse' blueprints; i stedet kombinerer JavaScript // instantiation og arv i et enkelt begreb: en 'prototype'. // Hvert JavaScript objekt har en 'prototype'. Når du prøver at tilgå en egenskab // på et objekt, der ikke findes på selve objektet, vil interpreteren // kigge på dens prototype. // Nogle JS implementeringer lader dig tilgå et objekts prototype på den magiske // egenskab `__proto__`. Selvom dette er nyttigt til at forklare prototyper, er det ikke // en del af standarden; vi vil komme til standard måder at bruge prototyper på senere. var mitObj = { minStreng: "Hej verden!", }; var minPrototype = { livetsBetydning: 42, minFunc: function () { return this.minStreng.toLowerCase(); }, }; mitObj.__proto__ = minPrototype; mitObj.livetsBetydning; // = 42 // Dette virker også for funktioner. mitObj.minFunc(); // = "hej verden!" // Selvfølgelig, hvis din egenskab ikke er på din prototype, søges prototypens // prototype, og så videre. minPrototype.__proto__ = { minBool: true, }; mitObj.minBool; // = true // Der er ingen kopiering involveret her; hvert objekt gemmer en reference til sin // prototype. Dette betyder, at vi kan ændre prototypen, og vores ændringer vil blive // afspejlet overalt. minPrototype.livetsBetydning = 43; mitObj.livetsBetydning; // = 43 // for/in udsagnet tillader iteration over egenskaber i et objekt, // går op ad prototypekæden, indtil det ser en null prototype. for (var x in mitObj) { console.log(mitObj[x]); } // udskriver: // Hej verden! // 43 // [Function: minFunc] // true // For kun at overveje egenskaber tilknyttet selve objektet // og ikke dets prototyper, brug `hasOwnProperty()` check. for (var x in mitObj) { if (mitObj.hasOwnProperty(x)) { console.log(mitObj[x]); } } // udskriver: // Hej verden! // Vi nævnte at `__proto__` var ikke-standard, og der er ingen standard måde at // ændre prototypen på et eksisterende objekt. Der er dog to måder at // oprette et nyt objekt med en given prototype. // Den første er Object.create, som er en nylig tilføjelse til JS, og derfor // ikke tilgængelig i alle implementeringer endnu. var mitObj = Object.create(minPrototype); mitObj.livetsBetydning; // = 43 // Den anden måde, som virker overalt, har at gøre med konstruktører. // Konstruktører har en egenskab kaldet prototype. Dette er *ikke* prototypen af // selve konstruktørfunktionen; i stedet er det prototypen, som nye objekter // får, når de oprettes med den konstruktør og new nøgleordet. MinKonstruktør.prototype = { mitTal: 5, hentMitTal: function () { return this.mitTal; }, }; var mitNyeObj2 = new MinKonstruktør(); mitNyeObj2.hentMitTal(); // = 5 mitNyeObj2.mitTal = 6; mitNyeObj2.hentMitTal(); // = 6 // Indbyggede typer som strenge og tal har også konstruktører, der opretter // tilsvarende wrapper objekter. var mitTal = 12; var mitTalObj = new Number(12); mitTal == mitTalObj; // = true // Bortset fra at de ikke er præcist tilsvarende. typeof mitTal; // = 'number' typeof mitTalObj; // = 'object' mitTal === mitTalObj; // = false if (0) { // Denne kode vil ikke blive udført, fordi 0 er falsy. } if (new Number(0)) { // Denne kode vil blive udført, fordi wrapped numbers er objekter, og objekter // er altid truthy. } // Dog deler wrapper objekterne og de almindelige indbyggede en prototype, så // du kan faktisk tilføje funktionalitet til en streng, for eksempel. String.prototype.førsteTegn = function () { return this.charAt(0); }; "abc".førsteTegn(); // = "a" // Dette faktum bruges ofte i "polyfilling", som er implementering af nyere // funktioner i JavaScript i en ældre undergruppe af JavaScript, så de kan // bruges i ældre miljøer som forældede browsere. // For eksempel nævnte vi, at Object.create ikke er tilgængelig i alle // implementeringer endnu, men vi kan stadig bruge det med denne polyfill: if (Object.create === undefined) { // overskriv det ikke, hvis det eksisterer Object.create = function (proto) { // lav en midlertidig konstruktør med den rigtige prototype var Konstruktør = function () {}; Konstruktør.prototype = proto; // brug den derefter til at oprette et nyt, passende prototyperet objekt return new Konstruktør(); }; } // ES6 Tilføjelser // "let" nøgleordet tillader dig at definere variable i et leksikalsk scope, // i modsætning til et funktionsscope som var nøgleordet gør. let navn = "Billy"; // Variable defineret med let kan tildeles nye værdier. navn = "William"; // "const" nøgleordet tillader dig at definere en variabel i et leksikalsk scope // som med let, men du kan ikke tildele værdien igen, når den først er tildelt. const pi = 3.14; pi = 4.13; // Du kan ikke gøre dette. // Der er en ny syntaks for funktioner i ES6 kendt som "lambda syntaks". // Dette tillader funktioner at blive defineret i et leksikalsk scope som med variable // defineret af const og let. const erLige = (tal) => { return tal % 2 === 0; }; erLige(7); // false // Den "tilsvarende" funktion i den traditionelle syntaks ville se sådan ud: function erLigeTraditionel(tal) { return tal % 2 === 0; } // Jeg satte ordet "tilsvarende" i citationstegn, fordi en funktion defineret // ved hjælp af lambda syntaksen ikke kan kaldes før definitionen. // Følgende er et eksempel på ugyldig brug: tilføj(1, 8); const tilføj = (førsteTal, andetTal) => { return førsteTal + andetTal; }; ``` ================================================ FILE: dart.md ================================================ --- name: Dart filename: learndart.dart contributors: - ["Joao Pedrosa", "https://github.com/jpedrosa/"] - ["Vince Ramces Oliveros", "https://github.com/ram231"] --- **Dart** is a single threaded, general purpose programming language. It borrows a lot from other mainstream languages. It supports Streams, Futures(known as Promises in JavaScript), Generics, First-class functions(closures) and static type checking. Dart can run in any platform such as Web, CLI, Desktop, Mobile and IoT devices. Dart's most controversial feature is its ~~Optional Typing~~ Static Type safety and [Sound Type checks](https://dart.dev/guides/language/sound-dart). ```dart import "dart:collection"; import "dart:math" as math; /// Welcome to Learn Dart in 15 minutes. http://dart.dev/ /// This is an executable tutorial. You can run it with Dart or on /// the Try Dart! site if you copy/paste it there. http://dartpad.dev/ /// You can also run Flutter in DartPad by click the `< > New Pad ` and choose Flutter /// In Dart, Everything is an Object. /// Every declaration of an object is an instance of Null and /// Null is also an object. /// 3 Types of comments in dart // Single line comment /** * Multi-line comment * Can comment several lines */ /// Code doc comment /// It uses markdown syntax to generate code docs when making an API. /// Code doc comment is the recommended choice when documenting your APIs, classes and methods. /// 4 types of variable declaration. /// Constants are variables that are immutable cannot be change or altered. /// `const` in dart should practice SCREAMING_SNAKE_CASE name declaration. const CONSTANT_VALUE = "I CANNOT CHANGE"; CONSTANT_VALUE = "DID I?"; //Error /// Final is another variable declaration that cannot be change once it has been instantiated. Commonly used in classes and functions /// `final` can be declared in pascalCase. final finalValue = "value cannot be changed once instantiated"; finalValue = "Seems not"; //Error /// `var` is another variable declaration that is mutable and can change its value. Dart will infer types and will not change its data type var mutableValue = "Variable string"; mutableValue = "this is valid"; mutableValue = false; // Error. /// `dynamic` is another variable declaration in which the type is not evaluated by the dart static type checking. /// It can change its value and data type. /// Some dartisans uses dynamic cautiously as it cannot keep track of its data type. so use it at your own risk dynamic dynamicValue = "I'm a string"; dynamicValue = false; // false /// Functions can be declared in a global space /// Function declaration and method declaration look the same. Function /// declarations can be nested. The declaration takes the form of /// name() {} or name() => singleLineExpression; /// The fat arrow function declaration can be an implicit or /// explicit return for the result of the expression. /// Dart will execute a function called `main()` anywhere in the dart project. /// example1() { nested1() { nested2() => print("Example1 nested 1 nested 2"); nested2(); } nested1(); } /// Anonymous functions don't include a name example2() { //// Explicit return type. nested1(void Function() fn) { fn(); } nested1(() => print("Example2 nested 1")); } /// When a function parameter is declared, the declaration can include the /// number of parameters the function takes by explicitly specifying the names of the /// parameters it takes. example3() { planA(fn(String informSomething)) { fn("Example3 plan A"); } planB(fn) { // Or don't declare number of parameters. fn("Example3 plan B"); } planA((s) => print(s)); planB((s) => print(s)); } /// Functions have closure access to outer variables. /// Dart will infer types when the variable has a value of something. /// In this example dart knows that this variable is a String. var example4Something = "Example4 nested 1"; example4() { nested1(fn(informSomething)) { fn(example4Something); } nested1((s) => print(s)); } /// Class declaration with a sayIt method, which also has closure access /// to the outer variable as though it were a function as seen before. var example5method = "Example5 sayIt"; class Example5Class { sayIt() { print(example5method); } } example5() { /// Create an anonymous instance of the Example5Class and call the sayIt /// method on it. /// the `new` keyword is optional in Dart. new Example5Class().sayIt(); } /// Class declaration takes the form of class name { [classBody] }. /// Where classBody can include instance methods and variables, but also /// class methods and variables. class Example6Class { var instanceVariable = "Example6 instance variable"; sayIt() { print(instanceVariable); } } example6() { Example6Class().sayIt(); } /// Class methods and variables are declared with "static" terms. class Example7Class { static var classVariable = "Example7 class variable"; static sayItFromClass() { print(classVariable); } sayItFromInstance() { print(classVariable); } } example7() { Example7Class.sayItFromClass(); new Example7Class().sayItFromInstance(); } /// Dart supports Generics. /// Generics refers to the technique of writing the code for a class /// without specifying the data type(s) that the class works on. /// Source: https://stackoverflow.com/questions/4560890/what-are-generics-in-c /// Type `T` refers to any type that has been instantiated /// you can call whatever you want /// Programmers uses the convention in the following /// T - Type(used for class and primitype types) /// E - Element(used for List, Set, or Iterable) /// K,V - Key Value(used for Map) class GenericExample{ void printType(){ print("$T"); } // methods can also have generics genericMethod(){ print("class:$T, method: $M"); } } /// List are similar to arrays but list is a child of Iterable /// Therefore Maps, List, LinkedList are all child of Iterable to be able to loop using the keyword `for` /// Important things to remember: /// () - Iterable /// [] - List /// {} - Map /// List are great, but there's a restriction for what List can be /// outside of function/method bodies. List on the outer scope of class /// or outside of class have to be constant. Strings and numbers are constant /// by default. But arrays and maps are not. They can be made constant by /// declaring them "const". Kind of similar to JavaScript's Object.freeze() const example8List = ["Example8 const array"]; const example8Map = {"someKey": "Example8 const map"}; /// Declare List or Maps as Objects. List explicitList = new List.empty(); Map explicitMaps = new Map(); example8() { explicitList.add("SomeArray"); print(example8Map["someKey"]); print(explicitList[0]); /// Assigning a list from one variable to another will not be the same result. /// Because dart is pass-reference-by-value. /// So when you assign an existing list to a new variable. /// Instead of List, it becomes an Iterable var iterableExplicitList = explicitList; print(iterableExplicitList); // ("SomeArray"); "[]" becomes "()" var newExplicitLists = explicitList.toList(); // Converts Iterable to List } /// Loops in Dart take the form of standard for () {} or while () {} loops, /// slightly more modern for (.. in ..) {}, or functional callbacks with many /// supported features, starting with forEach,map and where. var example9Array = const ["a", "b"]; example9() { for (int i = 0; i < example9Array.length; i++) { print("Example9 for loop '${example9Array[i]}'"); } var i = 0; while (i < example9Array.length) { print("Example9 while loop '${example9Array[i]}'"); i++; } for (final e in example9Array) { print("Example9 for-in loop '${e}'"); } example9Array.forEach((e) => print("Example9 forEach loop '${e}'")); } /// To loop over the characters of a string or to extract a substring. var example10String = "ab"; example10() { for (var i = 0; i < example10String.length; i++) { print("Example10 String character loop '${example10String[i]}'"); } for (var i = 0; i < example10String.length; i++) { print("Example10 substring loop '${example10String.substring(i, i + 1)}'"); } } /// `int`, `double` and `num` are the three supported number formats. /// `num` can be either `int` or `double`. /// `int` and `double` are children of type `num` example11() { var i = 1 + 320, d = 3.2 + 0.01; final num myFinalNumDouble = 2.2; final num myFinalNumInt = 2; final int myFinalInt = 1; final double myFinalDouble = 0.1; num myNumDouble = 2.2; num myNumInt = 2; int myInt = 1; double myDouble = 0; // Dart will add decimal prefix, becomes 0.0; myNumDouble = myFinalInt; // valid myNumDouble = myFinalDouble; // valid myNumDouble = myFinalNumInt; // valid myInt = myNumDouble; // error myInt = myFinalDouble; // error myInt = myFinalNumInt; // error (implicit downcasts removed in Dart 2.9) myInt = myFinalNumInt as int; // valid myDouble = myFinalInt; // error myDouble = myFinalNumInt; // error myDouble = myFinalNumDouble; // error (implicit downcasts removed in Dart 2.9) myDouble = myFinalNumDouble as double; // valid print("Example11 int ${i}"); print("Example11 double ${d}"); } /// DateTime provides date/time arithmetic. example12() { var now = new DateTime.now(); print("Example12 now '${now}'"); now = now.add(new Duration(days: 1)); print("Example12 tomorrow '${now}'"); } /// Regular expressions are supported. example13() { var s1 = "some string", s2 = "some", re = new RegExp("^s.+?g\$"); match(s) { if (re.hasMatch(s)) { print("Example13 regexp matches '${s}'"); } else { print("Example13 regexp doesn't match '${s}'"); } } match(s1); match(s2); } /// Boolean expressions support implicit conversions and dynamic type example14() { var a = true; if (a) { print("true, a is $a"); } a = false; if (a) { print("true, a is $a"); } else { print("false, a is $a"); /// runs here } /// dynamic typed null can not be convert to bool var b; /// b is dynamic type b = "abc"; try { if (b) { print("true, b is $b"); } else { print("false, b is $b"); } } catch (e) { print("error, b is $b"); /// this could be run but got error } b = null; if (b) { /// Failed assertion: boolean expression must not be null) print("true, b is $b"); } else { print("false, b is $b"); } /// statically typed null can not be convert to bool var c = "abc"; c = null; /// compilation failed /// if (c) { /// print("true, c is $c"); /// } else { /// print("false, c is $c"); /// } } /// try/catch/finally and throw are used for exception handling. /// throw takes any object as parameter; example15() { try { try { throw "Some unexpected error."; } catch (e) { print("Example15 an exception: '${e}'"); throw e; /// Re-throw } } catch (e) { print("Example15 catch exception being re-thrown: '${e}'"); } finally { print("Example15 Still run finally"); } } /// To be efficient when creating a long string dynamically, use /// StringBuffer. Or you could join a string array. example16() { var sb = new StringBuffer(), a = ["a", "b", "c", "d"], e; for (e in a) { sb.write(e); } print("Example16 dynamic string created with " "StringBuffer '${sb.toString()}'"); print("Example16 join string array '${a.join()}'"); } /// Strings can be concatenated by just having string List next to /// one another with no further operator needed. example17() { print("Example17 " "concatenate " "strings " "just like that"); } /// Strings have single-quote or double-quote for delimiters with no /// actual difference between the two. The given flexibility can be good /// to avoid the need to escape content that matches the delimiter being /// used. For example, double-quotes of HTML attributes if the string /// contains HTML content. example18() { print('Example18 ' "Don't can't I'm Etc" ''); } /// Strings with triple single-quotes or triple double-quotes span /// multiple lines and include line delimiters. example19() { print('''Example19 Example19 Don't can't I'm Etc Example19 '''); } /// Strings have the nice interpolation feature with the $ character. /// With $ { [expression] }, the return of the expression is interpolated. /// $ followed by a variable name interpolates the content of that variable. /// $ can be escaped like so \$ to just add it to the string instead. example20() { var s1 = "'\${s}'", s2 = "'\$s'"; print("Example20 \$ interpolation ${s1} or $s2 works."); } /// Optional types allow for the annotation of APIs and come to the aid of /// IDEs so the IDEs can better refactor, auto-complete and check for /// errors. So far we haven't declared any types and the programs have /// worked just fine. In fact, types are disregarded during runtime. /// Types can even be wrong and the program will still be given the /// benefit of the doubt and be run as though the types didn't matter. /// There's a runtime parameter that checks for type errors which is /// the checked mode, which is said to be useful during development time, /// but which is also slower because of the extra checking and is thus /// avoided during deployment runtime. class Example21 { List _names = []; Example21() { _names = ["a", "b"]; } List get names => _names; set names(List list) { _names = list; } int get length => _names.length; void add(String name) { _names.add(name); } } void example21() { Example21 o = new Example21(); o.add("c"); print("Example21 names '${o.names}' and length '${o.length}'"); o.names = ["d", "e"]; print("Example21 names '${o.names}' and length '${o.length}'"); } /// Class inheritance takes the form of class name extends AnotherClassName {}. class Example22A { var _name = "Some Name!"; get name => _name; } class Example22B extends Example22A {} example22() { var o = new Example22B(); print("Example22 class inheritance '${o.name}'"); } /// Class mixin is also available, and takes the form of /// class name extends SomeClass with AnotherClassName {}. /// It's necessary to extend some class to be able to mixin another one. /// The template class of mixin cannot at the moment have a constructor. /// Mixin is mostly used to share methods with distant classes, so the /// single inheritance doesn't get in the way of reusable code. /// Mixins follow the "with" statement during the class declaration. class Example23A {} /// Since Dart 3 the 'mixin' keyword is required instead of 'class'. mixin Example23Utils { addTwo(n1, n2) { return n1 + n2; } } class Example23B extends Example23A with Example23Utils { addThree(n1, n2, n3) { return addTwo(n1, n2) + n3; } } example23() { var o = new Example23B(), r1 = o.addThree(1, 2, 3), r2 = o.addTwo(1, 2); print("Example23 addThree(1, 2, 3) results in '${r1}'"); print("Example23 addTwo(1, 2) results in '${r2}'"); } /// The Class constructor method uses the same name of the class and /// takes the form of SomeClass() : super() {}, where the ": super()" /// part is optional and it's used to delegate constant parameters to the /// super-parent's constructor. class Example24A { var _value; Example24A({value = "someValue"}) { _value = value; } get value => _value; } class Example24B extends Example24A { Example24B({value = "someOtherValue"}) : super(value: value); } example24() { var o1 = new Example24B(), o2 = new Example24B(value: "evenMore"); print("Example24 calling super during constructor '${o1.value}'"); print("Example24 calling super during constructor '${o2.value}'"); } /// There's a shortcut to set constructor parameters in case of simpler classes. /// Just use the this.parameterName prefix and it will set the parameter on /// an instance variable of same name. class Example25 { var value, anotherValue; Example25({this.value, this.anotherValue}); } example25() { var o = new Example25(value: "a", anotherValue: "b"); print("Example25 shortcut for constructor '${o.value}' and " "'${o.anotherValue}'"); } /// Named parameters are available when declared between {}. /// Parameter order can be optional when declared between {}. /// Parameters can be made optional when declared between []. example26() { var _name, _surname, _email; setConfig1({name, surname}) { _name = name; _surname = surname; } setConfig2(name, [surname, email]) { _name = name; _surname = surname; _email = email; } setConfig1(surname: "Doe", name: "John"); print("Example26 name '${_name}', surname '${_surname}', " "email '${_email}'"); setConfig2("Mary", "Jane"); print("Example26 name '${_name}', surname '${_surname}', " "email '${_email}'"); } /// Variables declared with final can only be set once. /// In case of classes, final instance variables can be set via constant /// constructor parameter. class Example27 { final color1, color2; /// A little flexibility to set final instance variables with syntax /// that follows the : Example27({this.color1, color2}) : color2 = color2; } example27() { final color = "orange", o = new Example27(color1: "lilac", color2: "white"); print("Example27 color is '${color}'"); print("Example27 color is '${o.color1}' and '${o.color2}'"); } /// To import a library, use import "libraryPath" or if it's a core library, /// import "dart:libraryName". There's also the "pub" package management with /// its own convention of import "package:packageName". /// See import "dart:collection"; at the top. Imports must come before /// other code declarations. IterableBase comes from dart:collection. class Example28 extends IterableBase { var names; Example28() { names = ["a", "b"]; } get iterator => names.iterator; } example28() { var o = new Example28(); o.forEach((name) => print("Example28 '${name}'")); } /// For control flow we have: /// * standard switch with must break statements /// * if-else if-else and ternary ..?..:.. operator /// * closures and anonymous functions /// * break, continue and return statements example29() { var v = true ? 30 : 60; switch (v) { case 30: print("Example29 switch statement"); break; } if (v < 30) { } else if (v > 30) { } else { print("Example29 if-else statement"); } callItForMe(fn()) { return fn(); } rand() { v = new math.Random().nextInt(50); return v; } while (true) { print("Example29 callItForMe(rand) '${callItForMe(rand)}'"); if (v != 30) { break; } else { continue; } /// Never gets here. } } /// Parse int, convert double to int, or just keep int when dividing numbers /// by using the ~/ operation. Let's play a guess game too. example30() { var gn, tooHigh = false, n, n2 = (2.0).toInt(), top = int.parse("123") ~/ n2, bottom = 0; top = top ~/ 6; gn = new math.Random().nextInt(top + 1); /// +1 because nextInt top is exclusive print("Example30 Guess a number between 0 and ${top}"); guessNumber(i) { if (n == gn) { print("Example30 Guessed right! The number is ${gn}"); } else { tooHigh = n > gn; print("Example30 Number ${n} is too " "${tooHigh ? 'high' : 'low'}. Try again"); } return n == gn; } n = (top - bottom) ~/ 2; while (!guessNumber(n)) { if (tooHigh) { top = n - 1; } else { bottom = n + 1; } n = bottom + ((top - bottom) ~/ 2); } } /// Optional Positional Parameter: /// parameter will be disclosed with square bracket [ ] & square bracketed parameter are optional. example31() { findVolume31(int length, int breath, [int? height]) { print('length = $length, breath = $breath, height = $height'); } findVolume31(10,20,30); //valid findVolume31(10,20); //also valid } /// Optional Named Parameter: /// parameter will be disclosed with curly bracket { } /// curly bracketed parameter are optional. /// have to use parameter name to assign a value which separated with colan : /// in curly bracketed parameter order does not matter /// these type parameter help us to avoid confusion while passing value for a function which has many parameter. example32() { findVolume32(int length, int breath, {int? height}) { print('length = $length, breath = $breath, height = $height'); } findVolume32(10,20,height:30);//valid & we can see the parameter name is mentioned here. findVolume32(10,20);//also valid } /// Optional Default Parameter: /// same like optional named parameter in addition we can assign default value for this parameter. /// which means no value is passed this default value will be taken. example33() { findVolume33(int length, int breath, {int height=10}) { print('length = $length, breath = $breath, height = $height'); } findVolume33(10,20,height:30);//valid findVolume33(10,20);//valid } /// Dart has also added feature such as Null aware operators var isBool = true; var hasString = isBool ?? "default String"; /// Programs have only one entry point in the main function. /// Nothing is expected to be executed on the outer scope before a program /// starts running with what's in its main function. /// This helps with faster loading and even lazily loading of just what /// the program needs to startup with. main() { print("Learn Dart in 15 minutes!"); [ example1, example2, example3, example4, example5, example6, example7, example8, example9, example10, example11, example12, example13, example14, example15, example16, example17, example18, example19, example20, example21, example22, example23, example24, example25, example26, example27, example28, example29, example30 // Adding this comment stops the dart formatter from putting all items on a new line ].forEach((ef) => ef()); } ``` ## Further Reading Dart has a comprehensive web-site. It covers API reference, tutorials, articles and more, including a useful DartPad (a cloud-based Dart coding playground). [https://dart.dev/](https://dart.dev) [https://dartpad.dev/](https://dartpad.dev) ================================================ FILE: de/apl.md ================================================ --- name: APL contributors: - ["nooodl", "https://github.com/nooodl"] translators: - ["antonkesy", "https://github.com/antonkesy"] filename: learnapl.apl --- ```apl ⍝ Kommentare in APL beginnen mit ⍝. ⍝ Eine Liste von Zahlen. (¯ ist negativ) 2 3e7 ¯4 50.3 ⍝ Ein Ausdruck, der einige Funktionen zeigt. In APL gibt es ⍝ keine Operatorrangfolge: alles wird von rechts nach ⍝ links geparst. Dies entspricht 5 + (4 × (2 ÷ (5 - 3))) = 9: 5 + 4 × 2 ÷ 5 - 3 ⍝ 9 ⍝ Diese Funktionen funktionieren auch mit Listen: 1 2 3 4 × 5 ⍝ 5 10 15 20 1 2 3 4 × 5 6 7 8 ⍝ 5 12 21 32 ⍝ Alle Funktionen haben sowohl Einzelargument- als auch Doppelargument- ⍝ Bedeutungen. Zum Beispiel bedeutet "×" mit zwei Argumenten ⍝ multiplizieren, aber wenn es nur auf eine rechte Seite ⍝ angewendet wird, gibt es das Vorzeichen zurück: × ¯4 ¯2 0 2 4 ⍝ ¯1 ¯1 0 1 1 ⍝ Werte können mit diesen Operatoren verglichen werden (1 bedeutet ⍝ "wahr", 0 bedeutet "falsch"): 10 20 30 = 10 20 99 ⍝ 1 1 0 10 20 30 < 10 20 99 ⍝ 0 0 1 ⍝ "⍳n" gibt einen Vektor mit den ersten n natürlichen Zahlen zurück. ⍝ Matrizen können mit ⍴ (umformen) konstruiert werden: 4 3 ⍴ ⍳5 ⍝ 0 1 2 ⍝ 3 4 0 ⍝ 1 2 3 ⍝ 4 0 1 ⍝ Einzelargument ⍴ gibt die Dimensionen zurück: ⍴ 4 3 ⍴ ⍳5 ⍝ 4 3 ⍝ Werte können mit ← gespeichert werden. Lass uns den Mittelwert ⍝ eines Vektors von Zahlen berechnen: A ← 10 60 55 23 ⍝ Summe der Elemente von A (/ ist Reduktion): +/A ⍝ 148 ⍝ Länge von A: ⍴A ⍝ 4 ⍝ Mittelwert: (+/A) ÷ (⍴A) ⍝ 37 ⍝ Wir können dies als Funktion mit {} und ⍵ definieren: mean ← {(+/⍵)÷⍴⍵} mean A ⍝ 37 ``` ## Weitere Literatur - [APL Wiki](https://aplwiki.com/) - Eine ältere Version des APL-Buchs vom Erfinder: [Kenneth Iverson - A Programming Language](https://archive.org/details/aprogramminglanguage1962) - Weitere Bücher: [APL Books](https://aplwiki.com/wiki/Books) ================================================ FILE: de/asciidoc.md ================================================ --- contributors: - ["Ryan Mavilia", "http://unoriginality.rocks/"] translators: - ["Dennis Keller", "https://github.com/denniskeller"] --- AsciiDoc ist eine Auszeichnungssprache, ähnlich wie Markdown. Sie kann für alles verwendet werden von Büchern bis zu Blogs. Erfunden wurde sie 2002 von Stuart Rackham. Die Sprache ist simpel, aber sie ermöglicht eine große Anzahl an Anpassungen. Kopfzeile des Dokuments Kopfzeilen sind optional und dürfen keine Leerzeilen besitzen. Sie müssen mindestens eine Leerzeile vom Inhalt versetzt sein. Nur Titel ``` = Dokumententitel Erster Satz des Dokuments. ``` Titel und Autor ``` = Dokumententitel Vorname Nachname Start des Dokuments. ``` Mehrere Autoren ``` = Dokumententitel John Doe ; Jane Doe; Black Beard Starte ein Dokument mit mehreren Autoren. ``` Revisionszeile (benötigt eine Autorzeile) ``` = Dokumententitel V1 Potato Man v1.0, 2016-01-13 Dieser Artikel über Chips wird Spaß machen. ``` Absätze ``` Du musst nichts Besonderes machen für Absätze. Füge eine Leerzeile zwischen zwei Absätze, um sie zu trennen. Um eine Leerzeile zu erhalten musst du ein + ergänzen und du erhältst einen Umbruch! ``` Textformatierung ``` _Unterstriche erstellt Kursivschrift_ *Sternchen für Fett gedruckt* *_Kombinieren für extra Spaß_* `Benutze Ticks um Monospace zu signalisieren` `*Fett gedruckter Monospace*` ``` Abteilungstitel ``` = Level 0 (sollte nur in der Kopfzeile verwendet werden) == Level 1

=== Level 2

==== Level 3

===== Level 4

``` Listen Um eine Aufzählung zu erstellen, verwendest du Sternchen. ``` * foo * bar * baz ``` Um eine nummerierte Liste zu erstellen, verwendest du Punkte. ``` . item 1 . item 2 . item 3 ``` Um Listen zu verschachteln, musst du zusätzliche Sternchen beziehungsweise Punkte hinzufügen. Dies ist bis zu fünf Mal möglich. ``` * foo 1 ** foo 2 *** foo 3 **** foo 4 ***** foo 5 . foo 1 .. foo 2 ... foo 3 .... foo 4 ..... foo 5 ``` ================================================ FILE: de/bash.md ================================================ --- contributors: - ["Max Yankov", "https://github.com/golergka"] - ["Darren Lin", "https://github.com/CogBear"] translators: - ["kultprok", "http://www.kulturproktologie.de"] --- Bash ist der Name der Unix-Shell, die als Shell des GNU-Betriebssystems und auch als Standard-Shell von Linux und macOS ausgeliefert wurde. Beinahe alle der folgenden Beispiele können als Teile eines Shell-Skripts oder direkt in der Shell ausgeführt werden. ```bash #!/bin/bash # Die erste Zeile des Scripts nennt sich Shebang, dies gibt dem System an, # wie das Script ausgeführt werden soll: http://de.wikipedia.org/wiki/Shebang # Du hast es bestimmt schon mitgekriegt, Kommentare fangen mit # an. Das Shebang ist auch ein Kommentar # Ein einfaches Beispiel mit hello world: echo Hello, world! # Jeder Befehl fängt auf einer neuen Zeile oder nach einem Semikolon an: echo 'Dies ist die erste Zeile'; echo 'Dies die zweite Zeile' # Variablen deklariert man so: Variable="irgendein String" # Aber nicht so: Variable = "irgendein String" # Bash wird 'Variable' für einen Befehl halten, den es ausführen soll. Es wird einen Fehler ausgeben, # weil es den Befehl nicht findet. # Und so auch nicht: Variable= 'Some string' # Bash wird 'Variable' wieder für einen Befehl halten, den es ausführen soll. Es wird einen Fehler ausgeben, # Hier wird der Teil 'Variable=' als nur für diesen einen Befehl gültige Zuweisung an die Variable gesehen. # Eine Variable wird so benutzt: echo $Variable echo "$Variable" echo ${Variable} # aber echo '$Variable' # Wenn du eine Variable selbst benutzt – ihr Werte zuweist, sie exportierst oder irgendetwas anderes –, # dann über ihren Namen ohne $. Aber wenn du ihren zugewiesenen Wert willst, dann musst du $ voranstellen. # Beachte: ' (Hochkomma) verhindert das Interpretieren der Variablen # Ersetzen von Zeichenketten in Variablen echo ${Variable/irgendein/neuer} # Ersetzt das erste Vorkommen von "irgendein" durch "neuer" # Teil einer Zeichenkette Laenge=7 echo ${Variable:0:Laenge} # Gibt nur die ersten 7 Zeichen zurück # Standardwert verwenden echo ${Foo:-"ErsatzWennLeerOderUngesetzt"} # Das funktioniert mit nicht gesetzten Variablen (Foo=) und leeren Zeichenketten (Foo="") # Die Zahl 0 (Foo=0) liefert 0. # Beachte: der wert der Variablen wird nicht geändert # Eingebaute Variable (BUILTINS): # Einige nützliche Beispiele echo "Rückgabewert des letzten Befehls: $?" echo "Die PID des skripts: $$" echo "Anzahl der Argumente beim Aufruf: $#" echo "Alle Argumente beim Aufruf: $@" echo "Die Argumente in einzelnen Variablen: $1 $2..." # Einen Wert aus der Eingabe lesen: echo "Wie heisst du?" read NAME # Wir mussten nicht mal eine neue Variable deklarieren echo Hello, $NAME! # Wir haben die übliche if-Struktur: # 'man test' liefert weitere Informationen zu Bedingungen if [ "$NAME" -ne $USER ] then echo "Dein Name ist nicht dein Login-Name" else echo "Dein Name ist dein Login-Name" fi # Es gibt auch bedingte Ausführung echo "immer ausgeführt" || echo "Nur ausgeführt wenn der erste Befehl fehlschlägt" echo "immer ausgeführt" && echo "Nur ausgeführt wenn der erste Befehl Erfolg hat" # Um && und || mit if statements zu verwenden, braucht man mehrfache Paare eckiger Klammern: if [ "$NAME" == "Steve" ] && [ "$Alter" -eq 15 ] then echo "Wird ausgeführt wenn $NAME gleich 'Steve' UND $Alter gleich 15." fi if [ "$Name" == "Daniya" ] || [ "$Name" == "Zach" ] then echo "Wird ausgeführt wenn $NAME gleich 'Daniya' ODER $NAME gleich 'Zach'." fi # Ausdrücke haben folgendes Format: echo $(( 10 + 5 )) # Anders als andere Programmiersprachen ist Bash eine Shell – es arbeitet also im Kontext von Verzeichnissen. # Du kannst alle Dateien und Verzeichnisse im aktiven Verzeichnis mit ls auflisten: ls # Diese Befehle haben Optionen, die ihre Ausführung beeinflussen: ls -l # Liste alle Dateien und Unterverzeichnisse auf einer eigenen Zeile auf # Ergebnisse eines vorangegangenen Befehls können an den nächsten Befehl als Input übergeben werden. # Der grep-Befehl filtert den Input nach dem vorgegebenen Muster. So können wir alle # txt-Dateien im aktuellen Verzeichnis auflisten: ls -l | grep "\.txt" # Ein- und Ausgabe können umgeleitet werden (stdin, stdout, and stderr). # Von stdin lesen bis "EOF" allein in einer Zeile auftaucht # und die Datei hello.py mit den Zeilen zwischen den beiden "EOF" # überschreiben: cat > hello.py << EOF #!/usr/bin/env python from __future__ import print_function import sys print("#stdout", file=sys.stdout) print("#stderr", file=sys.stderr) for line in sys.stdin: print(line, file=sys.stdout) EOF # Führe hello.py mit verschiedenen Umleitungen von # stdin, stdout und stderr aus: python hello.py < "input.in" python hello.py > "output.out" python hello.py 2> "error.err" python hello.py > "output-and-error.log" 2>&1 python hello.py > /dev/null 2>&1 # Die Fehlerausgabe würde die Datei "error.err" überschreiben (falls sie existiert) # verwende ">>" um stattdessen anzuhängen: python hello.py >> "output.out" 2>> "error.err" # Überschreibe output.out, hänge an error.err an und zähle die Zeilen beider Dateien: info bash 'Basic Shell Features' 'Redirections' > output.out 2>> error.err wc -l output.out error.err # Führe einen Befehl aus und gib dessen "file descriptor" (zB /dev/fd/123) aus # siehe: man fd echo <(echo "#helloworld") # Mehrere Arten, um output.out mit "#helloworld" zu überschreiben: cat > output.out <(echo "#helloworld") echo "#helloworld" > output.out echo "#helloworld" | cat > output.out echo "#helloworld" | tee output.out >/dev/null # Löschen der Hilfsdateien von oberhalb, mit Anzeige der Dateinamen # (mit '-i' für "interactive" erfolgt für jede Datei eine Rückfrage) rm -v output.out error.err output-and-error.log # Die Ausgabe von Befehlen kann mithilfe von $( ) in anderen Befehlen verwendet werden: # Der folgende Befehl zeigt die Anzahl aller Dateien und Unterverzeichnisse # im aktuellen Verzeichnis an. echo "Dieser Ordner beinhaltet $(ls | wc -l) Dateien und Verzeichnisse." # Dasselbe kann man mit "backticks" `` erreichen, aber diese können # nicht verschachtelt werden. $() ist die empfohlene Methode. echo "Dieser Ordner beinhaltet `ls | wc -l` Dateien und Verzeichnisse." # Bash nutzt einen case-Ausdruck, der sich ähnlich wie switch in Java oder C++ verhält. case "$Variable" in # Liste der Fälle, die unterschieden werden sollen 0) echo "Hier ist eine Null." 1) echo "Hier ist eine Eins." *) echo "Das ist etwas anderes." esac # 'for' Schleifen iterieren über die angegebene Zahl von Argumenten: # Der Inhalt von $Variable wird dreimal ausgedruckt. for Variable in {1..3} do echo "$Variable" done # Oder verwende die "traditionelle 'for'-Schleife": for ((a=1; a <= 3; a++)) do echo $a done # Schleifen können auch mit Dateien arbeiten: # 'cat' zeigt zuerst file1 an und dann file2 for Variable in file1 file2 do cat "$Variable" done # .. oder mit der Ausgabe eines Befehls: # Ausgabe des Inhalts jeder Datei, die von 'ls' aufgezählt wird for Output in $(ls) do cat "$Output" done # while Schleife: while [ true ] do echo "Schleifenkörper..." break done # Funktionen definieren # Definition: function foo () { echo "Argumente funktionieren wie bei skripts: $@" echo "Und: $1 $2..." echo "Dies ist eine Funktion" return 0 } # oder einfacher bar () { echo "Auch so kann man Funktionen deklarieren!" return 0 } # Aufruf der Funktion: foo "My name is" $Name # Was du noch lernen könntest: # Ausgabe der letzten 10 Zeilen von file.txt tail -n 10 file.txt # Ausgabe der ersten 10 Zeilen von file.txt head -n 10 file.txt # sortierte Ausgabe von file.txt sort file.txt # Mehrfachzeilen in sortierten Dateien unterdrücken # oder (mit -d) nur diese ausgeben uniq -d file.txt # Ausgabe nur der ersten Spalte (vor dem ersten ',') cut -d ',' -f 1 file.txt # ersetze in file.txt jedes vorkommende 'gut' durch 'super' (versteht regex) sed -i 's/gut/super/g' file.txt # Ausgabe nach stdout aller Zeilen von file.txt, die auf eine regex passen # Im Beispiel: Zeilen, die mit "foo" beginnen und mit "bar" enden grep "^foo.*bar$" file.txt # Mit der Option "-c" wird stattdessen die Anzahl der gefundenen Zeilen ausgegeben grep -c "^foo.*bar$" file.txt # verwende 'fgrep' oder 'grep -F' wenn du buchstäblich nach den Zeichen # suchen willst, ohne sie als regex zu interpretieren fgrep "^foo.*bar$" file.txt # Dokumentation über die in bash eingebauten Befehle # bekommst du mit dem eingebauten Befehl 'help' help help help help for help return help source help . # Das bash-Handbuch liest du mit 'man' apropos bash man 1 bash man bash # Dann gibt es noch das 'info' System (drücke ? um Hilfe angezeigt zu bekommen) apropos info | grep '^info.*(' man info info info info 5 info # info Dokumentation über bash: info bash info bash 'Bash Features' info bash 6 info --apropos bash ``` [Weitere Informationen \(Englisch\)](https://www.gnu.org/software/bash/manual/bashref.html) ================================================ FILE: de/bc.md ================================================ --- contributors: - ["caminsha", "https://github.com/caminsha"] --- ```bc /* Das ist ein mehr- zeiliger Kommentar */ # Das ist ein (einzeiliger) Kommentar (in GNU bc). /*1. Variablen und Kontrollstrukturen*/ num = 45 /* Alle Variablen speichern nur Doubles und es ist nicht möglich String-Konstanten direkt zu speichern */ num = 45; /* Es kann nach jedem Statement ein optionales Semikolon hinzugefügt werden */ /* Blöcke werden mit den Operatoren {} (ähnlich wie in C) bezeichnet */ while(num < 50) { num += 1 /* äquivalent zu num=num+1. a = a Op b ist äquivalent zu a Op= b*/ } /* Ausserdem gibt es ++ (Inkrement) und -- (Dekrement) Operatoren */ /* Es gibt 3 spezielle Variablen: scale: definiert die Anzahl Nachkommastellen ibase: definiert die Basis der Eingabe obase: definiert die Basis der Ausgabe*/ /*Wenn-Bedingungen:*/ hour = read() /*Eingabe einer Zahl*/ if(hour < 12) { /*Operatoren sind genau wie in C*/ print "Guten Morgen\n" /*"print" Gibt Strings oder Variablen mit einem Komma separiert aus.*/ } else if(hour == 12) { print "Hallo\n" /* Escape-Sequenzen starten mit einem \ in einem String. Um Escape-Sequenzen klarer zu machen, ist hier eine vereinfachte Liste, welche in bc funktionieren: \b: Backspace \c: carriage return \n: Zeilenumbruch \t: Tab \\: Backslash*/ } else { /* Standardmässig sind Variablen global. */ thisIsGlobal = 5 /*Variablen können lokal gemacht werden. Benutze das Schlüsselwort "auto" in einer Funktion.*/ } /* Jede Variable hat als Voreinstellung den Wert 0. */ num = blankVariable /*num wurde auf 0 gesetzt.*/ /*Wie in C ist nur 0 falsch.*/ if(!num) {print "false\n"} /*Im Gegensatz zu C hat bc den Ternäroperator ?: nicht. Zum Beispiel führt dieser Codeblock zu einem Fehler: a = (num) ? 1 : 0 Jedoch kann dies simuliert werden:*/ a = (num) && (1) || (0) /*&& ist das UND, || ist das ODER*/ /*For-Schleifen*/ num = 0 for(i = 1; i <= 100; i++) {/*Gleich wie die For-Schleife in C*/ num += i } /*2.Funktionen und Arrays*/ define fac(n) { /*Definiere eine Funktion mit define*/ if(n == 1 || n == 0) { return 1 /*Gebe einen Wert zurück*/ } return n * fac(n - 1) /*Rekursion ist möglich*/ } /*Closures und anonyme Funktionen sind nicht möglich */ num = fac(4) /*24*/ /*Dies ist ein Beispiel von lokalen Variablen.*/ define x(n) { auto x x = 1 return n + x } x(3) /*4*/ print x /*Es stellt sich heraus, dass x ausserhalb der Funktion nicht zugänglich ist.*/ /*Arrays sind äquivalent zu C Arrays.*/ for(i = 0; i <= 3; i++) { a[i] = 1 } /*Greife wie folgt darauf zu:*/ print a[0], " ", a[1], " ", a[2], " ", a[3], "\n" quit /* Füge diese Codezeile hinzu, um sicherzustellen, dass das Programm beendet. Diese Codezeile ist optional.*/ ``` Viel Spass mit diesem einfachen Rechner! (Oder dieser Programmiersprache, um exakt zu sein.) Das ganze Programm wurde in GNU bc geschrieben. Um es auszuführen, benutze ```bc learnbc.bc```. ================================================ FILE: de/bf.md ================================================ --- contributors: - ["Prajit Ramachandran", "http://prajitr.github.io/"] - ["Mathias Bynens", "http://mathiasbynens.be/"] translators: - ["urfuchs", "https://github.com/urfuchs"] filename: brainfuck.bf --- Brainfuck ist eine extrem minimalistische Turing-vollständige Programmiersprache mit lediglich 8 Befehlen. Mit dem [brainfuck-visualizer](http://fatiherikli.github.io/brainfuck-visualizer/) kann Brainfuck im Browser ausprobiert werden. ```bf Alle Zeichen außer "><+-.,[]" (ohne die Klammern) werden ignoriert. Brainfuck besteht aus einem Array mit unendlich vielen Elementen, die alle mit Null initialisiert sind und einem Datenzeiger auf das aktuelle Element. Es gibt acht Befehle: + : Erhöht den Wert an der aktuellen Stelle um Eins. - : Verringert den Wert an der aktuellen Stelle um Eins. > : Bewegt den Zeiger um eine Stelle weiter. < : Bewegt den Zeiger um eine Stelle zurück. . : Gibt den Wert der aktuellen Zelle als ASCII Wert aus (z.B. 65 = 'A'). , : Liest ein einzelnes Zeichen von der Standardeingabe und speichert dessen ASCII Wert in der aktuellen Zelle. [ : Wenn der Wert des aktuellen Elements Null ist, bewege den Zeiger hinter den zugehörigen ]-Befehl. Ansonsten, bewege den Zeiger ein Element weiter. ] : Wenn der Wert des aktuellen Elements Null ist, bewege den Zeiger um eine Stelle weiter. Ansonsten, bewege den Zeiger hinter den zugehörigen [-Befehl. [ und ] bilden eine while-Schleife. Offensichtlich müssen sie paarweise vorkommen. Schauen wir uns einige grundlegende Programme an. ++++++ [ > ++++++++++ < - ] > +++++ . Dieses Programm gibt den Buchstaben 'A' aus. Zunächst erhöht es den Wert der 1. Zelle auf 6. Diese erste Zelle wird für die Schleife verwendet. Danach beginnt das Programm die Schleife ([) und geht vor zu Zelle #2. Es erhöht den Zellwert inkrementell 10 Mal, geht dann zurück zu Zelle #1, und verringert Zelle #1. Diese Schleife wird 6 Mal durchlaufen (nach 6 Durchläufen ist der Wert der Zelle #1 auf 0 reduziert, dadurch wird die Schleife abgebrochen und das Programm hinter dem korrespondierenden ] fortgesetzt). An dieser Stelle befinden wir uns an Zelle #1, die jetzt den Wert 0 hat, während Zelle #2 den Wert 60 hat. Wir gehen vor zu Zelle #2, inkrementieren 5 Mal, bis zum Wert 65, und geben dann den Wert der Zelle #2 aus. 65 ist ein 'A' im ASCII-Zeichensatz, daher wird 'A' am Terminal ausgegeben.. , [ > + < - ] > . Dieses Programm liest ein Zeichen von der Benutzereingabe und schreibt dessen Wert in Zelle #1. Danach beginnt eine Schleife. Rücke vor auf Zelle #2, erhöhe den Wert der Zelle #2, gehe zurück auf Zelle #1, verringere den Wert der Zelle #1. Dies geht so lange bis Zelle #1 den Wert 0 und Zelle #2 den alten Wert aus #1 hat. Da wir am Ende der Schleife bei Zelle #1 sind, gehe vor zu Zelle #2 und gibt den Wert als ASCII Zeichen aus. Beachte bitte, dass die Leerzeichen nur aus Gründen der Lesbarkeit geschrieben werden. Man könnte genauso schreiben: ,[>+<-]>. Versuche herauszufinden, was dieses Programm macht: ,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> Dieses Programm nimmt zwei Zahlen als Eingabe und multipliziert sie. Im Wesentlichen liest es zunächst zwei Werte ein. Dann beginnt die äußere Schleife mit Zelle #1 als Zähler. Danach geht das Programm zu Zelle #2 vor und startet die innere Schleife mit Zelle #2 als Zähler. Diese zählt Zelle #3 hoch. Es gibt jedoch ein Problem: Am Ende der inneren Schleife hat Zelle #2 den Wert Null. Daher würde die innere Schleife beim nächsten Durchgang nicht mehr funktionieren. Daher wird auch Zelle #4 erhöht und anschließend in Zelle #2 zurückkopiert. Am Ende steht in Zelle #3 das Ergebnis. ``` Das ist Brainfuck. Nicht so schwierig, oder? Zum Spaß kannst du dein eigenes Brainfuck Programm schreiben oder du schreibst einen Brainfuck-Interpreter in einer anderen Programmiersprache. Der Interpreter lässt sich ziemlich einfach implementieren. Falls du Masochist bist, kannst du auch versuchen, einen Brainfuck-Interpreter in Brainfuck zu implementieren. ================================================ FILE: de/c++.md ================================================ --- contributors: - ["Steven Basart", "http://github.com/xksteven"] - ["Matt Kline", "https://github.com/mrkline"] - ["Geoff Liu", "http://geoffliu.me"] - ["Connor Waters", "http://github.com/connorwaters"] - ["Ankush Goyal", "http://github.com/ankushg07"] - ["Jatin Dhankhar", "https://github.com/jatindhankhar"] - ["Maximilian Sonnenburg", "https://github.com/LamdaLamdaLamda"] - ["caminsha", "https://github.com/caminsha"] --- C++ ist eine Systemprogrammiersprache die, [laut dem Begründer Bjarne Stroustrup](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote) entworfen wurde um, - "besseres C" zu sein - Datenabstraktion zu unterstützen - Objektorientierung zu unterstützen - generische Programmierung zu unterstützen Durch seine Syntax kann sie durchaus schwieriger und komplexer als neuere Sprachen sein. Sie ist weit verbreitet, weil sie in Maschinen-Code kompiliert, welcher direkt vom Prozessor ausgeführt werden kann und somit eine strikte Kontrolle über die Hardware bietet und gleichzeitig High-Level-Features wie generics, exceptions und Klassen enthält. Diese Kombination aus Geschwindigkeit und Funktionalität bildet C++ und ist eine der weitverbreitesten Programmiersprachen. ```c++ ////////////////// // Vergleich zu C ////////////////// // C ist fast eine Untermenge von C++ und teilt sich grundsätzlich die // Syntax für Variablen Deklarationen, primitiven Typen und Funktionen. // Wie in C ist der Programmeinsprungpunkt eine Funktion, welche "main" genannt wird und // einen Integer als Rückgabetyp besitzt. // Dieser Wert fungiert als Beendigungsstatus des Programms. // Siehe: https://de.wikipedia.org/wiki/Return_Code für weitere Informationen int main(int argc, char** argv) { // Kommandozeilen Argumente werden genauso wie in C über argc und argv übergeben // argc entspricht der Anzahl von Argumenten und argv ist ein Array von C-style // strings (char*), welche die Argumente repräsentieren. // Das erste Argument ist der Name des Programms, welches aufgerufen wird. // Argc und argv können, wenn nicht benötigt, weg gelassen werden, indem // die Funktionssignatur "int main()" verwendet wird. // Ein Rückgabewert von 0 repräsentiert die erfolgreiche Ausführung. return 0; } // C++ unterscheidet sich in einigen Punkten von C: // In C++ sind Zeichen-Literale char´s sizeof('c') == sizeof(char) == 1 // In C sind Zeichen-Literale int´s sizeof('c') == sizeof(int) // C++ verwendet striktes prototyping void func(); // Funktion ohne Argumente // In C void func(); // Funktion mit beliebiger Anzahl von Argumenten // Verwende nullptr, anstatt von NULL!!! int* ip = nullptr; // C standard header sind in C++ verfügbar. // C header enden mit .h, während // C++ header das Präfix "c" besitzen und kein ".h" Suffix verwenden. // Die C++ Standard Version: #include // Die C Standard Version: #include int main() { printf("Hello, world!\n"); return 0; } /////////////////////// // Funktionsüberladung /////////////////////// // C++ unterstützt Funktionsüberladung // Jede Funktion kann unterschiedliche Parameter erhalten. void print(char const* myString) { printf("String %s\n", myString); } void print(int myInt) { printf("My int is %d", myInt); } int main() { print("Hello"); // Wird aufgelöst zu "void print(const char*)" print(15); // Wird aufgelöst zu "void print(int)" } ///////////////////////////// // Standard Funktionsargumente ///////////////////////////// // Argumente können per Standard für eine Funktion gesetzt werden, // wenn diese beim Aufruf nicht bereitgestellt werden. void doSomethingWithInts(int a = 1, int b = 4) { // führe Anweisungen mit "int´s" aus. } int main() { doSomethingWithInts(); // a = 1, b = 4 doSomethingWithInts(20); // a = 20, b = 4 doSomethingWithInts(20, 5); // a = 20, b = 5 } // Standard-Argumente müssen am Ende der Liste der Argumente stehen. void invalidDeclaration(int a = 1, int b) // Fehler! { } ///////////// // Namespaces (Namensräume) ///////////// // Namespaces stellen einen getrennten Gültigkeitsbereich für Variablen, // Funktionen und andere Deklarationen zur Verfügung. // Namespaces können geschachtelt werden. namespace First { namespace Nested { void foo() { printf("This is First::Nested::foo\n"); } } // Ende des Namespace "Nested" } // Ende des Namespace "First" namespace Second { void foo() { printf("This is Second::foo\n"); } } void foo() { printf("This is global foo\n"); } int main() { // Fügt alle Symbole aus dem namespace Second in den aktuellen Gültigkeitsbereich (scope). // "foo()" wird nun nicht länger funktionieren, da es nun doppeldeutig ist, ob foo aus // dem namespace foo oder darüberliegenden aufgerufen wird. using namespace Second; Second::foo(); // Gibt "This is Second::foo" aus. First::Nested::foo(); // Gibt "This is First::Nested::foo" aus. ::foo(); // Gibt "This is global foo" aus. } /////////////// // Eingabe/Ausgabe /////////////// // C++ verwendet für die Eingabe und Ausgabe streams. // cin, cout und cerr repräsentieren stdin, stdout und stderr. // << ist der Einfügeoperator und >> ist der Extraktionsoperator. #include // Include für Eingabe/Ausgabe (I/O) streams using namespace std; // Streams befinden sich im std namespace (standard library) int main() { int myInt; // Ausgabe auf stdout (oder Terminal/Bildschirm) cout << "Enter your favorite number:\n"; // Empfängt Eingabe cin >> myInt; // cout kann ebenfalls formatiert werden cout << "Your favorite number is " << myInt << "\n"; // Gibt "Your favorite number is " aus cerr << "Used for error messages"; } ////////// // Zeichenketten (Strings) ////////// // Strings in C++ sind Objekte und haben diverse member-functions #include using namespace std; // Strings sind ebenfalls im namespace std (Standard Bibliothek) string myString = "Hello"; string myOtherString = " World"; // + wird für das Anhängen von strings verwendet. cout << myString + myOtherString; // "Hello World" cout << myString + " You"; // "Hello You" // C++ strings sind mutable. myString.append(" Dog"); cout << myString; // "Hello Dog" ///////////// // Referenzen ///////////// // Zusätzlich zu Pointern, wie jene in C. // C++ besitzt _Referenzen_. // Diese sind Pointer-Typen, welche nicht erneut zugewiesen werden können // und nicht Null sein können. // Sie besitzen den selben Syntax wie Variablen. // Für die Dereferenzierung ist kein * notwendig und // & (die Adresse) wird nicht für die Zuweisung verwendet. using namespace std; string foo = "I am foo"; string bar = "I am bar"; string& fooRef = foo; // Erzeugt eine Referenz auf foo. fooRef += ". Hi!"; // Verändert foo durch die Referenz cout << fooRef; // Gibt "I am foo. Hi!" aus. // Weist "fooRef" nicht erneut zu. Dies ist dasselbe, wie "foo = bar" und // foo == "I am bar" // nach dieser Zeile cout << &fooRef << endl; // Gibt die Adresse von foo aus fooRef = bar; cout << &fooRef << endl; // Gibt ebenfalls die Adresse von foo aus cout << fooRef; // Gibt "I am bar" aus // Die Adresse von fooRef verbleibt die selbe, sie verweist immer noch auf foo const string& barRef = bar; // Erzeugt konstante Referenz auf bar. // Wie in C, können konstante Werte ( und Pointer bzw. Referenzen) nicht verändert werden. barRef += ". Hi!"; // Fehler: konstante Referenzen können nicht verändert werden. // Hinweis: bevor wir genauer Referenzen besprechen, schauen wir uns zuerst ein Konzept an, // welches als "temporäres Objekt" bezeichnet wird. Gehen wir von folgenden Code aus: string tempObjectFun() { ... } string retVal = tempObjectFun(); // Was passiert nun in der zweiten Zeile: // - ein String Objekt wird von "tempObjectFun" zurückgegeben // - ein neuer String wird mit dem zurückgegebenen Objekt als Argument für den Konstruktor erzeugt. // - das zurückgegebene Objekt wird zerstört // Das zurückgegebene Objekt wird temporäres Objekt genannt. Temporäre Objekte werden erzeugt // wann immer eine Funktion ein Objekt zurückgibt. Zerstört werden diese am Ende der Auswertung des Ausdrucks // (dies schreibt der Standard vor, aber Compiler sind berechtigt dieses Verhalten zu ändern. Siehe "return value optimization" // für Details). Wie in diesem Code: foo(bar(tempObjectFun())) // Nehmen wir an, foo und bar existieren. Das Objekt wird von "tempObjectFun" zurückgegeben, // wird an bar übergeben und ist zerstört bevor foo aufgerufen wird. // Zurück zu Referenzen. Die Annahme, dass die "am Ende des Ausdrucks" Regel gültig ist, // wenn das temporäre Objekt an eine konstante Referenz gebunden ist, ist der Fall, wenn die Lebensdauer // auf den aktuellen Gültigkeitsbereich erweitert wird. void constReferenceTempObjectFun() { // constRef erhält das temporäre Objekt und ist gültig bis ans Ende der Funktion const string& constRef = tempObjectFun(); ... } // Eine andere Art von Referenzen wurde in C++11 eingeführt und ist speziell für // temporäre Objekte. Es ist nicht möglich Variablen des Typs zu besitzen, aber // Vorrechte bei der Auflösung zu besitzen. void someFun(string& s) { ... } // Reguläre Referenz void someFun(string&& s) { ... } // Referenz auf ein temporäres Objekt string foo; someFun(foo); // Ruft die Funktion mit der regulären Referenz auf someFun(tempObjectFun()); // Ruft die Funktion mit der temporären Referenz auf // Zum Beispiel existieren diese zwei Varianten von Konstruktoren für // std::basic_string: basic_string(const basic_string& other); basic_string(basic_string&& other); // Nehmen wir an, wir erzeugen einen neuen String eines temporären Objekts (welches später // zerstört wird), hierbei existiert ein effizienterer Konstruktor. Dieses Konzept wird // als "move semantics" bezeichnet (bewegen eines Objekts in ein anderes in C++). ///////////////////// // Enumerations (Aufzählungstypen) ///////////////////// // Enums sind eine einfachere Art und Weise einen Wert einer Konstante zu zuweisen. // Häufig wird dies verwendet, um den Code lesbarer zu gestalten bzw. zu visualisieren. enum ECarTypes { Sedan, Hatchback, SUV, Wagon }; ECarTypes GetPreferredCarType() { return ECarTypes::Hatchback; } // Mit C++11 existiert eine einfache Möglichkeit einem Typ dem Enum zuzuweisen. Dies // kann durchaus sinnvoll bei der Serialisierung von Daten sein, oder bei der Konvertierung // zwischen Typen bzw. Konstanten. enum ECarTypes : uint8_t { Sedan, // 0 Hatchback, // 1 SUV = 254, // 254 Hybrid // 255 }; void WriteByteToFile(uint8_t InputValue) { // Serialisierung von "InputValue" in eine Datei } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { // Das enum wird implizit zu einem "uint8_t" konvertiert. Bedingt dadurch, dass // es sich um ein "enum" handelt. WriteByteToFile(InputCarType); } // Nicht immer ist es gewünscht, dass enum´s zu einem Integer oder zu einem anderen // enum umgewandelt werden. Daher ist es möglich eine enum-Klasse zu erzeugen, welche // nicht implizit umgewandelt wird. enum class ECarTypes : uint8_t { Sedan, // 0 Hatchback, // 1 SUV = 254, // 254 Hybrid // 255 }; void WriteByteToFile(uint8_t InputValue) { // Serialisierung von InputValue in eine Datei } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { // Wird nicht kompilieren, da "ECarTypes" ein "uint8_t" ist, da das enum // als "enum class" deklariert wurde! WriteByteToFile(InputCarType); } ////////////////////////////////////////// // Klassen und objekorientierte Programmierung ////////////////////////////////////////// // Erstes Beispiel einer Klasse #include // Deklaration einer Klasse. // Klassen werden üblicherweise im header (.h oder .hpp) deklariert. class Dog { // Member Variablen und Funktionen sind private per default (standard). std::string name; int weight; // Alle nachfolgenden member sind "public" bis // "private:" oder "protected:" auftritt. public: // Standard Konstruktor Dog(); // Member-Funktionsdeklaration (Implementierung folgt). // Bemerkung: std::string statt der Verwendung von namespace std; // "using namespace" sollte niemals in einem header verwendet werden. void setName(const std::string& dogsName); void setWeight(int dogsWeight); // Funktionen, die Objekte nicht ändern, sollten mit const deklariert werden. // Funktionen müssen explizit als "virtual" deklariert werden, um in einer // abgeleiteten Klassen überschrieben zu werden. // Aus performance Gründen sind Funktionen nicht per default virtual. virtual void print() const; // Funktionen können ebenfalls im class body definiert werden. // Derart definierte Funktionen sind automatisch "inline". void bark() const { std::cout << name << " barks!\n"; } // Neben Konstruktoren, bietet C++ Destruktoren. // Diese werden aufgerufen, wenn ein Objekt freigegeben wird oder // seinen Wertebereich verlässt. // Dies ermöglicht mächtige Paradigmen, wie auch RAII. // Destruktoren sollten virtual sein, wenn eine Klasse von ihr // abgeleitet wird. Ist dieser nicht virtual, dann wird der // Destruktor der abgeleiteten Klasse nicht aufgerufen, insofern // das Objekt durch eine Referenz/Pointer der Basisklasse entfernt wird. virtual ~Dog(); }; // Ein Semikolon schließt die Definition der Klasse ab. // Klassen-Member-Funktionen sind üblicherweise in der .cpp Datei implementiert. Dog::Dog() { std::cout << "A dog has been constructed\n"; } // Objekte sollten als Referenz übergeben werden und wenn diese nicht // verändert werden sollen, sollte das Objekt als const Referenz übergeben werden. void Dog::setName(const std::string& dogsName) { name = dogsName; } void Dog::setWeight(int dogsWeight) { weight = dogsWeight; } // "Virtual" wird nur bei der Deklaration benötigt und nicht bei der Definition. void Dog::print() const { std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; } Dog::~Dog() { std::cout << "Goodbye " << name << "\n"; } int main() { Dog myDog; // Ausgabe: "A dog has been constructed" myDog.setName("Barkley"); myDog.setWeight(10); myDog.print(); // Ausgabe: "Dog is Barkley and weighs 10 kg" return 0; } // Ausgabe: "Goodbye Barkley" // Diese Klasse erbt alles was public bzw. protected ist von der Dog-Klasse // und darüber hinaus auch private Methoden/Attribute, jedoch kann auf diese // nicht direkt zugegriffen werden. Lediglich über public/procted getter/setter. class OwnedDog : public Dog { public: void setOwner(const std::string& dogsOwner); // Überschreibt das Verhalten der "print" Funktion für alle "OwnedDogs". // Siehe: http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping // für eine grundlegende Einführung in "Subtype Polymorphismus". // Das "override" Schlüsselwort ist optional, aber stellt sicher, dass die // Methode der Basisklasse tatsächlich überschrieben wurde. void print() const override; private: std::string owner; }; // Die zugehörige .cpp Datei void OwnedDog::setOwner(const std::string& dogsOwner) { owner = dogsOwner; } void OwnedDog::print() const { Dog::print(); // Ruft die "print" Funktion der Basisklasse auf. std::cout << "Dog is owned by " << owner << "\n"; // Ausgaben: "Dog is and weights " // "Dog is owned by " } ////////////////////////////////////////// // Initialisierung und Operatorüberladung ////////////////////////////////////////// // In C++ können Operatoren wie: +, -, *, / etc. überladen werden. // Dies wird umgesetzt, indem eine entsprechende Funktion definiert wird, // welche immer dann aufgerufen wird, sobald der Operator verwendet wird. #include using namespace std; class Point { public: // Member Variablen können mit einem default Wert initialisiert werden. double x = 0; double y = 0; // Definition des Standard Konstruktor, welcher nichts tut // außer den Punkt auf den default Wert (0,0) zu setzen. Point() { }; // Die nachfolgende Syntax ist bekannt als "initialization list" // und ist eine gängige Art Klassen-Member zu initialisieren. Point (double a, double b) : x(a), y(b) { /* Ausschließliche Initialisierung der Werte */ } // Überladung des "+" Operator. Point operator+(const Point& rhs) const; // Überladung des "+=" Operator Point& operator+=(const Point& rhs); // Sinnhaft wäre es an dieser Stelle den "-" und "-=" Operator // ebenfalls zu überladen. }; Point Point::operator+(const Point& rhs) const { // Erzeugung eines neuen Punkts, welcher die Summe aus sich // selbst und "rhs" bildet return Point(x + rhs.x, y + rhs.y); } Point& Point::operator+=(const Point& rhs) { x += rhs.x; y += rhs.y; return *this; } int main () { Point up (0,1); Point right (1,0); // Ruft den + Operator mit den entsprechenden Parametern auf. Point result = up + right; // Ausgabe: "Result is upright (1,1)" cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; return 0; } ///////////////////// // Templates ///////////////////// // Templates in C++ werden in erster Linie dafür verwendet generisch zu programmieren. // Sie unterstützen explizite und partielle Spezialisierung und darüber hinaus können // sie für funktionale Klassen verwendet werden. // Tatsächlich bilden Templates die Turing-Vollständigkeit // (universelle Programmierbarkeit) ab. // Zu Beginn ein einführendes Beispiel der generischen Programmierung. // Die Definition einer Klasse bzw. Funktion, welche mit dem Typ T parametriert wird. template class Box { public: // T repräsentiert an dieser Stelle einen beliebigen Typen. void insert(const T&) { ... } }; // Während der Kompilierung generiert der Compiler Kopien für jedes Template, wobei // hierbei die Parameter substituiert werden. Somit muss bei jedem Aufruf die gesamte // Definition der Klasse zur Verfügung stehen. Aus diesem Grund wird ein Template // komplett im header definiert. // Erzeugung einer Template-Klasse auf dem Stack: Box intBox; // eine der zu erwartenden Verwendungen: intBox.insert(123); // Verschachtelungen von Templates sind möglich. Box > boxOfBox; boxOfBox.insert(intBox); // Bis C++11 war es erforderlich ein Leerzeichen zwischen '>' einzufügen, // andernfalls wurde es als '>>' geparsed (right shift). // Manchmal ist folgende Notation anzutreffen: // template // Das 'class' Schlüsselwort und das 'typename' Schlüsselwort // sind fast identisch hinsichtlich der Funktionalität. Weitere // Informationen auf: http://en.wikipedia.org/wiki/Typename // Eine Template-Funktion: template void barkThreeTimes(const T& input) { input.bark(); input.bark(); input.bark(); } // Hierbei ist zu beachten, dass an dieser Stelle nichts über den Typen des Parameters // definiert wurde. Der Compiler wird bei jedem Aufruf bzw. jeder Erzeugung den Typen // prüfen. Somit funktioniert die zuvor definierte Funktion für jeden Typ 'T', die die // const Methode 'bark' implementiert hat. Dog fluffy; fluffy.setName("Fluffy") barkThreeTimes(fluffy); // Gibt "Fluffy barks" dreimal aus. // Template Parameter müssen keine Klassen sein. template void printMessage() { cout << "Learn C++ in " << Y << " minutes!" << endl; } // Des Weiteren können Templates aus Effizienzgründen genauer spezifiziert werden. // Selbstverständlich sind reale Probleme, welche genauer spezifiziert werden, nicht // derart trivial. Auch wenn alle Parameter explizit definiert wurden, muss die // Funktion oder Klasse als Template deklariert werden. template<> void printMessage<10>() { cout << "Learn C++ faster in only 10 minutes!" << endl; } printMessage<20>(); // Gibt "Learn C++ in 20 minutes!" aus. printMessage<10>(); // Gibt "Learn C++ faster in only 10 minutes!" aus. ///////////////////// // Ausnahme Behandlungen (Exception-Handling) ///////////////////// // Die Standard Bibliothek bietet einige exceptions. // Siehe: http://en.cppreference.com/w/cpp/error/exception. // Grundsätzlich können alle Typen als exception geworfen werden. #include #include // Alle exceptions, die in dem "try" Block geworfen werden, können mittels // "catch" abgefangen werden. try { // exceptions sollten nicht auf dem heap mithilfe // von "new" allokiert werden. throw std::runtime_error("A problem occurred"); } // Exceptions sollten als const Referenz abgefangen werden // insofern diese Objekte sind. catch (const std::exception& ex) { std::cout << ex.what(); } // Abfangen aller Exceptions, welche zuvor nicht abgefangen wurden. catch (...) { std::cout << "Unknown exception caught"; throw; // Erneutes werfen der exception } /////// // RAII /////// // RAII steht für "Resource Acquisition Is Initialization". // Oft wird dies als eines der wichtigsten Paradigmen in C++ betrachtet. // RAII beschreibt das Konzept, dass der Konstruktor für ein Objekt // die Ressourcen akquiriert und der Destruktor diese freigibt. // Zum Verständnis, warum dies sinnvoll ist, nachfolgend // ein einführendes Beispiel: void doSomethingWithAFile(const char* filename) { // Wir nehmen an, dass nichts schiefgehen wird. FILE* fh = fopen(filename, "r"); // Öffnen der Datei im read-mode. doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); fclose(fh); // Schließen des file-handle. } // Unglücklicherweise ist die Fehlerbehandlung äußerst kompliziert. // Sollte fopen fehlschlagen und "doSomethingWithTheFile" bzw. // "doSomethingElseWithIt", geben diese einen Fehlercode zurück. // (Exceptions sind eine bevorzugte Möglichkeit Fehler abzufangen // , allerdings bei einigen Programmierern, besonders solchen die einen C // background besitzen, ein unbeliebtes Mittel zur Fehlerbehandlung). // Nun müssen wir jeden Aufruf auf mögliche auftretende Fehler überprüfen. bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Öffnet die Datei im read-mode if (fh == nullptr) // Der Pointer ist bei einem Fehler NULL . return false; // Benachrichtigt den Aufrufer über den Fehler. // Wir nehmen an, dass jede Funktion false zurückgibt, in einem Fehlerfall if (!doSomethingWithTheFile(fh)) { fclose(fh); // File handle schließen. return false; // Fehler "melden". } if (!doSomethingElseWithIt(fh)) { fclose(fh); // File handle schließen. return false; // Fehler "melden". } fclose(fh); // File handle schließen. return true; // Erfolg "melden". } // C-Programmierer handhaben dies häufig durch goto-Anweisungen: bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); if (fh == nullptr) return false; if (!doSomethingWithTheFile(fh)) goto failure; if (!doSomethingElseWithIt(fh)) goto failure; fclose(fh); // File handle schließen. return true; // Erfolg "melden". failure: fclose(fh); return false; // Fehler "melden". } // Insofern Funktionen Fehler durch exceptions indizieren, // ist dies "sauberer", aber immer noch suboptimal. void doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Öffnet die Datei im read-mode if (fh == nullptr) throw std::runtime_error("Could not open the file."); try { doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } catch (...) { // Im Fehlerfall sollte sichergestellt sein, dass die // Datei geschlossen wird. fclose(fh); throw; // Erneutes werfen der exception } fclose(fh); // Schließen der Datei } // Folgendes ist mit der C++ file stream Klasse (fstream) zu vergleichen. // fstream verwendet den Destruktor, um die Datei zu schließen. // Der obige Destruktor wird automatisch aufgerufen, sobald das Objekt // den Gültigkeitsbereich verlässt. void doSomethingWithAFile(const std::string& filename) { // ifstream entspricht der Kurzform von "input file stream". std::ifstream fh(filename); // Öffnen der Datei doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } // Die Datei wird automatisch vom Destruktor geschlossen. // Diese Vorgehensweise bietet massive Vorteile: // 1. Egal was passiert, die Ressource (das Datei-Handle) wird aufgelöst, // insofern der Destruktor korrekt beschrieben wurde. Es ist möglich // zu vergessen das Datei-Handle zu schließen, was zu einem "leak" der // entsprechenden Ressource führt. // 2. Der Code selbst ist wesentlich "sauberer". // Der Destruktor wird das Datei-Handle im Hintergrund schließen und der // Programmierer muss sich darum keinerlei Sorgen machen. // 3. Der Code ist "exception sicher". // Egal wo die exception geworfen wird, das Aufräumen wird definitiv vollzogen. // Der gesamte idiomatische C++ Code verwendet RAII für alle Ressourcen. // Weitere Beispiele: // - Speicher verwenden "unique_ptr" und "shared_ptr". // - Container - verkettete Listen (linked list), vector (selbst organisierende // Arrays), hash maps, etc., entfernen deren Inhalt, wenn diese außerhalb des // Gültigkeitsbereichs laufen. // - Mutex´s verwenden lock_guard und unique_lock. ///////////////////// // Container ///////////////////// // Die Container der Standard template Bibliothek beinhaltet einige vordefinierte Templates. // Diese verwalten die Speicherbereiche für die eigenen Elemente und stellen Member-Funktionen // für den Zugriff und die Manipulation bereit. // Beispielhafte Container: // Vector (dynamisches array) // Erlaubt das Definieren von Arrays oder Listen zur Laufzeit #include string val; vector my_vector; // Initialisierung des Vectors. cin >> val; my_vector.push_back(val); // Fügt den Wert "val" zum Vektor "my_vector" hinzu. my_vector.push_back(val); // Fügt den Wert "val" zum Vektor "my_vector" hinzu (nun zwei Elemente). // Für die Iteration über Vektoren stehen zwei Methodiken zu Verfügung: // Entweder die klassische Iteration über den Index: for (int i = 0; i < my_vector.size(); i++) { cout << my_vector[i] << endl; // Zugriff auf die Elemente des Vektors über den [] Operator } // Oder die Verwendung von Iteratoren: vector::iterator it; // Initialisierung des Iterators. for (it = my_vector.begin(); it != my_vector.end(); ++it) { cout << *it << endl; } // Set (Mengen) // Sets sind Container, welche einzigartige Elemente beinhalten die einer // spezifischen Ordnung folgen. #include set ST; // Initialisierung des Sets mit einem Integer Datentyp. ST.insert(30); // Einfügen des Werts 30 in das Set ST ST.insert(10); // Einfügen des Werts 10 in das Set ST ST.insert(20); // Einfügen des Werts 20 in das Set ST ST.insert(30); // Einfügen des Werts 30 in das Set ST // Folgende Elemente befinden sich nun in dem Set: // 10 20 30 // Entfernen eines Elements: ST.erase(20); // Set ST: 10 30 // Für das iterieren verwenden wir Iteratoren: set::iterator it; for(it=ST.begin();it map mymap; // Initialisierung der Map: char -> Key, int -> Value. mymap.insert(pair('A',1)); // Einfügen des Werts "1" für den Key "A". mymap.insert(pair('Z',26)); // Einfügen des Werts "26" für den Key "Z". // Das Iterieren über Maps: map::iterator it; for (it=mymap.begin(); it!=mymap.end(); ++it) std::cout << it->first << "->" << it->second << '\n'; // Ausgabe: // A->1 // Z->26 // Für das Finden des dazugehörigen Value des Keys. it = mymap.find('Z'); cout << it->second; // Ausgabe: 26 // Bemerkung: für "hash maps" sollten die "unordered_map´s" verwendet werden. Diese // sind effizienter und benötigen keine Reihenfolge. "unordered_maps" sind ab // C++11 verfügbar. // Container für nicht-primitive Datentypen benötigen Vergleichsfunktionen im Objekt selbst, // oder als Funktionspointer. Primitive Datentypen besitzen default-Vergleichsfunktionen. // Allerdings können diese überschrieben werden. class Foo { public: int j; Foo(int a) : j(a) {} }; struct compareFunction { bool operator()(const Foo& a, const Foo& b) const { return a.j < b.j; } }; // Folgender Code ist nicht valide, könnte aber von einigen Compilern // als valide angesehen werden: // std::map fooMap; std::map fooMap; fooMap[Foo(1)] = 1; fooMap.find(Foo(1)); // Wahr /////////////////////////////////////// // Lambda Ausdrücke (C++11 und höher) /////////////////////////////////////// // Lambdas sind eine gängige Methodik, um anonyme Funktionen an dem // Ort der Verwendung zu definieren. Darüber hinaus auch bei der // Verwendung von Funktionen als Argument einer Funktion. // Nehmen wir an, es soll ein Vektor von "pairs" (Paaren) mithilfe // des zweiten Werts des "pairs" sortiert werden. vector > tester; tester.push_back(make_pair(3, 6)); tester.push_back(make_pair(1, 9)); tester.push_back(make_pair(5, 0)); // Übergabe des Lambda-Ausdrucks als drittes Argument für die nachfolgende Sortierfunktion. sort(tester.begin(), tester.end(), [](const pair& lhs, const pair& rhs) { return lhs.second < rhs.second; }); // Beachte die Syntax von Lambda-Ausdrücken. // Die [] im Lambda Ausdruck werden für die Variablen verwendet. // Diese so genannte "capture list" definiert, was außerhalb des Lambdas, // innerhalb der Funktion verfügbar sein soll und in welcher Form. // Dies kann folgendes sein: // 1. ein Wert [x] // 2. eine Referenz [&x] // 3. eine beliebige Variable, welche sich im Gültigkeitsbereich durch // die Referenz [&] befindet. // 4. wie bei 3. aber mithilfe des Werts [=] // Beispiel: vector dog_ids; for(int i = 0; i < 3; i++) { dog_ids.push_back(i); } int weight[3] = {30, 50, 10}; // Nehmen wir an wir möchten die "dog_ids" gemäß des Gewichts des Hundes sortieren. // So sollten sich die "dog_ids" wie folgt verhalten: [2, 0, 1] // Hier werden Lambdas praktisch: sort(dog_ids.begin(), dog_ids.end(), [&weight](const int &lhs, const int &rhs) { return weight[lhs] < weight[rhs]; }); // Weiterführender Link über Lambda-Ausdrücke: // http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11 /////////////////////////////// // Range For (C++11 und höher) /////////////////////////////// // Range-For Schleifen können verwendet werden, um über Container zu iterieren. int arr[] = {1, 10, 3}; for(int elem: arr) { cout << elem << endl; } // Insofern "auto" verwendet wird, muss der Typ nicht weiter beachtet werden. for(auto elem: arr) { // Anweisungen ... } ///////////////////// // Weiteres: ///////////////////// // Einige Aspekte von C++ sind für Neueinsteiger häufig überraschend (aber auch für // C++ Veteranen). // Der nachfolgende Abschnitt ist leider nicht vollständig: // C++ ist eine der Sprachen, bei der es ein Leichtes ist, sich selbst ins Bein zu schießen. // Private-Methoden können überschrieben werden class Foo { virtual void bar(); }; class FooSub : public Foo { virtual void bar(); // Überschreibt Foo::bar! }; // 0 == false == NULL bool* pt = new bool; *pt = 0; // Setzt den Wert des Pointers 'pt' auf false. pt = 0; // Setzt 'pt' auf den "null-pointer". Keine Compiler-Warnung. // nullptr sollte dieses Problem nicht lösen: int* pt2 = new int; *pt2 = nullptr; // Kompiliert nicht. pt2 = nullptr; // Setzt pt2 auf null. // Eine Ausnahme bilden bool´s. // Dies erlaubt es "null-pointer" zu testen: if(!ptr) // Die Konsequenz ist jedoch, dass dem nullptr ein bool zugewiesen werden kann. *pt = nullptr; // Kompiliert auch, wenn '*pt' ein bool ist! // '=' != '=' != '='! // Ruft Foo::Foo(const Foo&) auf, oder den Kopierkonstruktor Foo f2; Foo f1 = f2; // Ruft Foo::Foo(const Foo&) auf, aber kopiert lediglich den "Foo" Teil von // "fooSub". Alle zusätzlichen Member werden verworfen. Diese eigenartige Verhalten // wird auch "object slicing" genannt. FooSub fooSub; Foo f1 = fooSub; // Ruft Foo::operator=(Foo&) oder eine andere Variante auf. Foo f1; f1 = f2; /////////////////////////////////////// // Tuple (C++11 und höher) /////////////////////////////////////// #include // Konzeptionell sind Tupel alten Datenstrukturen sehr ähnlich, allerdings haben diese keine // bezeichneten Daten-Member, sondern werden durch die Reihenfolge angesprochen. // Erstellen des Tupels und das Einfügen eines Werts. auto first = make_tuple(10, 'A'); const int maxN = 1e9; const int maxL = 15; auto second = make_tuple(maxN, maxL); // Ausgabe der Elemente des "first" Tuple. cout << get<0>(first) << " " << get<1>(first) << "\n"; // Ausgabe : 10 A // Ausgabe der Elemente des "second" Tuple. cout << get<0>(second) << " " << get<1>(second) << "\n"; // Ausgabe: 1000000000 15 int first_int; char first_char; tie(first_int, first_char) = first; cout << first_int << " " << first_char << "\n"; // Ausgabe : 10 A // Tuple können auch wie folgt erzeugt werden: tuple third(11, 'A', 3.14141); // tuple_size gibt die Anzahl der Elemente in einem Tuple zurück. // Als "constexpr". cout << tuple_size::value << "\n"; // prints: 3 // tuple_cat fügt die Elemente eines Tupels aneinander (in der selben Reihenfolge). auto concatenated_tuple = tuple_cat(first, second, third); // concatenated_tuple wird zu = (10, 'A', 1e9, 15, 11, 'A', 3.14141) cout << get<0>(concatenated_tuple) << "\n"; // Ausgabe: 10 cout << get<3>(concatenated_tuple) << "\n"; // Ausgabe: 15 cout << get<5>(concatenated_tuple) << "\n"; // Ausgabe: 'A' /////////////////////////////////// // Logische- und Bitoperatoren ////////////////////////////////// // Die meisten Operatoren in C++ entsprechen denen aus anderen Sprachen // Logische Operatoren. // C++ verwendet so genannte "Short-circuit" Evaluierung für Boolean-Ausdrücke. // Das zweite Argument wird ausgeführt bzw. evaluiert, wenn das erste Argument genügt, // um den Ausdruck zu bestimmen. true && false // Führt **logisches und** aus. true || false // Führt **logisches oder** aus. ! true // Führt **logisches nicht** aus. // Anstelle von Symbolen können auch Schlüsselwörter verwendet werden. true and false // Führt **logisches und** aus. true or false // Führt **logisches oder** aus. not true // Führt **logisches nicht** aus. // Bitoperationen // **<<** Links-Shift // **>>** Rechts-Shift ~4 // Führt bitweises nicht aus. 4 | 3 // Führt bitweises oder aus. 4 & 3 // Führt bitweises und aus. 4 ^ 3 // Führt bitweises xor aus. // Gleichwertige Schlüsselwörter: compl 4 // Führt bitweises nicht aus. 4 bitor 3 // Führt bitweises oder aus. 4 bitand 3 // Führt bitweises und aus. 4 xor 3 // Führt bitweises xor aus. ``` Weiterführende Literatur: * Aktuelle Sprachen-Referenz [CPP Reference](http://cppreference.com/w/cpp). * Zusätzliches: [CPlusPlus](http://cplusplus.com). * Grundlagen Tutorial: [TheChernoProject - C++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb). ================================================ FILE: de/c.md ================================================ --- contributors: - ["caminsha", "https://github.com/caminsha"] --- Ach, C. Immer noch **die** Sprache für modernes High-Performance Computing. C ist wahrscheinlich die Programmiersprache mit dem niedrigsten Abstraktionsniveau, welche die meisten Programmierer je brauchen werden. Die Geschwindigkeit von C ist enorm, allerdings muss man sich stets der manuellen Speicherverwaltung bewusst sein. ```c // einzeilige Kommentare starten mit // - nur in C99 und später vorhanden. /* mehrzeilige Kommentare sehen so aus. Diese funktionieren auch in C89 */ /* mehrzeilige Kommentare können nicht verschachtelt werden /* Sei Vorsichtig! */ // Kommentar endet auf dieser Linie ... */ // ... nicht bei dieser! // Konstanten: #define // Konstanten werden laut der Konvention immer in GROSSBUCHSTABEN geschrieben #define DAYS_IN_YEAR 365 // Konstanten können auch als Aufzählungskonstanten (Enums) definiert werden. // Alle Anweisungen müssen mit einem Semikolon beendet werden. enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; // MON wird automatisch zu 2, TUE zu 3 etc. // Importiere Header-Dateien mit #include #include #include #include // Dateien, welche zwischen stehen, sind Header-Dateien aus // der C-Standard-Bibliothek. // Für deine eigenen Header müssen Anführungszeichen verwendet werden, z.B.: // #include "mein_header.h" // Funktionssignaturen werden entweder vorher in einer .h-Datei deklariert oder // am Anfang der .c-Datei. void function_1(); int function_2(void); // Es muss ein Funktionsprototyp deklariert werden vor der `main()` Funktion, // wenn die Funktion nach der `main()` Funktion gebraucht wird. int add_two_ints(int x1, int x2); // Funktionsprototyp // Auch wenn der Ausdruck `int add_two_ints(int, int)` auch valid wäre, // ist es empfohlen, dass man die Namen der Argumente hinschreibt für eine // einfachere Analyse. // Der Einstiegspunkt deines Programms ist eine Funktion mit dem Namen main und // einem Integer als Rückgabewert. int main(void) { // dein Programm } // Die Kommandozeilenargumente, welche gebraucht werden, damit dein Programm // läuft, werden als Argumente der `main`-Funktion mitgegeben. // argc (argument counter) steht für die Anzahl von Argumenten. // Der Programmname ist das erste Argument. // argv (argument vector) ist ein Array von Zeichenarrays, welche die // Argumente beinhaltet. // argv[0] = Name des Programms // argv[1] = erstes Argument usw. int main (int argc, char** argv) { // Ausgabe mit Hilfe von printf (print formatted) // %d ist ein Integer. // \n steht für eine neue Zeile printf("%d\n",0); // => Gibt 0 aus. //////////////////////////////////////////////// // Operatoren //////////////////////////////////////////////// // Kurzschreibweise für mehrere Deklarationen int i1 = 1, i2 = 2; flaot f1 = 1.0, f2 = 2.0; int b,c; b = c = 0; // Arithmetik ist unkompliziert 1 + 2; // => 3 2 - 1; // => 1 2 * 1; // => 2 1 / 2; // 0 (0.5, aber abgeschnitten, da es int sind.) // Man muss mindestens ein Integer zu einen float konvertieren, damit man als // Resultat eine Gleitkommazahl erhält. (float)1 / 2; // => 0.5f 1 / (double)2; // => 0.5 // das gleiche mit dem Typ `double` 1.0 / 2.0; // => 0.5, plus oder minus Epsilon // Gleitkommazahlen und deren Berechnungen sind nicht exakt. // Es gibt auch die Möglichkeit, Modulo zu rechnen 11 % 3; // => 2 // Vergleichsoperatoren sind vielleicht schon bekannt, aber in C gibt es // keinen Boolean-Typ. In C verwenden wir `int`. (Oder _Bool oder bool in C99) // 0 ist falsch, alles andere ist wahr (Die Vergleichsoperatoren ergeben // immer 1 oder 0. 3 == 2; // => 0 (falsch) 3 != 2; // => 1 (wahr) 3 > 2; // => 1 3 < 2; // => 0 2 <= 2; // => 1 2 >= 2; // => 1 // C ist nicht Python - Vergleiche können nicht einfach verkettet werden. // Warnung: die folgende Zeile wird kompilieren, aber es bedeutet `(0 < a) < 2`. // Dieser Ausdruck ist immer wahr, weil (0 < a) kann entweder 1 oder 0 sein. // In diesem Falle ist es 1, weil (0 < 1). int zwischen_0_und_2 = 0 < a < 2; // Benutze stattdessen folgende Schreibweise: int zwischen_0_und_2 = 0 < a && a < 2; // Logik funktioniert auch mit ints !3; // => 0 (logisches Nicht) !0; // => 1 1 && 1; // => 1 (logisches Und) 0 && 1; // => 0 0 || 1; // => 1 (logisches Oder) 0 || 0; // => 0 // Bedingter ternärer Ausdruck ( ? : ) int e = 5; int f = 10; int z; z = ( e > f ) ? e : f; // => // => 10 "wenn e > f ist, gib e zurück, sonst f." // Inkrementierungs- und Dekrementierungsoperatoren int j = 0; int s = j++; // gib j zurück und erhöhe danach j. (s = 0, j = 1) s = ++j; // erhöhe zuerst j und gib dann j zurück (s = 2, j = 2) // das gleiche gilt für j-- und --j // Bitweise Operatoren ~0x0F; // => 0xFFFFFFF0 (Bitweise Negation, "Einer-Komplement", // Beispielresultat für 32-Bit int) 0x0F & 0xF0; // => 0x00 (Bitweises UND) 0x0F | 0xF0; // => 0xFF (Bitweises ODER) 0x04 ^ 0x0F; // => 0x0B (Bitweises XOR) 0x01 << 1; // => 0x02 (Bitweises Linksverschiebung (left shift) (um 1)) 0x02 >> 1; // => 0x01 (Bitweises Rechtsverschiebung (right shift) (um 1)) // Sei vorsichtig beim Shift mit vorzeichenbehafteten Integern // folgende Ausdrücke sind nicht definiert: // - Verschiebung in das Vorzeichenbit (int a = 1 << 31) // - Linksshift einer negativen Zahl (int a = -1 << 2) // - Shift um einen Offset, welcher >= die Breite des linken Ausdrucks ist. // int a = 1 << 32; // undefiniertes Verhalten, wenn int 32-Bit ist. //////////////////////////////////////////////// // Typen //////////////////////////////////////////////// // Compiler, welche nicht C99-kompatibel sind, verlangen, dass sämtliche // Variablen zu Beginn des Blocks deklariert werden. // C99-Konforme Compiler erlauben die Variablendeklaration an dem Punkt, an // welchem die Variable verwendet wird. // Wir deklarieren die Variablen dynamisch im Code um die Lesbarkeit im // Tutorial zu verbessern. // integer sind normalerweise 4 Bytes groß int x_int = 0; // shorts sind normalerweise 2 Bytes groß short x_short = 0; // chars sind garantiert 1 Byte groß char x_char = 0; char y_char = 'y'; // Charakterliterale werden mit '' gekennzeichnet. // longs sind oft 4 bis 8 Bytes groß. long long sind garantiert mindestens // 8 Bytes groß. long x_long = 0; long long x_long_long = 0; // floats sind normalerweise 32-Bit Gleitkommazahlen float x_float = 0.0f; // 'f'-Suffix beschreibt eine Gleitkommazahl. // doubles sind normalerweise 64-Bit Gleitkommazahlen double x_double = 0.0; // echte Zahlen ohne Suffix sind vom Typ double // integer-Typen können vorzeichenlos (unsigned) sein // (größer oder kleiner als 0) unsigned short ux_short; unsigned int ux_int; unsigned long long ux_long_long; // Zeichen innerhalb von einfachen Anführungszeichen sind Integers im // Maschinenzeichensatz '0'; // => 48 im ASCII-Zeichensatz 'A'; // => 65 im ASCII-Zeichensatz // sizeof(T) gibt die Größe einer Variablen des Typen T in Bytes zurück. // sizeof(obj) ergibt die Größe des Ausdrucks (Variable, Literal usw.) printf("%zu\n", sizeof(int)); // => 4 (auf den Rechnern mit einem 4-Byte-Wort) // Wenn das Argument des `sizeof`-Operator ein Ausdruck ist, dann wird das // Argument nicht ausgewertet (außer Arrays mit variabler Länge) // Der Wert, der in diesem Fall zurückgegeben wird, ist eine Konstante zur // Kompilierzeit. int a = 1; //size_t ist ein vorzeichenloser Integer Typ mit mindestens 2 Byte um die // Größe eines Objekts zu repräsentieren. size_t size = sizeof(a++); // a++ wird nicht ausgewertet printf("sizeof(a++) = %zu, wobei a=%d ist\n", size, a); // Gibt "sizeof(a++) = 4, wobei a=1 ist" aus (mit einer 32-Bit-Architektur) // Arrays müssen mit einer Größe initialisiert werden. char my_char_array[20]; // Dieses Array beinhaltet 1 * 20 = 20 Bytes int my_int_array[20]; // Dieses Array beinhaltet 4 * 20 = 80 Bytes. // unter der Voraussetzung eines 4-Byte-Worts. // Ein Array kann auf diese Weise mit 0 initialisiert werden. char my_array[20] = {0}; // Hierbei ist der Teil "{0}" der "Array Initialisierer". // Beachte, dass die Länge des Arrays nicht explizit definiert werden muss, // wenn er auf derselben Linie initialisiert wird. // Folgende Deklaration ist gleichwertig: char my_array[] = {0}; // Allerdings muss die Länge des Arrays dann zur Laufzeit ausgewertet werden: size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]); // WARNUNG: Wenn dieser Ansatz gewählt wird, muss man sicherstellen, dass die // Größe des Arrays ermittelt werden *bevor* dieser einer Funktion als // Argument weitergegeben wird (siehe Diskussion weiter unten), weil Arrays // einer Funktion nur als Zeiger übergeben werden. => Das obere Statement // würde innerhalb einer Funktion ein falsches Resultat liefern. // Das Indexieren eines Arrays funktioniert wie in anderen Sprache - resp. // in anderen Sprachen funktioniert es gleich wie in C. my_array[0]; // => 0 // Arrays sind veränderbar; es ist nur Arbeitsspeicher! my_array[1] = 2; printf("%d\n", my_array[1]); // => 2 // In C99 (und als optionales Feature in C11) können Arrays mit variabler // Länge deklariert werden. Die Größe eines solchen Array muss eine Konstante // zur Kompilierzeit sein. printf("Geben Sie die Arraygröße an: "); //Frag den Benutzer nach // der Arraygröße int array_size; fcsanf(stdin, "%d", &array_size); int var_length_array[array_size]; // deklariere Array mit variabler Länge printf("sizeof array =%zu\n", sizeof var_length_array); // Zum Beispiel: // > Geben Sie die Arraygröße an: 10 // > sizeof array = 40 // Strings sind lediglich Arrays von `chars`, welche mit einem Null-Byte // (0x00) beendet werden. In Strings wird das Nullbyte durch das Zeichen \0 // repräsentiert. Wir müssen das Null-Byte nicht angeben in String-Literalen; // der Compiler fügt es am Ende des Array automatisch hinzu. char a_string[20] = "Das ist ein String"; printf("%s\n", a_string); // %s formatiert einen String printf("%d\n", a_string[18]); // => 0 // Hier ist das Byte #19 0 (wie auch Byte #20) // Wenn wir Zeichen zwischen einfachen Anführungszeichen haben, ist es ein // Zeichenliteral vom Typ int und *nicht* char. (aus historischen Gründen) int cha = 'a'; // Ok char chb = 'a'; // auch ok (implizite Umwandlung von int zu char) // Mehrdimensionale Arrays: int multi_array[2][5] = { {1,2,3,4,5}, {6,7,8,9,0} }; // Auf Elemente zugreifen: int array_int = multi_array[0][2]; // => 3 //////////////////////////////////////////////// // Kontrollstrukturen //////////////////////////////////////////////// if (0) { printf("Ich werde nie ausgeführt."); } else if (0) { printf("Ich werde auch nie ausgeführt."); } else { printf("Ich gebe etwas aus."); } // While-Schleifen existieren auch int ii = 0; while (ii < 10) { // JEDER Wert unter zehn ist wahr printf("%d, " ii++); //i++ inkrementiert ii NACHDEM der Wert gebraucht // wurde. } // => gibt folgendes aus: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); int kk = 0; do { printf("%d, ", kk); } while(++kk < 10); //++kk inkrementiert kk BEVOR der Wert gebraucht wurde. // => gibt folgendes aus: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // In C gibt es auch for-Schleifen int jj; for (jj = 0; jj < 10; jj++) { printf("%d, ", jj); } // => gibt folgendes aus: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // **Merke** // Schleifen und Funktionen müssen einen Rumpf haben. Wenn kein Rumpf gebraucht // wird, kann folgendes gemacht werden: int i; for (i = 0; i <= 5; i++) { ; // Semikolon wird als Rumpf behandelt (Null-Anweisung) } // Alternativ kann auch folgendes geschrieben werden: for (i = 0; i <= 5; i++); // Verzweigungen mit mehreren Möglichkeiten: `switch()` switch (a) { case 0: // Labels müssen integrale *konstante* Ausdrücke sein (z.B. Enums) printf("Hey, 'a' ist gleich 0!\n"); break; //Wenn du kein break einsetzt, so geht der Kontrollfluss // durch die Labels case 1: printf("Huh, 'a' ist gleich 1!\n"); break; // Sei vorsichtig - wenn man das `break` vergisst, werden alle // Anweisungen ausgeführt bis das nächste `break` erscheint. case 3: case 4: printf("Schau mal ... 'a' ist entweder 3 oder 4.\n"); break; default: // wenn der Ausdruck `a` auf kein Label zutrifft. fputs("Fehler!\n", stderr); exit(-1); break; } //////////////////////////////////////////////// // Typenumwandlung //////////////////////////////////////////////// // Jeder Wert in C hat einen bestimmten Typen, aber es ist möglich, ein // Wert in einen anderen Typ umzuwandeln (mit einigen Einschränkungen). int x_hex = 0x01; // Es ist möglich, Variablen Hexadezimalwerten zuzuweisen. // Bei der Umwandlung zwischen Typen wird versucht, den numerischen Wert // beizubehalten. printf("%d\n", x_hex); // => 1 printf("%d\n", (short) x_hex); // => 1 printf("%d\n", (char) x_hex); // => 1 // Typen werden überlaufen (overflow) ohne jegliche Warnung printf("%d\n", (unsigned char) 257); // => 1 (Max char=255 wenn char 8 Bit ist) // Um den maximalen Wert eines `char`, `signed char` oder `unsigned char` // herauszufinden, können die Makros `CHAR_MAX`, `SCHAR_MAX` und `UCHAR_MAX` // aus der Header-Datei `` verwendet werden. // Integer-Typen können zu Gleitkommazahlen und umgekehrt umgewandelt werden. printf("%f\n", (double) 100); // %f formatiert immer zu einem `double`... printf("%f\n", (flaot) 100); // ... auch mit einem `float` printf("%d\n", (char)100.0); //////////////////////////////////////////////// // Zeiger (aka Pointer) //////////////////////////////////////////////// // In diesem Tutorial wird das deutsche Wort Zeiger nicht verwendet, da es // bei einer weiteren Recherche einfacher ist, wenn man von Pointern ausgeht. // Außerdem ist der Begriff Pointer auch im deutschen Sprachgebrauch zu finden. // Ein Pointer ist eine Variable, welche deklariert wurde, um eine Speicher- // adresse zu speichern. Die Deklaration eines Pointers wird auch zeigen, // auf welche Art von Daten der Pointer zeigt. Man kann die Speicheradresse // von Variablen abrufen und dann mit diesen herumspielen. int x = 0; printf("%p\n", (void *)&x); // verwende & um die Adresse der Variable // zu erhalten // %p formatiert einen Objektpointer des Typen void*) // => Gibt eine Adresse im Speicher aus // Pointer starten mit einem * zu Beginn der Deklaration. int *px, not_a_pointer; // px ist ein Pointer zu einem int. px = &x; // Speichert die Adresse von x in px printf("%p\n", (void *)px); // => Gibt eine Adresse im Speicher aus printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); // Gibt auf einem typischen 64-Bit-System folgendes aus: "8, 4" // Um den Wert einer Adresse, auf welche ein Pointer zeigt, herauszufinden, // muss man vor die Variable ein * setzen, um sie zu dereferenzieren. // Notiz: Ja, es kann verwirrend sein, dass '*' sowohl für das Deklarieren // als auch das Derefenzieren verwendet werden kann. printf("%d\n", *px); // => 0, der Wert von x // Man kann den Wert, auf welchen ein Pointer zeigt, auch verändern. // Man muss die Dereferenzierung in Klammern setzen, weil ++ eine höhere // Priorität als * hat. (*px)++; // Inkrementiere den Wert, auf welchen px zeigt, um 1 printf("%d\n", *px); // => 1 printf("%d\n", x); // => 1 // Arrays sind eine gute Möglichkeit, einen zusammenhängenden Block von // Speicher zu allozieren. int x_array[20]; // deklariert einen Array der Größe 20 (Größe kann // nicht geändert werden.) int xx; for (xx =0; xx < 20; xx++) { x_array[xx] 20 -xx; } // Initialisiere x_array zu 20, 19, 18, ... 2, 1 // Deklariere ein Pointer des Typs int und initialisiere ihn, um auf `x_array` // zu zeigen. int *x_ptr = x_array; // x_ptr zeigt jetzt auf den ersten Wert innerhalb des Arrays (int 20) // Das funktioniert, weil Arrays oft zu Pointern reduziert werden, welche // auf das erste Element zeigen. // Zum Beispiel: Wenn ein Array einer Funktion mitgegeben wird oder einem // Pointer zugewiesen wird, wird es zu einem Pointer reduziert (implizites Casting) // Ausnahme: Wenn das Array das Argument des Operators `&` ist. int arr[10]; int (*ptr_to_arr)[10] = &arr; //`&arr` ist nicht vom Typ `int *`! // Es ist vom Typen "Pointer auf Array" (aus zehn `int`s) // oder wenn das Array ein Stringliteral ist, welches gebraucht wird um ein // `char`-Array zu initialisieren. char other_arr[] = "foobarbazquirk"; // oder wenn es das Argument des `sizeof` oder `alignof` Operators ist. int third_array[10]; int *ptr = third_array; // gleich wie: `int *ptr = &arr[0]` printf("%zu, %zu\n", sizeof(third_array), sizeof(ptr)); // Gibt wahrscheinlich "40, 4" oder "40, 8" aus // Pointer werden basierend auf dem Typ in- und dekrementiert // Dies wird Pointer-Arithmetik genannt. printf("%d\n", *(x_ptr + 1)); // => 19 printf("%d\n", x_array[1]); // => 19 // Man kann zusammenhängende Speicherblöcke auch mit der Funktion `malloc` // aus der Standardbibliothek dynamisch allozieren. Der Funktion `malloc` // muss ein Argument des Typs `size_t` übergeben werden, welches bestimmt, // wie viele Bytes alloziert werden sollen. (Normalerweise geschieht dies // aus dem Heap - dies kann auf eingebetteten Systemen unterschiedlichen sein. // Der C Standard sagt nichts darüber.) int *my_ptr = malloc(sizeof(*my_ptr) * 20); for (xx = 0; xx < 20; xx++) { *(my_ptr + xx) = 20 -xx; //my_ptr[xx] = 20-xx } // initialisiere Speicher zu 20, 19, 18, 17, ... 2, 1 (als `int`) // Sei vorsichtig beim Übergeben von Benutzerdefinierten Werten an `malloc`. // Wenn du sicher sein willst, kannst du die Funktion `calloc` nutzen, welche // (nicht wie `malloc`) auch den Speicher nullt. int *my_other_ptr = calloc(20, sizeof(int)); // Merke, dass es in C keinen Standard-Weg gibt, um die Länge eines dynamisch // allozierten Arrays zu bestimmen. Auf Grund dessen sollte eine Variable // erstellt werden, welche sich die Anzahl der Elemente im Array merkt, wenn // die Arrays mehrmals im Programm gebraucht werden. // Weitere Informationen stehen im Abschnitt Funktionen. size_t size = 10; int *my_array = calloc(size, sizeof(int)); // Füge dem Array ein Element hinzu size++; my_array = realloc(my_array, sizeof(int) *size); if (my_array == NULL) { // Denke daran, realloc-Fehler zu prüfen return } my_array[10] = 5; // Das Dereferenzieren von nicht alloziertem Speicher führt zu einem // Undefinierten Verhalten. printf("%d\n", *(my_ptr + 21)); // Gibt irgendwas aus. // Das Programm kann auch abstürzen // Nachdem du fertig mit einem Block bist, welcher `malloc` verwendet hat, // muss der Speicher befreit werden. Ansonsten kann dieser Speicherbereich // niemand nutzen bis dein Programm beendet wird. // Dies wird auch als "Speicherleck" (engl: memory leak) bezeichnet. free(my_ptr); // Obwohl Strings normalerweise als Pointer-to-Char (Pointer zum ersten // Zeichen des Arrays) repräsentiert werden, sind Strings Arrays aus `char`s. // Es ist eine gute Praxis, `const char *` zu verwenden, wenn man ein // String-Literal referenziert, da String-Literale nicht modifiziert werden // sollten (z.B. "foo"[0] = 'a' ist ILLEGAL) const char *my_str = "Das ist mein eigener String"; printf("%c\n", *my_str); // => D // Dies ist nicht der Fall, wenn der String ein Array (möglicherweise mit // einem String-Literal initialisiert) ist, welcher im beschreibbaren Speicher // bleibt, wie zum Beispiel in: char foo[] = "foo"; foo[0] = 'a'; // Dies ist legal, foo enthält jetzt "aoo" function_1(); } // Ende der `main`-Funktion //////////////////////////////////////////////// // Funktionen //////////////////////////////////////////////// // Syntax einer Funktionsdeklaration // () int add_two_ints(int x1, int x2) { return x1 + x2; // verwendet return, um einen Wert zurückzugeben } /* Funktionen werden auf Grund des Wertes aufgerufen (call-by-value). Wenn eine Funktion aufgerufen wird, sind die Argumente Kopien der ursprünglichen Werte (ausgenommen Arrays). Alles, was man innerhalb einer Funktion mit den Werten macht, hat keinen Einfluss auf die Originalwerte als die Funktion aufgerufen wurde. Verwende Pointer, um den Originalinhalt zu bearbeiten. Beispiel: */ // Eine `void`-Funktion gibt keinen Wert zurück void str_reverse(char *str_in) { char tmp; size_t ii = 0; size_t size = strlen(str_in); // `strlen()` ist ein Teil der C Standard-Bibliothek. // Merke: Die Länge, welche von `strlen` zurückgegeben wird, ist ohne den // Null-Byte Terminator. for (ii = 0; i < size /2; ii++) { // in C99 kann man `ii` hier deklarieren. tmp = str_in[ii]; str_in[ii] = str_in[size - ii - 1]; //#ii'tes Zeichen vom Ende her str_in[size - ii- 1] = tmp; } } // Merke: Die `string.h`-Headerdatei muss inkludiert werden, bevor `strlen()` // verwendet werden kann. /* char c[] = "Das ist ein Test"; str_reverse(c); printf("%s\n", c), => "tseT nie tsi saD" */ // Weil wir lediglich eine Variable zurückgeben können, kann zum Ändern mehrerer // Variablen das Konzept call-by-reference verwendet werden. void swap_two_numbers(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int first = 10; int seconde = 20; printf("Erste Zahl: %d\n Zweite Zahl: %d\n", first, second); swap_two_numbers(&first, &second); printf("Erste Zahl: %d\n Zweite Zahl: %d\n", first, second); // Werte sind vertauscht. /* Wenn man Arrays betrachtet, so werden diese immer als Pointer übergeben. Auch wenn die Arrays statisch alloziert werden (wie zum Beispiel `arr[10]`), werden diese als Pointer zum ersten Element des Arrays übergeben. Auch hier soll noch einmal erwähnt werden, dass es keinen Standard gibt, wie die Größe eines dynamischen Arrays herausgefunden werden kann. */ // Die Größe des Arrays muss unbedingt mitgegeben werden. // Sonst hat die Funktion keine Ahnung wie groß das Array ist. void print_int_arrray(int *arr, size_t size) { int i; for (i = 0; i < size; i++) { printf("arr[%d] ist %d\n", i, arr[i]); } } int my_array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int size = 10; print_int_array(my_array, size); // Wird folgendes ausgeben: "arr[0] ist 1" usw. // Wenn man auf externe Variable (außerhalb der Funktion) referenziert, sollte // man das Schlüsselwort `extern` verwenden. int i = 0; void test_function() { extern int i; // i braucht nun die externe Variable i } // Das Schlüsselwort `static` macht, dass eine Variable außerhalb der Kompilier- // einheit nicht zugreifbar ist. (Auf den meisten Systemen ist eine Kompiliereinheit // eine `.c`-Datei.) Das Schlüsselwort `static` kann sowohl bei globalen // (zur Kompiliereinheit gehörende) Variablen, Funktionen und Funktionslokale // Variablen angewendet werden. // Wenn man `static` bei lokalen Variablen verwendet, so ist diese Variable global // erreichbar und behält dessen Wert über Funktionsaufrufe hinweg, aber sie ist // nur innerhalb der deklarierten Funktion verfügbar. Außerdem werden statische // Variablen mit 0 initialisiert, wenn sie nicht mit einem anderen Startwert // initialisiert werden. // Es ist auch möglich, Funktionen als statisch zu deklarieren, damit diese // `private` sind. Privat heißt, dass sie nur in diesem Kontext sichtbar sind. //////////////////////////////////////////////// // Benutzerdefinierte Typen und Strukturen (Structs) //////////////////////////////////////////////// // `typedef`s können verwendet werden, um Typenaliase zu erstellen. typedef int my_type; my_type my_type_var = 0; // Structs sind lediglich Sammlungen von Daten, die Inhalte werden // (in der Reihenfolge wie sie geschrieben wurden) sequentiell alloziert. struct rectangle { int width; int height; }; // Allgemein ist es nicht so, dass folgender Ausdruck wahr ist. // sizeof(struct rectangle) == sizeof(int) + sizeof(int) // Dies ist so, weil potentiell ein Padding zwischen den Struktur-Inhalten // möglich ist). (siehe [1, Englisch]) void function_1() { struct rectangle my_rectangle; // Greife auf Struct-Inhalte mit `.` zu. my_rectangle.width = 10; my_rectangle.height = 20; // Du kannst Pointer zu Structs deklarieren. struct rectangle *my_rectangle_ptr = &my_rectangle; // Verwende Dereferenzierung, um Struct-Inhalte zu bearbeiten (*my_rectangle_ptr).width = 30; //Noch besser: Verwende die Kurzschreibweise ->, um die Lesbarkeit zu // verbessern. my_rectangle_ptr->height = 10; // Gleich wie: (*my_rectangle_ptr).height = 10; } // Aus Bequemlichkeitsgründen ist es möglich einem `struct` ein `typedef` hinzuzufügen. typedef struct rectangle rect; int area(rect r) { return r.width * r.height; } // Wenn du große Structs hast, kannst du diese mit dem Pointer kopieren, // damit große Kopiervorgänge vermieden werden. int area_ptr(const rect *r) { return r->width * r->height; } //////////////////////////////////////////////// // Funktionspointer //////////////////////////////////////////////// /* Zur Laufzeit sind Funktionen in einer Speicheradresse gespeichert. Funktionspointer sind wie normale Pointer (es wird einfach eine Speicheradresse gespeichert). Funktionspointer können verwendet werden, um Funktionen und Handler (oder Callback-Funktionen) direkt aufzurufen. Wie auch immer, die Syntax kann zu Beginn verwirrend wirken. Zum Beispiel: Verwende str_reverse von einem Pointer */ void str_reverse_through_pointer(char *str_in) { // Definiere eine Funktionspointer-Variable, welche f genannt wird. void (*f)(char *); // Signatur sollte genau der Funktion entsprechen. f = &str_reverse; // weise die Adresse der wirklichen Funktion zu // (zur Laufzeit bestimmt) // `f = str_reverse;` würde auch funktionieren, da Funktionen zu Pointern // reduziert werden (ähnlich wie Arrays) (*f)(str_in); // Die Funktion einfach mit dem Pointer aufrufen // f(str_in); // Dies ist eine weitere gültige Alternative um eine Funktion // aufzurufen. } /* Solange die Signaturen der Funktionen übereinstimmen, kann man sämtliche Funktionen demselben Pointer zuweisen. Funktionspointer sind auf Grund der Einfachheit und Leserlichkeit normalerweise wie folgt `typedef`d */ typedef void (*my_fnp_type)(char *); // Danach werden diese genutzt, um die wirkliche Pointervariable zu deklarieren. // .. // my_fnp_type f; // Spezialzeichen // Im folgenden sin die englischen Begriffe jeweils in Klammern geschrieben, // da diese Begriffe auch im deutschen Sprachgebrauch verwendet werden. '\a'; // Alarmzeichen (alert (bell) character) '\n'; // Zeichen für neue Linie (newline character) '\t'; // Tab (tab character (left justifies text)) '\v'; // Vertikaler Tab (vertical tab) '\f'; // Neue Seite (new page (form feed)) '\r'; // Wagenrücklauf (carriage return) '\b'; // Backspace-Zeichen (backspace character) '\0'; // Null-Byte (NULL character). In C wird dieses Zeichen normalerweise am // Ende eines Strings gesetzt. // Beispiel: Hallo\n\0. "\0" wird per Konvention verwendet, um das Ende // eines Strings zu kennzeichnen. '\\'; // Backslash (backslash) '\?'; // Fragezeichen (question mark) '\''; // einfaches Anführungszeichen (single quote) '\"'; // doppeltes Anführungszeichen (double quote) '\xhh'; // Hexadezimale Zahl (hexadecimal number.) Beispiel: // '\xb' = Zeichen für vertikalen Tab '\0oo'; // Oktalzahl (octal number). Beispiel \013 = Zeichen für vertikalen Tab //Ausgabeformatierung "%d"; // Integer "%3d"; // Integer mit einer minimalen Länge von drei Zeichen. "%s"; // String "%f"; // Gleitkommazahl (float) "%ld"; // genauere Gleitkommazahl (long) "%3.2f"; // Mindestens drei Zeichen vor und drei nach dem Komma. "%7.4s"; // (Kann auch mit Strings gemacht werden) "%c"; // einzelnes Zeichen (char) "%p"; // Pointer. Merke: man muss den Pointer zu void umwandeln, // bevor `printf` funktioniert. "%x"; // Hexadezimal "%o"; // Oktalzahl "%%"; // Gibt % aus //////////////////////////////////////////////// // Reihenfolge der Auswertung von Operatoren //////////////////////////////////////////////// //-------------------------------------------------------// // Operatoren | Assoziativität // //-------------------------------------------------------// // () [] -> . | linksassoziativ // // ! ~ ++ -- + - *(type)sizeof | rechtsassoziativ // // * / % | linksassoziativ // // + - | linksassoziativ // // << >> | linksassoziativ // // < <= > >= | linksassoziativ // // == != | linksassoziativ // // & | linksassoziativ // // ^ | linksassoziativ // // | | linksassoziativ // // && | linksassoziativ // // || | linksassoziativ // // ?: | rechtsassoziativ // // = += -= *= /= %= &= ^= |= <<= >>= | rechtsassoziativ // // , | linksassoziativ // //-------------------------------------------------------// //////////////////////////////////////////////// // Header-Dateien //////////////////////////////////////////////// /* Header-Dateien sind ein wichtiger Teil von C, da sie eine Verbindung zwischen unterschiedlichen C-Quelldateien herstellen. Außerdem vereinfachen Header-Dateien den Code und Definitionen, da diese in separaten Dateien geschrieben werden können. Header-Dateien sind von der Syntax her ähnlich zu C-Quelldateien, allerdings haben die Header-Dateien die Dateiendung `.h`. Header-Dateien können im Quellcode mit der `#include`-Anweisung eingebunden werden z.B. `#include "beispiel.h". Die vorherige Anweisung geht davon aus, dass sich die Header-Datei im selben Ordner befindet wie die C-Quelldatei. */ // Eine sichere Möglichkeit, einen Header mehrere Male zu definieren bietet, das // folgende Statement. Die mehrfache Definition geschieht, wenn Kreisabhängigkeiten // bestehen. #ifndef EXAMPLE_H /* Wenn EXAMPLE_H noch nicht definiert wurde */ #define EXAMPLE_H /* definiere das Makro EXAMPLE_H */ // Es können weitere Header innerhalb eines Headers eingebunden werden, was dazu // führt, dass diese bereits in anderen Dateien eingebunden wurden. So kann eine // Header-Datei in mehreren Dateien eingebunden werden. zum Beispiel: #include // Wie in den Quelldateien können auch in den Header-Dateien Makros definiert // werden und in anderen Dateien verwendet werden, welche diesen Header einbinden. #define EXAMPLE_NAME "Dennis Ritchie" // Funktionsmakros können auch definiert werden. #define ADD(a, b) ((a) + (b)) // Beachte die Klammern, welche um die Argumente geschrieben wurden - diese sind // wichtig, damit sichergestellt werden kann, dass a und b nicht unerwartet // erweitert werden. Zum Beispiel: `MUL (x,y) (x * y)`; Bei der Verwendung von // `MUL(1 + 2, 3)` würde dies wie folgt erweitert werden: `(1 + 2 * 3)`, was zu // einem falschen Resultat führt. // Strukturen und Typendefinitionen können verwendet werden, um die Konsistenz // zwischen unterschiedlichen Dateien beizubehalten. typedef struct Node { int value; struct Node *next; }Node; // Dies kann auch mit Aufzählungen gemacht werden. enum traffic_light_state {GREEN, YELLOW, RED}; // Funktionsprototypen können auch in Header-Dateien definiert werden, um die // Funktion in unterschiedlichen Dateien zu verwenden, aber dies wird als schlechte // Praxis angesehen. Definitionen sollten in einer C-Datei erstellt werden. Node create_linked_list(int *value, int length); // Außer den oben genannten Elementen, sollten weitere Definitionen in einer // C-Datei gemacht werden. Übermäßige Includes und Definitionen sollten auch // nicht einer Header-Datei gemacht werden. Stattdessen wird es empfohlen, diese // in eine separate Header-Datei oder in eine C-Quelldatei zu schreiben. #endif /* Ende der Präprozessordirektive */ ``` ## Weiterführende Literatur Das Beste wird es sein, wenn man sich ein Exemplar des Buches ["The C Programming Language"](https://de.wikipedia.org/wiki/The_C_Programming_Language) besorgt. Dieses Buch gilt als **das** Buch über die Programmiersprache C und wurde von Dennis Ritchie, dem Erfinder der Programmiersprache C, und Brian Kernighan geschrieben. Sei vorsichtig, da dieses Buch mittlerweile schon etwas älter ist und gewisse Unkorrektheiten (d.h. Ideen, welche nicht mehr als gut empfunden werden.) oder mittlerweile geänderte Praktiken enthält. [Hinweis: Das Buch wurde auf Englisch geschrieben, es gibt aber auch eine Übersetzung davon] Eine weitere gute Ressource ist [Learn C The Hard Way](http://learncodethehardway.org/c/). [Englisch] Solltest du Fragen zu C haben, so lies die FAQ [compl.lang.c Frequently Asked Questions](http://c-faq.com).[Englisch] Außerdem ist es wichtig, eine saubere Einrückung zu verwenden. Des weiteren ist es wichtig, dass der Codestil möglichst konsistent ist. Es ist wichtiger, lesbaren Code zu schreiben als Code, welcher clever und schnell ist. Es lohnt sich ein Blick auf den [Codestil des Linuxkernel](https://www.kernel.org/doc/Documentation/process/coding-style.rst) zu werfen. [Englisch] [1] [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) ================================================ FILE: de/clojure-macros.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] translators: - ["Dennis Keller", "https://github.com/denniskeller"] --- Wie mit allen Lisps besitzt auch Clojure die inhärente [Homoikonizität](https://en.wikipedia.org/wiki/Homoiconic), die dir den vollen Zugang der Sprache gibt, um Code-Generierungsroutinen zu schreiben. Diese werden "Macros" genannt. Macros geben dir eine leistungsstarke Möglichkeit, die Sprache an deine Bedürfnisse anzupassen. Sei aber vorsichtig, es wird als schlechter Stil angesehen, wenn du ein Macro schreibst, obwohl eine Funktion genauso gut funktionieren würde. Verwende nur dann ein Macro, wenn du Kontrolle darüber brauchst, wann oder ob Argumente in einer Form evaluiert werden. Wenn du mit Clojure vertraut sein möchtest, stelle sicher, dass du alles in [Clojure in Y Minutes](../clojure/) verstehst. ```clojure ;; Definiere ein Macro mit defmacro. Dein Macro sollte eine Liste zurückgeben, ;; die als Clojure Code evaluiert werden kann. ;; ;; Dieses Macro ist das Gleiche, als ob du (reverse "Hallo Welt") geschrieben ;; hättest (defmacro my-first-macro [] (list reverse "Hallo Welt")) ;; Inspiziere das Ergebnis eines Macros mit macroexpand oder macroexpand-1. ;; ;; Beachte, dass der Aufruf zitiert sein muss. (macroexpand '(my-first-macro)) ;; -> (# "Hallo Welt") ;; Du kannst das Ergebnis von macroexpand direkt auswerten. (eval (macroexpand '(my-first-macro))) ; -> (\t \l \e \W \space \o \l \l \a \H) ;; Aber du solltest diese prägnante und funktionsähnliche Syntax verwenden: (my-first-macro) ; -> (\t \l \e \W \space \o \l \l \a \H) ;; Du kannst es dir leichter machen, indem du die Zitiersyntax verwendest ;; um Listen in ihren Makros zu erstellen: (defmacro my-first-quoted-macro [] '(reverse "Hallo Welt")) (macroexpand '(my-first-quoted-macro)) ;; -> (reverse "Hallo Welt") ;; Beachte, dass reverse nicht mehr ein Funktionsobjekt ist, sondern ein Symbol ;; Macros können Argumente haben. (defmacro inc2 [arg] (list + 2 arg)) (inc2 2) ; -> 4 ;; Aber wenn du versuchst das mit einer zitierten Liste zu machen wirst du ;; einen Fehler bekommen, weil das Argument auch zitiert sein wird. ;; Um dies zu umgehen, bietet Clojure eine Art und Weise Macros zu zitieren: ` ;; In ` kannst du ~ verwenden um in den äußeren Bereich zu kommen. (defmacro inc2-quoted [arg] `(+ 2 ~arg)) (inc2-quoted 2) ;; Du kannst die normalen destruktuierungs Argumente verwenden. Expandiere ;; Listenvariablen mit ~@. (defmacro unless [arg & body] `(if (not ~arg) (do ~@body))) ; Erinnere dich an das do! (macroexpand '(unless true (reverse "Hallo Welt"))) ;; -> ;; (if (clojure.core/not true) (do (reverse "Hallo Welt"))) ;; (unless) evaluiert und gibt body zurück, wenn das erste Argument falsch ist. ;; Andernfalls gibt es nil zurück (unless true "Hallo") ; -> nil (unless false "Hallo") ; -> "Hallo" ;; Die Verwendung Macros ohne Sorgfalt kann viel Böses auslösen, indem es ;; deine Variablen überschreibt (defmacro define-x [] '(do (def x 2) (list x))) (def x 4) (define-x) ; -> (2) (list x) ; -> (2) ;; Um das zu verhindern kannst du gensym verwenden um einen eindeutigen ;; Identifikator zu bekommen (gensym 'x) ; -> x1281 (oder etwas Ähnliches) (defmacro define-x-safely [] (let [sym (gensym 'x)] `(do (def ~sym 2) (list ~sym)))) (def x 4) (define-x-safely) ; -> (2) (list x) ; -> (4) ;; Du kannst # innerhalb von ` verwenden um für jedes Symbol automatisch ;; ein gensym zu erstellen (defmacro define-x-hygienically [] `(do (def x# 2) (list x#))) (def x 4) (define-x-hygienically) ; -> (2) (list x) ; -> (4) ;; Es ist üblich, Hilfsfunktionen mit Macros zu verwenden. Lass uns einige ;; erstellen, die uns helfen , eine (dumme) arithmetische Syntax ;; zu unterstützen (declare inline-2-helper) (defn clean-arg [arg] (if (seq? arg) (inline-2-helper arg) arg)) (defn apply-arg "Bekomme die Argumente [x (+ y)], gebe (+ x y) zurück" [val [op arg]] (list op val (clean-arg arg))) (defn inline-2-helper [[arg1 & ops-and-args]] (let [ops (partition 2 ops-and-args)] (reduce apply-arg (clean-arg arg1) ops))) ;; Wir können es sofort testen, ohne ein Macro zu erstellen (inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5)) ; Allerdings, brauchen wir ein Macro, wenn wir es zur Kompilierungszeit ; ausführen wollen (defmacro inline-2 [form] (inline-2-helper form)) (macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1))) ; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1) (inline-2 (1 + (3 / 2) - (1 / 2) + 1)) ; -> 3 (eigentlich, 3N, da die Zahl zu einem rationalen Bruch mit / umgewandelt wird) ``` ### Weiterführende Literatur [Macros schreiben](http://www.braveclojure.com/writing-macros/) [Offizielle Docs](http://clojure.org/macros) [Wann verwendet man Macros?](https://lispcast.com/when-to-use-a-macro/) ================================================ FILE: de/clojure.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] translators: - ["Dennis Keller", "https://github.com/denniskeller"] --- Clojure ist ein Lispdialekt, der für die Java Virtual Maschine entwickelt worden ist. Sie hat eine stärkere Betonung auf reine [funktionale Programmierung](https://en.wikipedia.org/wiki/Functional_programming) als Common Lisp. Jedoch besitzt sie je nach Bedarf mehrere [STM](https://en.wikipedia.org/wiki/Software_transactional_memory) Werkzeuge zur Handhabung von Zustand. Diese Verknüpfung erlaubt es, parallele Verarbeitung sehr einfach und häufig automatisch zu verarbeiten. (Du brauchst die Clojure Version 1.2 oder neuer) ```clojure ; Kommentare starten mit einem Semikolon. ; Clojure wird in "Forms" geschrieben, was nur Listen von Dingen ; in Klammern sind, getrennt durch Leerzeichen. ; ; Der Clojure Leser nimmt an, dass das Erste, was aufgerufen wird ; eine Funktion oder ein Makro ist, der Rest sind Argumente. ; Der erste Aufruf in einer Datei sollte ns sein, um den Namespace zu setzen. (ns learnclojure) ; Weitere einfache Beispiele: ; str erstellt einen String aus allen Argumenten (str "Hallo" " " "Welt") ; => "Hallo Welt" ; Mathe ist einfach (+ 1 1) ; => 2 (- 2 1) ; => 1 (* 1 2) ; => 2 (/ 2 1) ; => 2 ; Gleichheit ist = (= 1 1) ; => true (= 2 1) ; => false ; Du brauchst auch not für Logik (not true) ; => false ; Verschachtelte Forms funktionieren, wie erwartet (+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2 ; Typen ;;;;;;;;;;;;; ; Clojure verwendet Javas Objekt Typen für Booleans, Strings und Zahlen. ; Verwende `class` um sie zu inspizieren. (class 1) ; Integer-Literale sind standardmäßig java.lang.Long (class 1.); Float-Literale sind java.lang.Double (class ""); Strings sind immer in doppelten Anführungszeichen notiert und sind java.lang.String (class false) ; Booleans sind java.lang.Boolean (class nil); Der "null" Wert heißt nil ; Wenn du ein literale Liste aus Daten erzeugen willst, verwendest du ' um ; zu verhindern dass es evaluiert wird '(+ 1 2) ; => (+ 1 2) ; (Kurzform für (quote (+ 1 2))) ; Du kannst eine zitierte Liste evaluieren (eval '(+ 1 2)) ; => 3 ; Kollektionen & Sequenzen ;;;;;;;;;;;;;;;;;;; ; Listen sind Linked-Lists Datenstrukturen, während Vektoren arraybasierend sind. ; Vektoren und Listen sind auch Java Klassen! (class [1 2 3]); => clojure.lang.PersistentVector (class '(1 2 3)); => clojure.lang.PersistentList ; Eine Liste würde nur als (1 2 3) geschrieben, aber wir müssen es zitieren ; damit der Leser aufhört zu denken, es sei eine Funktion. ; Außerdem ist (list 1 2 3) dasselbe, wie '(1 2 3) ; "Kollektionen" sind nur Gruppen von Daten ; Listen und Vektoren sind Kollektionen: (coll? '(1 2 3)) ; => true (coll? [1 2 3]) ; => true ; "Sequenzen" (seqs) sind abstrakte Beschreibungen von Listen von Daten. ; Nur Listen sind seqs. (seq? '(1 2 3)) ; => true (seq? [1 2 3]) ; => false ; Ein seq muss nur einen Eintrittspunkt bereitstellen, wenn auf ihm zugegriffen wird. ; Das heißt, dass seqs faul sein können -- Mit ihnen kann man unendliche Serien beschreiben. (range 4) ; => (0 1 2 3) (range) ; => (0 1 2 3 4 ...) (eine unendliche Serie) (take 4 (range)) ; (0 1 2 3) ; Verwende cons um ein Item zum Anfang einer Liste oder eines Vektors hinzuzufügen. (cons 4 [1 2 3]) ; => (4 1 2 3) (cons 4 '(1 2 3)) ; => (4 1 2 3) ; Conj fügt ein Item auf die effizienteste Weise zu einer Kollektion hinzu. ; Für Listen fügt er sie an den Anfang hinzu. Für Vektoren fügt er sie an das Ende hinzu. (conj [1 2 3] 4) ; => [1 2 3 4] (conj '(1 2 3) 4) ; => (4 1 2 3) ; Verwende concat um Listen und Vektoren miteinander zu verbinden (concat [1 2] '(3 4)) ; => (1 2 3 4) ; Verwende filter, map um mit Kollektionen zu interagieren (map inc [1 2 3]) ; => (2 3 4) (filter even? [1 2 3]) ; => (2) ; Verwende reduce um sie zu reduzieren (reduce + [1 2 3 4]) ; = (+ (+ (+ 1 2) 3) 4) ; => 10 ; Reduce kann auch einen Initialwert als Argument verwenden (reduce conj [] '(3 2 1)) ; = (conj (conj (conj [] 3) 2) 1) ; => [3 2 1] ; Funktionen ;;;;;;;;;;;;;;;;;;;;; ; Verwende fn um neue Funktionen zu erstellen. Eine Funktion gibt immer ihr ; letztes Statement zurück. (fn [] "Hallo Welt") ; => fn ; (Du brauchst exta Klammern um sie aufzurufen) ((fn [] "Hallo Welt")) ; => "Hallo Welt" ; Du kannst eine Variable mit def erstellen (def x 1) x ; => 1 ; Weise eine Funktion einer Variable zu (def hello-world (fn [] "Hallo Welt")) (hello-world) ; => "Hallo Welt" ; Du kannst den Prozess verkürzen indem du defn verwendest (defn hello-world [] "Hallo Welt") ; [] ist die Liste der Argumente für die Funktion ; The [] is the list of arguments for the function. (defn hello [name] (str "Hallo " name)) (hello "Steve") ; => "Hallo Steve" ; Du kannst diese Kurzschreibweise verwenden um Funktionen zu erstellen: (def hello2 #(str "Hallo " %1)) (hello2 "Julie") ; => "Hallo Julie" ; Du kannst auch multi-variadische Funktionen haben (defn hello3 ([] "Hallo Welt") ([name] (str "Hallo " name))) (hello3 "Jake") ; => "Hallo Jake" (hello3) ; => "Hallo Welt" ; Funktionen können auch extra Argumente in einem seq für dich speichern (defn count-args [& args] (str "Du hast " (count args) " Argumente übergeben: " args)) (count-args 1 2 3) ; => "Du hast 3 Argumente übergeben: (1 2 3)" ; Du kannst reguläre und gepackte Argumente mischen (defn hello-count [name & args] (str "Hallo " name ", Du hast " (count args) " extra Argumente übergeben")) (hello-count "Finn" 1 2 3) ; => "Hallo Finn, Du hast 3 extra Argumente übergeben" ; Maps ;;;;;;;;;; ; Hash maps und Array maps teilen sich ein Interface. Hash maps haben eine schnellere Zugriffszeit, ; aber behalten keine Schlüsselreihenfolge. (class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap (class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap ; Arraymaps werden durch die meisten Operationen automatisch zu Hashmaps, ; sobald sie groß genug werden. Das heißt du musst dich nicht darum sorgen. ; Maps können einen beliebigen Hash-Typ als Schlüssel verwenden, in der Regel ; sind jedoch Keywords am besten. Keywords sind wie Strings, jedoch besitzen sie ; Performance-Vorteile (class :a) ; => clojure.lang.Keyword (def stringmap {"a" 1, "b" 2, "c" 3}) stringmap ; => {"a" 1, "b" 2, "c" 3} (def keymap {:a 1, :b 2, :c 3}) keymap ; => {:a 1, :c 3, :b 2} ; Übrigens werden Kommas als Leerzeichen behandelt und machen nichts. ; Rufe einen Wert von einer Map ab, indem du sie als Funktion aufrufst (stringmap "a") ; => 1 (keymap :a) ; => 1 ; Keywords können auch verwendet werden um ihren Wert aus der Map zu bekommen! (:b keymap) ; => 2 ; Versuche es nicht mit Strings. ;("a" stringmap) ; => Exception: java.lang.String cannot be cast to clojure.lang.IFn ; Das Abrufen eines nicht vorhandenen Keys gibt nil zurück (stringmap "d") ; => nil ; Verwende assoc um einen neuen Key zu einer Hash-map hinzuzufügen (def newkeymap (assoc keymap :d 4)) newkeymap ; => {:a 1, :b 2, :c 3, :d 4} ; Aber denk daran, Clojure Typen sind unveränderlich! keymap ; => {:a 1, :b 2, :c 3} ; Verwende dissoc um Keys zu entfernen (dissoc keymap :a :b) ; => {:c 3} ; Sets ;;;;;; (class #{1 2 3}) ; => clojure.lang.PersistentHashSet (set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3} ; Füge ein Element mit conj hinzu (conj #{1 2 3} 4) ; => #{1 2 3 4} ; Entferne ein Element mit disj (disj #{1 2 3} 1) ; => #{2 3} ; Teste auf Existenz, indem du das Set als Funktion verwendest: (#{1 2 3} 1) ; => 1 (#{1 2 3} 4) ; => nil ; Es gibt mehr Funktionen in dem clojure.sets Namespace. ; Nützliche Forms ;;;;;;;;;;;;;;;;; ; Logische Konstrukte in Clojure sind nur Makros und sie sehen, wie alles ; andere aus (if false "a" "b") ; => "b" (if false "a") ; => nil ; Verwende let um temporäre Bindungen aufzubauen (let [a 1 b 2] (> a b)) ; => false ; Gruppiere Statements mit do zusammen ; Group statements together with do (do (print "Hallo") "Welt") ; => "Welt" (prints "Hallo") ; Funktionen haben ein implizites do (defn print-and-say-hello [name] (print "Sage Hallo zu " name) (str "Hallo " name)) (print-and-say-hello "Jeff") ;=> "Hallo Jeff" (prints "Sage Hallo zu Jeff") ; let macht das auch (let [name "Urkel"] (print "Sage Hallo zu " name) (str "Hallo " name)) ; => "Hallo Urkel" (prints "Sage Hallo zu Urkel") ; Verwende die Threading Makros (-> and ->>) um Transformationen von ; Daten deutlicher auszudrücken. ; Das "Thread-zuerst" Makro (->) fügt in jede Form das Ergebnis des ; Vorherigen als erstes Argument (zweites Element) ein. (-> {:a 1 :b 2} (assoc :c 3) ;=> (assoc {:a 1 :b 2} :c 3) (dissoc :b)) ;=> (dissoc (assoc {:a 1 :b 2} :c 3) :b) ; Dieser Ausdruck kann auch als so geschrieben werden: ; (dissoc (assoc {:a 1 :b 2} :c 3) :b) ; and evaluates to {:a 1 :c 3} ; Der Doppelpfeil macht das Selbe, aber er fügt das Ergebnis von jeder ; Zeile an das Ende der Form, Das ist vor allem für Operationen auf ; Kollektionen nützlich: (->> (range 10) (map inc) ;=> (map inc (range 10)) (filter odd?) ;=> (filter odd? (map inc (range 10))) (into [])) ;=> (into [] (filter odd? (map inc (range 10)))) ; Result: [1 3 5 7 9] ; Wenn du in einer Situation bist, in der du mehr Freiheit willst, ; wohin du das Ergebnis vorheriger Datentransformationen in einem Ausdruck ; platzieren möchtest, kannst du das as-> Macro verwenden. Mit diesem Macro ; kannst du einen speziellen Namen auf die Ausgabe einer Transformationen geben. ; Du kannst es als Platzhalter in verketteten Ausdrücken verwenden: (as-> [1 2 3] input (map inc input);=> Du kannst die letzte Ausgabe der Transformation in der letzten Position verwenden (nth input 2) ;=> und auch in der zweiten Position, im selben Ausdruck verwenden (conj [4 5 6] input [8 9 10])) ;=> oder auch in der Mitte! ; Module ;;;;;;;;;;;;;;; ; Verwende "use" um alle Funktionen aus einem Modul zu bekommen (use 'clojure.set) ; Nun können wir set Operationen verwenden (intersection #{1 2 3} #{2 3 4}) ; => #{2 3} (difference #{1 2 3} #{2 3 4}) ; => #{1} ; Du kannst auch auswählen nur ein Subset von Funktionen zu importieren (use '[clojure.set :only [intersection]]) ; Verwende require um ein Modul zu importieren (require 'clojure.string) ; Verwende / um eine Funktion aus einem Modul aufzurufen ; Hier verwenden wir das Modul clojure.string und die Funktion blank? (clojure.string/blank? "") ; => true ; Du kannst auch einem Modul einen kürzeren Namen beim Import geben (require '[clojure.string :as str]) (str/replace "Das ist ein Test." #"[a-o]" str/upper-case) ; => "DAs IsT EIN TEsT." ; (#"" bezeichnet einen regulären literalen Ausdruck) ; Du kannst require aus einem Namespace verwenden (auch use ist möglich, aber nicht zu empfehlen) ; indem du :require verwendest. ; Du brauchst keine Zitierzeichen für deine Module verwenden, wenn du ; es auf diese Weise machst. (ns test (:require [clojure.string :as str] [clojure.set :as set])) ; Java ;;;;;;;;;;;;;;;;; ; Java hat eine riesige und nützliche Standardbibliothek, ; du möchtest lernen wie man sie verwendet. ; Verwende import um ein Java modul zu laden. (import java.util.Date) ; Du kannst auch von einem ns importieren. (ns test (:import java.util.Date java.util.Calendar)) ; Verwende den Klassennamen mit einem "." am Ende, um eine neue Instanz zu erstellen (Date.) ; ; Verwende . um Methoden aufzurufen oder verwende die ".method" Abkürzung (. (Date.) getTime) ; (.getTime (Date.)) ; Genau das Selbe ; Verwende / um statische Methoden aufzurufen (System/currentTimeMillis) ; (system ist immer da) ; Verwende doto um mit veränderliche Klassen besser umzugehen (import java.util.Calendar) (doto (Calendar/getInstance) (.set 2000 1 1 0 0 0) .getTime) ; => A Date. set to 2000-01-01 00:00:00 ; STM ;;;;;;;;;;;;;;;;; ; Software Transactional Memory ist der Mechanismus, den Clojure verwendet ; um mit persistenten Zuständen umzugehen. Es gibt ein Paar Konstrukte in ; Clojure die es verwenden. ; Ein Atom ist das Einfachste. Gebe es einen Initialwert (def my-atom (atom {})) ; Update ein Atom mit swap!. ; swap! nimmt eine Funktion und ruft sie mit dem aktuellen Zustand des ; Atoms auf und alle nachfolgenden Argumente als das Zweite (swap! my-atom assoc :a 1) ; Setzt my-atom zu dem Ergebnis von (assoc {} :a 1) (swap! my-atom assoc :b 2) ; Setzt my-atom zu dem Ergebnis von (assoc {:a 1} :b 2) ; Verwende '@' um das Atom zu dereferenzieren und den Wert zu bekommen my-atom ;=> Atom<#...> (Gibt das Atom Objekt zurück @my-atom ; => {:a 1 :b 2} ; Hier ist ein einfacher Zähler mit einem Atom (def counter (atom 0)) (defn inc-counter [] (swap! counter inc)) (inc-counter) (inc-counter) (inc-counter) (inc-counter) (inc-counter) @counter ; => 5 ; Andere STM Konstrukte sind refs und agents. ; Refs: http://clojure.org/refs ; Agents: http://clojure.org/agents ``` ### Weiterführende Literatur Das ist alles andere als erschöpfend, aber hoffentlich ist es genug, um dich auf die Beine zu stellen. Clojure.org hat eine Menge von Artikeln: [http://clojure.org/](http://clojure.org/) Clojuredocs.org hat eine Dokumentation mit Beispielen für die meisten Kernfunktionen [http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core) 4Clojure ist eine gute Möglichkeit um deine clojure/FP zu verbessern: [http://www.4clojure.com/](http://www.4clojure.com/) Clojure-doc.org (ja, wirklich) hat eine Reihe von Artikeln zum Starten: [http://clojure-doc.org/](http://clojure-doc.org/) ================================================ FILE: de/coffeescript.md ================================================ --- contributors: - ["Tenor Biel", "http://github.com/L8D"] - ["Xavier Yao", "http://github.com/xavieryao"] translators: - ["Frederik Ring", "https://github.com/m90"] - ["Philipp Fischbeck", "https://github.com/PFischbeck"] --- CoffeeScript ist eine kleine Sprache, die eins zu eins nach JavaScript übersetzt wird - es findet keine Interpretation zur Laufzeit statt. Als Nachfolger von JavaScript konzipiert, gibt CoffeeScript sein Bestes, lesbaren, gut formatierten und sauber laufenden JavaScript-Code zu erzeugen, der in jeder JavaScript-Laufzeit einwandfrei funktioniert. Auf [der CoffeeScript Website](http://coffeescript.org/) gibt es ein ausführliches Tutorial. ``` coffeescript # CoffeeScript ist eine dieser Sprachen für "Hipster" # und folgt daher vielen Trends und Einflüssen aus modernen Sprachen. # Kommentare werden daher wie in Ruby und Python mit Hashes gekennzeichnet ### Kommentarblöcke sehen aus wie diese und werden direkt nach '/ *'s und '* /'s im erzeugten JavaScript umgewandelt. Vorweg: bevor du mit CoffeeScript anfängst, solltest du bereits einen guten Überblick über die Sprache JavaScript haben. ### # Zuweisung: number = 42 #=> var number = 42; opposite = true #=> var opposite = true; # Bedingungen: number = -42 if opposite #=> if(opposite) { number = -42; } # Funktionen: square = (x) -> x * x #=> var square = function(x) { return x * x; } fill = (container, liquid = "Kaffee") -> "#{container} wird mit #{liquid} gefüllt..." #=>var fill; # #fill = function(container, liquid) { # if (liquid == null) { # liquid = "Kaffee"; # } # return container + " wird mit " + liquid + " gefüllt..."; #}; # "Ranges": list = [1..5] #=> var list = [1, 2, 3, 4, 5]; # Objekte: math = root: Math.sqrt square: square cube: (x) -> x * square x #=> var math = { # "root": Math.sqrt, # "square": square, # "cube": function(x) { return x * square(x); } #} # "Splats": race = (winner, runners...) -> print winner, runners #=>race = function() { # var runners, winner; # winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : []; # return print(winner, runners); #}; # Existenz-Operator: alert "Hab ich's nicht gesagt?" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("Hab ich's nicht gesagt?"); } # Listen-Abstraktion: cubes = (math.cube num for num in list) #=>cubes = (function() { # var _i, _len, _results; # _results = []; # for (_i = 0, _len = list.length; _i < _len; _i++) { # num = list[_i]; # _results.push(math.cube(num)); # } # return _results; # })(); foods = ['Brokkoli', 'Spinat', 'Schokolade'] eat food for food in foods when food isnt 'Schokolade' #=>foods = ['Brokkoli', 'Spinat', 'Schokolade']; # #for (_k = 0, _len2 = foods.length; _k < _len2; _k++) { # food = foods[_k]; # if (food !== 'Schokolade') { # eat(food); # } #} ``` ## Weiterführende Links - [Smooth CoffeeScript](http://autotelicum.github.io/Smooth-CoffeeScript/) - [CoffeeScript Ristretto](https://leanpub.com/coffeescript-ristretto/read) ================================================ FILE: de/crystal.md ================================================ --- contributors: - ["Vitalii Elenhaupt", "http://veelenga.com"] - ["Arnaud Fernandés", "https://github.com/TechMagister/"] translators: - ["caminsha", "https://github.com/caminsha"] --- ```crystal # Das ist ein Kommentar # Alles ist ein Objekt nil.class # => Nil 100.class # => Int32 true.class # => Bool # Falschwerte sind: nil, false und Nullpointer !nil # => true : Bool !false # => true : Bool !0 # => false : Bool # Integer 1.class # => Int32 # Fünf vorzeichenbehaftete Ganzzahlen 1_i8.class # => Int8 1_i16.class # => Int16 1_i32.class # => Int32 1_i64.class # => Int64 1_i128.class # => Int128 # Fünf vorzeichenlose Ganzzahlen 1_u8.class # => UInt8 1_u16.class # => UInt16 1_u32.class # => UInt32 1_u64.class # => UInt64 1_u128.class # => UInt128 2147483648.class # => Int64 9223372036854775808.class # => UInt64 # Binäre Zahlen 0b1101 # => 13 : Int32 # Oktalzahlen 0o123 # => 83 : Int32 # Hexadezimalzahlen 0xFE012D # => 16646445 : Int32 0xfe012d # => 16646445 : Int32 # Gleitkommazahlen (floats) 1.0.class # => Float64 # Es gibt zwei Typen von Gleitkommazahlen 1.0_f32.class # => Float32 1_f32.class # => Float32 1e10.class # => Float64 1.5e10.class # => Float64 1.5e-7.class # => Float64 # Chars (einzelne Zeichen) 'a'.class # => Char # Oktale Schreibweise '\101' # => 'A' : Char # Unicode Schreibweise '\u0041' # => 'A' : Char # Strings (Zeichenketten) "s".class # => String # Strings sind unveränderlich s = "hello, " # => "hello, " : String s.object_id # => 1234667712 : UInt64 s += "Crystal" # => "hello, Crystal" : String s.object_id # => 142528472 : UInt64 # Interpolation wird unterstützt "sum = #{1 + 2}" # => "sum = 3" : String # Mehrzeilige Strings " Dies ist ein mehrzeiliger String." # String mit doppeltem Anführungszeichen %(hello "world") # => "hello \"world\"" # Symbole # Unveränderbare, wiederverwendbare Konstanten, welche intern als Int32 Integer # Werte repräsentiert werden. # Symbole werden oft anstelle von Strings verwendet, um bestimmte Werte zu bestimmen. :symbol.class # => Symbol sentence = :question? # :"question?" : Symbol sentence = :question? # => true : Bool sentence = :exclamation! # => false : Bool sentence = "question?" # => false : Bool # Arrays [1, 2, 3].class # => Array(Int32) [1, "hello", 'x'].class # => Array(Int32 | String | Char) # Leere Arrays sollten einen Typen definieren [] # => Syntaxfehler: für leere Arrays, # verwende `[] of ElementType` [] of Int32 # => [] : Array(Int32) Array(Int32).new # => [] : Array(Int32) # Arrays können indiziert werden array = [1, 2, 3, 4, 5] # => [1, 2, 3, 4, 5] : Array(Int32) array[0] # => 1 : Int32 array[10] # führt zu einem IndexError array[-6] # führt zu einem IndexError array[10]? # => nil : (Int32 | Nil) array[-6]? # => nil : (Int32 | Nil) # Starte am Ende des Arrays array[-1] # => 5 # Mit einem Startindex und einer Länge array[2, 4] # => [3, 4, 5] # oder mit einem Bereich array[1..3] # => [2, 3, 4] # Füge etwas zu einem Array hinzu array << 6 # => [1, 2, 3, 4, 5, 6] # Entferne Einträge am Ende des Arrays array.pop # => 6 array # => [1, 2, 3, 4, 5] # Entferne ersten Eintrag im Array array.shift # => 1 array # => [2, 3, 4, 5] # Überprüfe, ob ein Element in einem Array existiert array.includes? 3 # => true # Spezielle Syntax für String-Arrays und Symbol-Arrays %w(one two three) # => ["one", "two", "three"] : Array(String) %i(one two three) # 0> [:one, :two, :three] : Array(Symbol) # Es gibt auch für andere Arrays eine spezielle Syntax, wenn die Methoden # `.new` und `#<<` definiert werden. set = Set{1, 2, 3} # => [1, 2, 3] set.class # => Set(Int32) # Das obere ist äquivalent zu: set = Set(typeof(1, 2, 3)).new set << 1 set << 2 set << 3 # Hashes {1 => 2, 3 => 4}.class # => Hash(Int32, Int32) {1 => 2, 'a' => 3}.class # => Hash (Int32 | Char, Int32) # Leere Hashes sollten einen Typen spezifizieren {} # Syntaxfehler {} of Int32 => Int32 # {} Hash(Int32, Int32).new # {} # Hashes können schnell mit dem Key nachgeschaut werden hash = {"color" => "green", "number" => 5} hash["color"] # => "green" hash["no_such_key"] # => Fehlender hash key: "no_such_key" (KeyError) hash["no_such_key"]? # => nil # Überprüfe die Existenz eines Hashkeys hash.has_key? "color" # => true # Spezielle Schreibweise für Symbol- und Stringkeys {key1: 'a', key2: 'b'} # {:key1 => 'a', :key2 => 'b'} {"key1": 'a', "key2": 'b'} # {"key1" => 'a', "key2" => 'b'} # Die spezielle Syntax für Hash-Literale gibt es auch für andere Typen, sofern # diese die Methoden `.new` und `#[]=` Methoden definieren. class MyType def []=(key, value) puts "do stuff" end end MyType{"foo" => "bar"} # Das obere ist äquivalent zu: tmp = MyType.new tmp["foo"] = "bar" tmp # Ranges (Bereiche) 1..10 # => Range(Int32, Int32) Range.new(1,10).class # => Range(Int32, Int32) # Ranges können inklusiv oder exklusiv sein. (3..5).to_a # => [3, 4, 5] (3...5).to_a # => [3, 4] # Überprüfe, ob ein Range einen Wert enthält oder nicht. (1..8).includes? 2 # => true # Tupel sind unveränderliche, Stack-zugewiese Folgen von Werten mit fester # Größe und möglicherweise unterschiedlichen Typen {1, "hello", 'x'}.class # => Tuple(Int32, String, Char) # Erhalte den Wert eines Tupels über den Index tuple = {:key1, :key2} tuple[1] # => :key2 tuple[2] # syntax error: Index out of bound # Können auf mehrere Variablen erweitert werden a, b, c = {:a, 'b', "c"} a # => :a b # => 'b' c # => "c" # Procs repräsentieren ein Funktionspointer mit einem optionalen Kontext. # Normalerweise wird ein Proc mit einem proc-Literal erstellt. proc = ->(x : Int32) { x.to_s } proc.class # => Print(Int32, String) # Außerdem kann man auch mit der Methode `new` ein Proc erstellen. Proc(Int32, String).new { |x| x.to_s } # Rufe ein Proc auf mit der Methode `call` proc.call 10 # => "10" # Kontrollstatements if true "if statement" elsif false "else-f, optional" else "else, auch optional" end puts "if as a suffix" if true # => if as a suffix # If als Ausdruck a = if 2 > 1 3 else 4 end a # => 3 # Bedingter ternärer Ausdruck a = 1 > 2 ? 3 : 4 # => 4 # Case-Statement cmd = "move" action = case cmd when "create" "Creating..." when "copy" "Copying..." when "move" "Moving..." when "delete" "Deleting..." end action # => "Moving..." # Schleifen index = 0 while index <= 3 puts "Index: #{index}" index += 1 end # Index: 0 # Index: 1 # Index: 2 # Index: 3 index = 0 until index > 3 puts "Index: #{index}" index += 1 end # Index: 0 # Index: 1 # Index: 2 # Index: 3 # Der bevorzugte Weg, ist `each` zu verwenden. (1..3).each do |index| puts "Index: #{index}" end # Index: 1 # Index: 2 # Index: 3 # Der Typ der Variablen hängt vom Typen innerhalb der Kontrollanweisung ab if a < 3 a = "hello" else a = true end typeof a # => (Bool | String) if a && b # Hier wird garantiert, dass weder a noch b vom Typ Nil sind end if a.is_a? String a.class # => String end # Funktionen def double(x) x * 2 end # Funktionen geben implizit den Wert der letzten Anweisung zurück # Dies ist auch bei anderen Blöcken der Fall. double(2) # => 4 # Klammern müssen nicht gesetzt werden, wenn der Aufruf eindeutig ist double 3 # => 6 double double 3 # => 12 def sum(x, y) x + y end # Funktionsargumente werden mit einem Komma separiert. sum 3, 4 # => 7 sum sum(3, 4), 5 # => 12 # yield # Alle Methoden haben einen impliziten, optionalen Blockparameter. # Dieser kann mit dem Schlüsselwort `yield` aufgerufen werden. def surround puts '{' yield puts '}' end surround { puts "Hallo Welt" } # { # Hallo Welt # } # Du kannst ein Block einer Funktion übergeben. # "&" kennzeichnet eine Referenz zu einem übergebenen Block def guests(&block) block.call "some_argument" end # Du kannst eine Liste von Argumenten mitgeben, welche zu einem Array # umgewandelt werden. # Hierfür ist der Splat-Operator ("*") def guests(*array) array.each { |guest| puts guest } end # Wenn eine Methode ein Array zurückgibt, kann destrukturiende Zuordnung # verwendet werden. def foods ["pancake", "sandwich", "quesadilla"] end breakfast, lunch, dinner = foods breakfast # => "pancake" dinner # => "quesadilla" # Gemäß der Konvention enden alle Methoden, welchen einen Boolean zurückgeben # mit einem Fragezeichen. 5.even? # false 5.odd? # true # Und wenn eine Methode mit einem Ausrufezeichen endet, macht sie etwas # destruktives. Zum Beispiel wird der Aufrufer verändert. Einige Methoden haben # eine !-Version, um eine Änderung zu machen und eine Nicht-!-Version, welche # lediglich eine neue veränderte Version zurückgibt. company_name = "Dunder Mifflin" company_name.gsub "Dunder", "Donald" # => "Donald Mifflin" company_name # => "Dunder Mifflin" company_name.gsub! "Dunder", "Donald" company_name # => "Donald Mifflin" # definiere eine Klasse mit dem Schlüsselwort `class`. class Human # eine Klassenvariable. Diese wird mit allen Instanzen dieser Klasse geteilt. @@species = "H. sapiens" # type of name is String @name: String # Grundlegender Intialisierer # Weise das Argument der Instanz-Variable "name" zu # Wenn kein Alter angegeben wird, wird der Default (hier 0) genommen. def initialize(@name, @age = 0) end # Einfache Setter-Methode def name=(name) @name = name end # einfache Getter-Methode def name @name end # Die obere Funktionalität kann mit der property-Methode gekapselt werden: property :name # Getter/Setter-Methoden können auch individuell erstellt werden: getter :name setter :name # eine Klassenmethode verwendet `self` um sich von Instanzmethoden zu # unterscheiden. Diese kann lediglich von einer Klasse aufgerufen werden, # nicht von einer Instanz. def self.say(msg) puts msg end def species @@species end end # Eine Klasse instanziieren jim = Human.new("Jim Halpert") dwight = Human.new("Dwight K. Schrute") # Lass uns ein paar Methoden aufrufen jim.species # => "H. sapiens" jim.name # => "Jim Halpert" jim.name = "Jim Halpert II" # => "Jim Halpert II" jim.name # => "Jim Halpert II" dwight.species # => "H. sapiens" dwight.name # => "Dwight K. Schrute" # Rufe die Klassenmethode auf Human.say("Hi") # => gibt Hi aus und gibt `nil` zurück # Variablen, welche mit @ starten, sind im Scope der Instanz class TestClass @var = "Ich bin eine Instanzvariable" end # Variablen, welche mit @@ starten, sind im Scope der Klasse class TestClass @@var = "Ich bin eine Klassenvariable" end # Variablen, welche mit einem Großbuchstaben starten, sind Konstanten. Var = "Ich bin eine Konstante" Var = "Ich kann nicht aktualisiert werden." # Die Konstante Var wurde bereits # initialisiert. # In Crystal ist Class auch ein Objekt. Dadurch können Klassen Instanzvariablen # haben. Klassenvariablen werden mit der Klasse und allen Subklassen geteilt. # Basisklasse class Human @@foo = 0 def self.foo @@foo end def self.foo=(value) @@foo = value end end # abgeleitete Klasse class Worker < Human end Human.foo # => 0 Worker.foo # => 0 Human.foo = 2 # => 2 Worker.foo # => 0 Worker.foo = 3 # => 3 Human.foo # => 2 Worker.foo # => 3 module ModuleExample def foo "foo" end end # Wenn ein Modul mit include eingeschlossen wird, so werden die Methoden an die # Instanzen gebunden. # Wenn eine Klasse mit einem Modul erweitert wird, so werden die Methoden an die # Klasse selbst gebunden. class Person include ModuleExample end class Book extend ModuleExample end Person.foo # => undefinierte Methode 'foo' für Person:Class Person.new.foo # => 'foo' Book.foo # => 'foo' Book.new.foo # => undefinierte Methode für Book # Ausnahmebehandlung # Definiere eine neue Ausnahme class MyException < Exception end # Definiere eine weitere Ausnahme class MyAnotherException < Exception; end ex = begin raise MyException.new rescue ex1 : IndexError "ex1" rescue ex2 : MyException | MyAnotherException "ex2" rescue ex3 : Exception "ex3" rescue ex4 # fange alle Ausnahmen ab "ex4" end ex # => "ex2" ``` ## Weitere Unterlagen - [offizielle Dokumentation, englisch](https://crystal-lang.org/) ================================================ FILE: de/csharp.md ================================================ --- contributors: - ["Irfan Charania", "https://github.com/irfancharania"] - ["Max Yankov", "https://github.com/golergka"] - ["Melvyn Laïly", "http://x2a.yt"] - ["Shaun McCarthy", "http://www.shaunmccarthy.com"] translators: - ["Frederik Ring", "https://github.com/m90"] --- C# ist eine elegante, typsichere und objektorientierte Sprache, mit der Entwickler eine Vielzahl sicherer und robuster Anwendungen erstellen können, die im .NET Framework ausgeführt werden. [Mehr über C# erfährst du hier.](http://msdn.microsoft.com/de-de/library/vstudio/z1zx9t92.aspx) ```c# // Einzeilige Kommentare starten mit zwei Schrägstrichen: // /* Mehrzeile Kommentare wie in C Schrägstrich / Stern */ /// /// XML-Kommentare können zur automatisierten Dokumentation verwendet werden /// // Zu Beginn werden die in der Datei verwendeten Namespaces aufgeführt using System; using System.Collections.Generic; using System.Data.Entity; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Threading.Tasks; using System.IO; // definiert einen Namespace um Code in "packages" zu organisieren namespace Learning { // Jede .cs-Datei sollte zumindest eine Klasse mit dem Namen der Datei // enthalten. Das ist zwar nicht zwingend erforderlich, es anders zu // handhaben führt aber unweigerlich ins Chaos (wirklich)! public class LearnCSharp { // Zuerst erklärt dieses Tutorial die Syntax-Grundlagen, // wenn du bereits Java oder C++ programmieren kannst: // lies bei "Interessante Features" weiter! public static void Syntax() { // Mit Console.WriteLine kannst du einfachen Text ausgeben: Console.WriteLine("Hallo Welt"); Console.WriteLine( "Integer: " + 10 + " Double: " + 3.14 + " Boolean: " + true); // Console.Write erzeugt keinen Zeilenumbruch Console.Write("Hallo "); Console.Write("Welt"); /////////////////////////////////////////////////// // Typen & Variablen /////////////////////////////////////////////////// // Deklariere eine Variable mit // Sbyte - Vorzeichenbehaftete 8-Bit Ganzzahl // (-128 <= sbyte <= 127) sbyte fooSbyte = 100; // Byte - Vorzeichenlose 8-Bit Ganzzahl // (0 <= byte <= 255) byte fooByte = 100; // Short - 16-Bit Ganzzahl // Vorzeichenbehaftet - (-32,768 <= short <= 32,767) // Vorzeichenlos - (0 <= ushort <= 65,535) short fooShort = 10000; ushort fooUshort = 10000; // Integer - 32-bit Ganzzahl int fooInt = 1; // (-2,147,483,648 <= int <= 2,147,483,647) uint fooUint = 1; // (0 <= uint <= 4,294,967,295) // Long - 64-bit Ganzzahl long fooLong = 100000L; // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) ulong fooUlong = 100000L; // (0 <= ulong <= 18,446,744,073,709,551,615) // Ganze Zahlen werden standardmäßig - je nach Größe - als int oder // uint behandelt. Ein nachgestelltes L markiert den Wert als long // oder ulong. // Double - Double-precision 64-bit IEEE 754 Fließkommazahl double fooDouble = 123.4; // Genauigkeit: 15-16 Stellen // Float - Single-precision 32-bit IEEE 754 Fließkommazahl float fooFloat = 234.5f; // Genauigkeit: 7 Stellen // Das nachgestellte f zeigt an dass es sich um einen Wert vom Typ // float handelt // Decimal - ein 128-Bit-Datentyp mit größerer Genauigkeit als // andere Fließkommatypen, und somit bestens geeignet für // die Berechnung von Geld- und Finanzwerten decimal fooDecimal = 150.3m; // Boolean - true & false bool fooBoolean = true; // oder false // Char - Ein einzelnes 16-Bit Unicode Zeichen char fooChar = 'A'; // Strings - im Gegensatz zu allen vorhergehenden Basistypen, die // alle Werttypen sind, ist String ein Referenztyp. Strings sind // somit nullable, Werttypen sind dies nicht. string fooString = "\"maskiere\" Anführungszeichen, und füge \n (Umbrüche) und \t (Tabs) hinzu"; Console.WriteLine(fooString); // Jeder Buchstabe eines Strings kann über seinen Index // referenziert werden: char charFromString = fooString[1]; // => 'e' // Strings sind unveränderlich: // `fooString[1] = 'X';` funktioniert nicht // Ein Vergleich zweier Strings, unter Berücksichtigung der // aktuellen, sprachspezifischen Gegebenheiten (also z.B. a,ä,b,c // in deutschsprachigen Umgebungen), und ohne Beachtung von // Groß- und Kleinschreibung: string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase); // Formatierung, genau wie "sprintf" string fooFs = string.Format("Mikrofon Check, {0} {1}, {0} {1:0.0}", 1, 2); // Datumsangaben und Formatierung DateTime fooDate = DateTime.Now; Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy")); // Durch ein vorangestelltes @ lässt sich ein mehrzeiliger String // schreiben. Um " zu maskieren benutzt man "" string bazString = @"Hier geht es zur nächsten Zeile, ""Wahnsinn!"", die Massen waren kaum zu bändigen"; // Die Keywords const oder readonly kennzeichnen eine // unveränderliche Variable/Konstante. Die Werte von Konstanten // werden übrigens bereits zur Compile-Zeit berechnet. const int HOURS_I_WORK_PER_WEEK = 9001; /////////////////////////////////////////////////// // Datenstrukturen /////////////////////////////////////////////////// // Arrays - Index beginnt bei Null // Die Größe des Arrays wird bei der Deklaration festgelegt. // Die syntaktische Struktur um ein neues Array zu erzeugen sieht // folgendermaßen aus: // [] = new []; int[] intArray = new int[10]; // Arrays können auch über ein Array-Literal deklariert werden: int[] y = { 9000, 1000, 1337 }; // Indizierung eines Arrays - Zugriff auf ein bestimmtes Element Console.WriteLine("intArray @ 0: " + intArray[0]); // Arrays sind veränderbar intArray[1] = 1; // Listen // Durch ihre größere Flexibilität kommen Listen in C# weit // häufiger zum Einsatz als Arrays. Eine Liste wird so deklariert: // List = new List(); List intList = new List(); List stringList = new List(); List z = new List { 9000, 1000, 1337 }; // Die <> kennzeichnen "Generics", mehr dazu unter "Coole Sachen" // Listen haben keinen Default-Wert. // Bevor auf einen Index zugegriffen werden kann, muss dieser // auch gesetzt worden sein: intList.Add(1); Console.WriteLine("intList @ 0: " + intList[0]); // Andere interessante Datenstrukturen sind: // Stack/Queue // Dictionary (entspricht einer Hash Map) // HashSet // Read-only Collections // Tuple (.Net 4+) /////////////////////////////////////// // Operatoren /////////////////////////////////////// Console.WriteLine("\n->Operatoren"); // kurze Schreibweise um mehrere Deklarationen zusammenzufassen: // (Benutzung vom C# Styleguide aber ausdrücklich abgeraten!) int i1 = 1, i2 = 2; // Arithmetik funktioniert wie erwartet: Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3 // Modulo Console.WriteLine("11%3 = " + (11 % 3)); // => 2 // Vergleiche Console.WriteLine("3 == 2? " + (3 == 2)); // => false Console.WriteLine("3 != 2? " + (3 != 2)); // => true Console.WriteLine("3 > 2? " + (3 > 2)); // => true Console.WriteLine("3 < 2? " + (3 < 2)); // => false Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true // Bitweise Operatoren /* ~ Unäres bitweises NICHT << Verschieben nach links >> Verschieben nach rechts & Bitweises UND ^ Bitweises exklusives ODER | Bitweises inklusives ODER */ // Inkremente int i = 0; Console.WriteLine("\n->Inkrement / Dekrement"); Console.WriteLine(i++); //i = 1. Post-Inkrement Console.WriteLine(++i); //i = 2. Pre-Inkrement Console.WriteLine(i--); //i = 1. Post-Dekrement Console.WriteLine(--i); //i = 0. Pre-Dekrement /////////////////////////////////////// // Kontrollstrukturen /////////////////////////////////////// Console.WriteLine("\n->Kontrollstrukturen"); // If-Statements funktionieren wie in C int j = 10; if (j == 10) { Console.WriteLine("Ich werde ausgegeben"); } else if (j > 10) { Console.WriteLine("Ich nicht"); } else { Console.WriteLine("Ich leider auch nicht"); } // Ternärer Operator // Anstatt eines einfachen if/else lässt sich auch folgendes schreiben: // ? : int zumVergleich = 17; string isTrue = zumVergleich == 17 ? "Ja" : "Nein"; // while-Schleife int fooWhile = 0; while (fooWhile < 100) { // Wird 100-mal wiederholt, fooWhile 0->99 fooWhile++; } // do-while-Schleife int fooDoWhile = 0; do { // Wird 100-mal wiederholt, fooDoWhile 0->99 fooDoWhile++; } while (fooDoWhile < 100); //for-Schleifen => for(; ; ) for (int fooFor = 0; fooFor < 10; fooFor++) { // Wird 10-mal wiederholt, fooFor 0->9 } // foreach-Schleife // Die normale Syntax für eine foreach-Schleife lautet: // foreach( in ) // foreach kann mit jedem Objekt verwendet werden das IEnumerable // oder IEnumerable implementiert. Alle Auflistungs-Typen // (Array, List, Dictionary...) im .NET Framework implementieren // eines dieser beiden Interfaces. foreach (char character in "Hallo Welt".ToCharArray()) { // Ein Durchgang für jedes Zeichen im String } // (ToCharArray() könnte man hier übrigens auch weglassen, // da String IEnumerable bereits implementiert) // Switch Struktur // Ein Switch funktioniert mit byte, short, char und int Datentypen. // Auch Aufzählungstypen können verwendet werden, genau wie // die Klasse String, und ein paar Sonderklassen, die Wrapper für // Primitives sind: Character, Byte, Short und Integer int month = 3; string monthString; switch (month) { case 1: monthString = "Januar"; break; case 2: monthString = "Februar"; break; case 3: monthString = "März"; break; // Man kann für mehrere Fälle auch dasselbe Verhalten // definieren. Jeder Block muss aber mit einem break-Statement // abgeschlossen werden. Einzelne Fälle können über // `goto case x` erreicht werden case 6: case 7: case 8: monthString = "Sommer!!"; break; default: monthString = "Irgendein anderer Monat"; break; } /////////////////////////////////////// // Umwandlung von Datentypen und Typecasting /////////////////////////////////////// // Umwandlung // von String nach Integer // bei einem Fehler wirft dieser Code eine Exception int.Parse("123"); //gibt die Ganzzahl 123 zurück // TryParse gibt bei einem Fehler den Default-Wert zurück // (im Fall von int: 0) int tryInt; if (int.TryParse("123", out tryInt)) // gibt true oder false zurück { Console.WriteLine(tryInt); // 123 } // von Integer nach String // Die Klasse Convert stellt Methoden zur Konvertierung von // unterschiedlichsten Daten zur Verfügung: Convert.ToString(123); // "123" // oder tryInt.ToString(); // "123" } /////////////////////////////////////// // Klassen /////////////////////////////////////// public static void Classes() { // Benutze das new-Keyword um eine Instanz einer Klasse zu erzeugen Bicycle trek = new Bicycle(); // So werden Methoden der Instanz aufgerufen trek.SpeedUp(3); // Es empfiehlt sich immer Getter und Setter zu benutzen trek.Cadence = 100; // ToString ist eine Konvention über die man üblicherweise // Informationen über eine Instanz erhält Console.WriteLine("Infos zu trek: " + trek.ToString()); // Wir instantiieren ein neues Hochrad PennyFarthing funbike = new PennyFarthing(1, 10); Console.WriteLine("Infos zu funbike: " + funbike.ToString()); Console.Read(); } // Ende der Methode main // Main als Konsolenstartpunkt // Eine Konsolenanwendung muss eine Methode Main als Startpunkt besitzen public static void Main(string[] args) { OtherInterestingFeatures(); } /////////////////////////////////////// // Interessante Features /////////////////////////////////////// // Methodensignaturen public // Sichtbarkeit static // Erlaubt einen Zugriff auf der Klasse (nicht auf einer Instanz) int // Typ des Rückgabewerts, MethodSignatures( // Erstes Argument, erwartet int int maxCount, // setzt sich selbst auf 0, wenn kein anderer Wert übergeben wird int count = 0, int another = 3, // enthält alle weiteren der Methode übergebenen Parameter (quasi Splats) params string[] otherParams ) { return -1; } // Methoden können überladen werden, solange sie eindeutige // Signaturen haben public static void MethodSignatures(string maxCount) { } // Generische Typen // Die Typen für TKey und TValue werden erst beim Aufruf der Methode // festgelegt. Diese Methode emuliert z.B. SetDefault aus Python: public static TValue SetDefault( IDictionary dictionary, TKey key, TValue defaultItem) { TValue result; if (!dictionary.TryGetValue(key, out result)) { return dictionary[key] = defaultItem; } return result; } // Möglichen Typen lassen sich auch über ihr Interface beschränken: public static void IterateAndPrint(T toPrint) where T: IEnumerable { // Da T ein IEnumerable ist können wir foreach benutzen foreach (var item in toPrint) { // Item ist ein int Console.WriteLine(item.ToString()); } } public static void OtherInterestingFeatures() { // Optionale Parameter MethodSignatures(3, 1, 3, "Ein paar", "extra", "Strings"); // setzt explizit einen bestimmten Parameter, andere werden übersprungen MethodSignatures(3, another: 3); // Erweiterungsmethoden int i = 3; i.Print(); // Weiter unten definiert // Nullables - perfekt für die Interaktion mit // Datenbanken / Rückgabewerten // Jeder Wert (d.h. keine Klassen) kann durch das Nachstellen eines ? // nullable gemacht werden: ? = int? nullable = null; // Die explizite Langform wäre Nullable Console.WriteLine("Mein Nullable: " + nullable); bool hasValue = nullable.HasValue; // true wenn nicht null // ?? ist "syntaktischer Zucker" um einen Default-Wert für den Fall, // dass die Variable null ist festzulegen. int notNullable = nullable ?? 0; // 0 // Implizit typisierte Variablen // Man kann auch den Typ einer Variable auch vom Compiler // bestimmen lassen: var magic = "magic ist zur Compile-Zeit ein String, folglich geht keine Typsicherheit verloren"; magic = 9; // funktioniert nicht da magic vom Typ String ist // Generics var phonebook = new Dictionary() { {"Resi", "08822 / 43 67"} // Fügt einen Eintrag zum Telefonbuch hinzu }; // Hier könnte man auch unser generisches SetDefault von // weiter oben benutzen: Console.WriteLine(SetDefault(phonebook, "Xaver", "kein Telefon")); // kein Telefon // TKey und TValue müssen nicht zwingend angegeben werden, da sie // auch implizit vom Compiler ermittelt werden können Console.WriteLine(SetDefault(phonebook, "Resi", "kein Telefon")); // 08822 / 43 67 // Lambdas - konzise Syntax für Inline-Funktionen Func square = (x) => x * x; // Das letzte Element vom Typ T ist der Rückgabewert Console.WriteLine(square(3)); // 9 // Disposables - einfaches Management von nicht verwalteten Ressourcen // So gut wie alle Objekte die auf nicht verwaltete Ressourcen // (Dateien, Geräte, ...) zugreifen, implementieren das Interface // IDisposable. Das using Statement stellt sicher, dass die vom // IDisposable benutzten Ressourcen nach der Benutzung wieder // freigegeben werden: using (StreamWriter writer = new StreamWriter("log.txt")) { writer.WriteLine("Alles bestens!"); // Am Ende des Codeblocks werden die Ressourcen wieder // freigegeben - auch im Falle einer Exception } // Parallel Klasse // http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx var websites = new string[] { "http://www.google.com", "http://www.reddit.com", "http://www.shaunmccarthy.com" }; var responses = new Dictionary(); // Für jeden Request wird ein neuer Thread erzeugt, der nächste // Schritt wird erst nach Beendigung aller Tasks ausgeführt Parallel.ForEach(websites, // maximal 3 Threads gleichzeitig new ParallelOptions() {MaxDegreeOfParallelism = 3}, website => { // Hier folgt eine langwierige, asynchrone Operation using (var r = WebRequest.Create(new Uri(website)).GetResponse()) { responses[website] = r.ContentType; } }); // Dieser Code wird erst nach Beendigung aller Requests ausgeführt foreach (var key in responses.Keys) { Console.WriteLine("{0}:{1}", key, responses[key]); } // Dynamische Objekte (gut um mit anderen Sprachen zu arbeiten) dynamic student = new ExpandoObject(); // hier muss kein Typ angegeben werden student.FirstName = "Christian"; // Einem solchen Objekt kann man sogar Methoden zuordnen. // Das Beispiel gibt einen String zurück und erwartet einen String student.Introduce = new Func( (introduceTo) => string.Format("Hallo {0}, das ist {1}", student.FirstName, introduceTo)); Console.WriteLine(student.Introduce("Bettina")); // IQueryable - So gut wie alle Aufzählungstypen implementieren // dieses Interface, welches eine Vielzahl von funktionalen Methoden // wie Map / Filter / Reduce zur Verfügung stellt: var bikes = new List(); // sortiert die Liste bikes.Sort(); // sortiert nach Anzahl Räder bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); var result = bikes // diese Filter können auch aneinandergehängt werden .Where(b => b.Wheels > 3) // (gibt ein IQueryable des vorherigen Typs zurück) .Where(b => b.IsBroken && b.HasTassles) // diese Zuordnung gibt ein IQueryable zurück .Select(b => b.ToString()); // "Reduce" - addiert alle Räder der Aufzählung zu einem Wert var sum = bikes.Sum(b => b.Wheels); // So erzeugt man ein implizit typisiertes Objekt, basierend auf // den Parametern der Elemente: var bikeSummaries = bikes.Select(b=>new { Name = b.Name, IsAwesome = !b.IsBroken && b.HasTassles }); // Auch wenn wir es hier nicht demonstrieren können: // In einer IDE wie VisualStudio kriegen wir hier sogar TypeAhead, // da der Compiler in der Lage ist, die passenden Typen zu erkennen. foreach (var bikeSummary in bikeSummaries.Where(b => b.IsAwesome)) { Console.WriteLine(bikeSummary.Name); } // AsParallel-Methode // Jetzt kommen die Schmankerl! Die AsParallel-Methode kombiniert // LINQ und parallele Operationen: var threeWheelers = bikes.AsParallel().Where(b => b.Wheels == 3).Select(b => b.Name); // Diese Berechnung passiert parallel! Benötigte Threads werden // automatisch erzeugt, und die Rechenlast unter ihnen aufgeteilt. // Ein Traum für die Verarbeitung von großen Datenmengen // auf mehreren Cores! // LINQ - bildet einen Datenspeicher auf IQueryable Objekte ab // LinqToSql beispielsweise speichert und liest aus einer // SQL-Datenbank, LinqToXml aus einem XML-Dokument. // LINQ-Operationen werden "lazy" ausgeführt. var db = new BikeRepository(); // Die verzögerte Ausführung ist optimal für Datenbankabfragen var filter = db.Bikes.Where(b => b.HasTassles); // noch keine Abfrage // Es können noch mehr Filter hinzugefügt werden (auch mit // Bedingungen) - ideal für z.B. "erweiterte Suchen" if (42 > 6) { filter = filter.Where(b => b.IsBroken); // immer noch keine Abfrage } var query = filter .OrderBy(b => b.Wheels) .ThenBy(b => b.Name) .Select(b => b.Name); // auch hier: immer noch keine Abfrage // Erst hier wird die Datenbankabfrage wirklich ausgeführt, // limitiert auf die Elemente, die der foreach-Loop verwendet foreach (string bike in query) { Console.WriteLine(result); } } } // Ende der Klasse LearnCSharp // Eine .cs-Datei kann auch mehrere Klassen enthalten public static class Extensions { // Erweiterungsmethoden public static void Print(this object obj) { Console.WriteLine(obj.ToString()); } } // Syntax zur Deklaration einer Klasse: // class { // // Datenfelder, Konstruktoren und Methoden leben alle // // innerhalb dieser Deklaration // } public class Bicycle { // Felder/Variablen der Klasse "Bicycle" // Das Keyword public macht das Member von überall zugänglich public int Cadence { get // get definiert eine Methode, um die Eigenschaft abzurufen { return _cadence; } set // set definiert eine Methode, um die Eigenschaft zu setzen { _cadence = value; // value ist der dem Setter übergebene Wert } } private int _cadence; // Das Keyword protected macht das Member nur für die Klasse selbst // und ihre Subklassen zugänglich protected virtual int Gear { get; // erzeugt eine Eigenschaft für die kein "Zwischenwert" benötigt wird set; } // Das Keyword internal macht das Member innerhalb der Assembly zugänglich internal int Wheels { get; private set; // get/set kann auch über Keywords modifiziert werden } int _speed; // Member ohne vorangestellte Keywords sind standardmäßig // private, sie sind nur innerhalb der Klasse zugänglich. // Man kann aber natürlich auch das Keyword private benutzen. private string Name { get; set; } // Ein Enum ist ein klar definierter Satz an benannten Konstanten. // Eigentlich ordnet es diese Konstanten nur bestimmten Werten zu // (einer int-Zahl, solange nicht anders angegeben). Mögliche Typen für // die Werte eines Enums sind byte, sbyte, short, ushort, int, uint, // long, oder ulong. Alle Werte in einem Enum sind eindeutig. public enum BikeBrand { Colnago, EddyMerckx, Bianchi = 42, // so kann man den Wert explizit setzen Kynast // 43 } // Nachdem dieser Typ in der Klasse "Bicycle" definiert ist, // sollte Code außerhalb der Klasse den Typen als Bicycle.Brand referenzieren // Nachdem das Enum deklariert ist, können wir den Typen verwenden: public BikeBrand Brand; // Als static gekennzeichnete Member gehören dem Typ selbst, // nicht seinen Instanzen. Man kann sie also ohne Referenz zu einem // Objekt benutzen // Console.WriteLine("Schon " + Bicycle.BicyclesCreated + " Fahrräder, nur für dieses Tutorial!"); static public int BicyclesCreated = 0; // readonly-Werte werden zur Laufzeit gesetzt // Ihr Wert kann nur bei ihrer Deklaration, oder in einem Konstruktor // festgelegt werden readonly bool _hasCardsInSpokes = false; // readonly und private // Konstruktoren bestimmen was bei einer Instantiierung passiert. // Das ist ein Default-Konstruktor: public Bicycle() { // Member der Klasse können über das Keyword this erreicht werden this.Gear = 1; // oft ist das aber gar nicht nötig Cadence = 50; _speed = 5; Name = "Bonanzarad"; Brand = BikeBrand.Kynast; BicyclesCreated++; } // Das ist ein spezifischer Konstruktor (d.h. er erwartet Argumente): public Bicycle(int startCadence, int startSpeed, int startGear, string name, bool hasCardsInSpokes, BikeBrand brand) : base() // ruft zuerst den "base"-Konstruktor auf { Gear = startGear; Cadence = startCadence; _speed = startSpeed; Name = name; _hasCardsInSpokes = hasCardsInSpokes; Brand = brand; } // Konstruktoren können aneinandergehängt werden: public Bicycle(int startCadence, int startSpeed, BikeBrand brand) : this(startCadence, startSpeed, 0, "richtig große Räder", true, brand) { } // Syntax für Methoden: // () // Klassen können Getter und Setter für Werte definieren, // oder diese Werte direkt als Eigenschaft implementieren // (in C# der bevorzugte Weg) // Parameter von Methoden können Default-Werte haben. // "SpeedUp" kann man also auch ohne Parameter aufrufen: public void SpeedUp(int increment = 1) { _speed += increment; } public void SlowDown(int decrement = 1) { _speed -= decrement; } // Eigenschaften mit get/set // wenn es nur um den Zugriff auf Daten geht, ist eine Eigenschaft zu // empfehlen. Diese können Getter und Setter haben, oder auch nur // einen Getter bzw. einen Setter private bool _hasTassles; // private Variable public bool HasTassles // öffentliches Interface { get { return _hasTassles; } set { _hasTassles = value; } } // Das kann man auch kürzer schreiben: // Dieser Syntax erzeugt automatisch einen hinterlegten Wert, // (entsprechend `private bool _isBroken`) der gesetzt // bzw. zurückgegeben wird: public bool IsBroken { get; private set; } public int FrameSize { get; // für Getter und Setter kann der Zugriff auch einzeln // beschränkt werden, FrameSize kann also nur von innerhalb // der Klasse "Bicycle" gesetzt werden private set; } // Diese Methode gibt eine Reihe an Informationen über das Objekt aus: public virtual string ToString() { return "Gang: " + Gear + " Kadenz: " + Cadence + " Geschwindigkeit: " + _speed + " Name: " + Name + " Hipster-Karten zwischen den Speichen: " + (_hasCardsInSpokes ? "Na klar!" : "Bloß nicht!") + "\n------------------------------\n" ; } // Auch Methoden können als static gekennzeichnet werden, nützlich // beispielsweise für Helper-Methoden public static bool DidWeCreateEnoughBicyclesYet() { // In einer statischen Methode können wir natürlich auch nur // statische Member der Klasse referenzieren return BicyclesCreated > 9000; } // Wenn eine Klasse nur statische Member enthält, kann es eine gute Idee // sein die Klasse selbst als static zu kennzeichnen } // Ende der Klasse "Bicycle" // "PennyFarthing" ist eine Unterklasse von "Bicycle" class PennyFarthing : Bicycle { // (Hochräder - englisch Penny Farthing - sind diese antiken Fahrräder // mit riesigem Vorderrad. Sie haben keine Gangschaltung.) // hier wird einfach der Elternkonstruktor aufgerufen public PennyFarthing(int startCadence, int startSpeed) : base(startCadence, startSpeed, 0, "Hochrad", true, BikeBrand.EddyMerckx) { } protected override int Gear { get { return 0; } set { throw new ArgumentException("Ein Hochrad hat keine Gangschaltung, doh!"); } } public override string ToString() { string result = "Hochrad "; result += base.ToString(); // ruft die "base"-Version der Methode auf return result; } } // Interfaces (auch Schnittstellen genannt) definieren nur die Signaturen // ihrer Member, enthalten aber auf keinen Fall ihre Implementierung: interface IJumpable { // Alle Member eines Interfaces sind implizit public void Jump(int meters); } interface IBreakable { // Interfaces können Eigenschaften, Methoden und Events definieren bool Broken { get; } } // Eine Klasse kann nur von einer Klasse erben, kann aber eine beliebige // Anzahl von Interfaces implementieren class MountainBike : Bicycle, IJumpable, IBreakable { int damage = 0; public void Jump(int meters) { damage += meters; } public bool Broken { get { return damage > 100; } } } // Das hier stellt eine Datenbankverbindung für das LinqToSql-Beispiel her. // EntityFramework Code First ist großartig // (ähnlich zu Ruby's ActiveRecord, aber bidirektional) // http://msdn.microsoft.com/de-de/data/jj193542.aspx public class BikeRepository : DbSet { public BikeRepository() : base() { } public DbSet Bikes { get; set; } } } // Ende des Namespaces ``` ## In dieser Übersicht nicht enthalten sind die Themen: * Flags * Attributes * Statische Eigenschaften * Exceptions, Abstraction * ASP.NET (Web Forms/MVC/WebMatrix) * Winforms * Windows Presentation Foundation (WPF) ## Zum Weiterlesen gibt es viele gute Anlaufpunkte: * [DotNetPerls](http://www.dotnetperls.com) * [C# in Depth](http://manning.com/skeet2) * [Programming C#](http://shop.oreilly.com/product/0636920024064.do) * [LINQ](http://shop.oreilly.com/product/9780596519254.do) * [MSDN Library](http://msdn.microsoft.com/en-us/library/618ayhy6.aspx) * [ASP.NET MVC Tutorials](http://www.asp.net/mvc/tutorials) * [ASP.NET Web Matrix Tutorials](http://www.asp.net/web-pages/overview/exploring-webmatrix) * [ASP.NET Web Forms Tutorials](http://www.asp.net/web-forms/tutorials) * [Windows Forms Programming in C#](http://www.amazon.com/Windows-Forms-Programming-Chris-Sells/dp/0321116208) [C# Coding Conventions](http://msdn.microsoft.com/de-de/library/vstudio/ff926074.aspx) ================================================ FILE: de/css.md ================================================ --- contributors: - ["Mohammad Valipour", "https://github.com/mvalipour"] translators: - ["Kyr", "http://github.com/kyrami"] --- In den frühen Tagen des Internets gab es keine visuellen Elemente, alles war nur reiner Text. Aber mit der Weiterentwicklung von Browsern wurden auch vollständig visuelle Webseiten zu einem Standard. Durch Verwendung von CSS lässt sich eine strikte Trennung zwischen HTML-Code und Designelementen erreichen. Kurzgefasst, CSS ermöglicht es, verschiedene HTML-Elemente innerhalb eines Dokuments auszuwählen und ihnen visuelle Eigenschaften zu geben. CSS hat wie jede andere Sprache viele Versionen. Hier fokussieren wir uns auf CSS2.0, welche nicht die neueste, aber die am weitesten verbreitete und unterstützte Version ist. **HINWEIS:** Weil die Ausgabe von CSS visuelle Eigenschaften sind, wirst du wahrscheinlich eine CSS-Sandbox wie [dabblet](http://dabblet.com/) benutzen müssen, um die Sprache richtig zu lernen. In diesem Artikel wird am meisten auf generelle Hinweise und die Syntax geachtet. ```css /* Kommentare werden in Sternchen-Schrägstrichkombinationen gepackt (genauso wie hier!) */ /* #################### ## SELEKTOREN ####################*/ /* Eigentlich ist das grundlegende CSS-Statement sehr simpel */ selektor { eigenschaft: wert; /* mehr Eigenschaften...*/ } /* Der Selektor wird dazu benutzt, ein Element auf der Seite auszuwählen. Man kann aber auch alle Elemente auf einer Seite auswählen! */ * { color:red; } /* farbe:rot */ /* Angenommen, wir haben folgendes Element auf einer Seite:
*/ /* kann man es so über seine Klasse auswählen */ .eine-klasse { } /* oder über beide Klassen! */ .eine-klasse.klasse2 { } /* oder über den Namen des Tags */ div { } /* oder über seine Id */ #eineId { } /* oder darüber, dass es ein Attribut hat! */ [attr] { font-size:smaller; } /* oder auch darüber, dass das Attribut einen bestimmten Wert hat */ [attr='wert'] { font-size:smaller; } /* beginnt mit dem übergebenen Wert */ [attr^='we'] { font-size:smaller; } /* endet damit */ [attr$='rt'] { font-size:smaller; } /* oder beinhaltet einen Teil davon */ [attr~='er'] { font-size:smaller; } /* Noch wichtiger ist aber die Möglichkeit, all das miteinander kombinieren zu können - man sollte hierbei nur mit der Leerzeichensetzung vorsichtig sein, ein Leerzeichen macht es zu zwei verschiedenen Selektoren */ div.eine-klasse[attr$='rt'] { } /* so ist es richtig */ /* Man kann auch ein Element über seine Elternelemente auswählen */ /* > wählt ein direktes Kind aus */ div.ein-elternteil > .klassen-name {} /* Mit einem Leerzeichen getrennt kann man alle Elternelemente ansprechen */ /* Das folgende heißt also, dass jedes Element mit der Klasse 'klassen-name' und dem Elternteil IN JEDER TIEFE ausgewählt wird */ div.ein-elternteil .klassen-name {} /* Achtung: das selbe ohne das Leerzeichen hat eine andere Bedeutung, kannst du mir sagen, was? */ div.ein-elternteil.klassen-name {} /* Man kann ein Element auch nach seinem direkten Nachbarelement auswählen */ .ich-bin-vorher + .dieses-element { } /* Oder über jedes Geschwisterelement davor */ .ich-kann-jeder-davor-sein ~ .dieses-element {} /* Mit Pseudoklassen lassen sich Elemente anhand ihres momentanen Zustands auf der Seite auswählen (anstatt über die Seitenstruktur) */ /* Zum Beispiel, wenn über ein Element mit dem Mauszeiger gefahren wird */ :hover {} /* Oder einen bereits besuchten Link*/ :visited {} /* Oder einen noch nicht besuchten Link*/ :link {} /* Oder ein Eingabeelement, das zurzeit im Fokus steht */ :focus {} /* #################### ## EIGENSCHAFTEN ####################*/ selector { /* Einheiten */ width: 50%; /* in Prozent */ font-size: 2em; /* mal der derzeitigen Schriftgröße */ width: 200px; /* in Pixeln */ font-size: 20pt; /* in Punkten */ width: 5cm; /* in Zentimetern */ width: 50mm; /* in Millimetern */ width: 5in; /* in Zoll */ /* Farben */ background-color: #F6E /* in kurzem Hex */ background-color: #F262E2 /* in langem Hex */ background-color: tomato /* kann auch eine benannte Farbe sein */ background-color: rgb(255, 255, 255) /* in RGB */ background-color: rgb(10%, 20%, 50%) /* in RGB Prozent */ background-color: rgba(255, 0, 0, 0.3); /* in semi-transparentem RGB */ /* Bilder */ background-image: url(/pfad-zum-bild/image.jpg); /* Schriften */ font-family: Arial; font-family: "Courier New"; /* wenn der Name ein Leerzeichen enthält, kommt er in Anführungszeichen */ font-family: "Courier New", Trebuchet, Arial; /* wird die erste Schriftart nicht gefunden, wird die zweite benutzt, usw. */ } ``` ## Benutzung Speichere das CSS, das du benutzen willst, mit der Endung '.css'. ```xml
``` ## Spezifität Ein Element kann natürlich auch von mehr als einer Regel in einem Stylesheet angesprochen werden und kann eine Eigenschaft auch öfters als einmal zugewiesen bekommen. In diesen Fällen gibt es Regeln, die die Spezifität von Selektoren regeln. Wir haben dieses CSS: ```css /*A*/ p.klasse1[attr='wert'] /*B*/ p.klasse1 {} /*C*/ p.klasse2 {} /*D*/ p {} /*E*/ p { property: wert !important; } ``` und das folgende Markup: ```xml

``` Die Spezifität der Stile ist wie folgt: (die Spezifität gilt nur für **einzelne Eigenschaften**, nicht für ganze Blöcke) * `E` hat die größte Spezifität wegen des Schlüsselworts `!important`. man sollte diese Form aber vermeiden. * `F` ist als nächstes dran, da es direkt an dem Element definiert ist. * Dann folgt `A`, da es "spezifischer" als alle anderen ist. spezifischer = mehr Zuweisungen: 1 Tagname `p` + Klassenname `klasse1` + 1 Attribut `attr='value'` * `C` kommt als nächstes, obwohl es genau so ist wie `B`, es erscheint aber später im Stylesheet. * dann kommt `B` * und als letztes `D`. ## Kompatibilität Die meisten Features von CSS sind in allen Browsern verfügbar. Man sollte jedoch immer darauf achten die benutzten Features auf Verfügbarkeit in den vom Projekt unterstützten Browser zu überprüfen. [QuirksMode CSS](http://www.quirksmode.org/css/) oder [Can I Use](http://caniuse.com/) sind zwei der besten Quellen dafür. ## Weiterlesen * [Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade](http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/) * [QuirksMode CSS](http://www.quirksmode.org/css/) * [Z-Index - The stacking context](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context) ================================================ FILE: de/d.md ================================================ --- contributors: - ["Nick Papanastasiou", "www.nickpapanastasiou.github.io"] translators: - ["Dominik Süß", "www.thesuess.me"] --- ```d // Es war klar, dass das kommt... module hello; import std.stdio; // Argumente sind optional void main(string[] args) { writeln("Hello, World!"); } ``` Wenn du so wie ich bist und viel Zeit im Internet verbringst, stehen die Chancen gut, dass du schonmal über [D](http://dlang.org/) gehört hast. Die D-Sprache ist eine moderne, überall einsetzbare Programmiersprache die von Low bis High Level verwendet werden kann und dabei viele Stile anbietet. D wird aktiv von Walter Bright und Andrei Alexandrescu entwickelt, zwei super schlaue, richtig coole Leute. Da das jetzt alles aus dem Weg ist - auf zu den Beispielen! ```d import std.stdio; void main() { // Logische Ausdrücke und Schleifen funktionieren wie erwartet for(int i = 0; i < 10000; i++) { writeln(i); } auto n = 1; // auto um den Typ vom Compiler bestimmen zu lassen // Zahlenliterale können _ verwenden für Lesbarkeit while(n < 10_000) { n += n; } do { n -= (n / 2); } while(n > 0); // For und while sind ja schön und gut aber D bevorzugt foreach // Die '..' erstellen eine Spanne von Zahlen, inklusive dem ersten Wert // jedoch ohne dem letzten foreach(i; 1..1_000_000) { if(n % 2 == 0) writeln(i); } // Es gibt auch ein 'foreach_reverse' wenn du rückwerts gehen willst. foreach_reverse(i; 1..int.max) { if(n % 2 == 1) { writeln(i); } else { writeln("No!"); } } } ``` Neue Typen können mit `struct`, `class`, `union`, und `enum` definiert werden. Structs und unions werden as-value (kopiert) an Methoden übergeben wogegen Klassen als Referenz übergeben werden. Templates können verwendet werden um alle Typen zu parametrisieren. ```d // Hier, T ist ein Type-Parameter, Er funktioniert wie Generics in C#/Java/C++ struct LinkedList(T) { T data = null; LinkedList!(T)* next; // Das ! wird verwendet, um T zu übergeben. ( in C#/Java/C++) } class BinTree(T) { T data = null; // Wenn es nur einen T Parameter gibt, können die Klammern um ihn weggelassen werden BinTree!T left; BinTree!T right; } enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, } // Aliase können verwendet werden, um die Entwicklung zu erleichtern alias IntList = LinkedList!int; alias NumTree = BinTree!double; // Funktionen können genau so Templates beinhalten T max(T)(T a, T b) { if(a < b) return b; return a; } // Steht ref vor einem Parameter, wird sichergestellt, dass er als Referenz übergeben wird. Selbst bei Werten wird es immer eine Referenz sein. void swap(T)(ref T a, ref T b) { auto temp = a; a = b; b = temp; } // Templates können ebenso Werte parametrisieren. class Matrix(uint m, uint n, T = int) { T[m] rows; T[n] columns; } auto mat = new Matrix!(3, 3); // Standardmäßig ist T vom Typ Integer ``` Wo wir schon bei Klassen sind - Wie wäre es mit Properties! Eine Property ist eine Funktion, die wie ein Wert agiert. Das gibt uns viel klarere Syntax im Stil von `structure.x = 7` was gleichgültig wäre zu `structure.setX(7)` ```d // Diese Klasse ist parametrisiert mit T, U class MyClass(T, U) { T _data; U _other; } // Ihre Getter und Setter Methoden sehen so aus class MyClass(T, U) { T _data; U _other; // Konstruktoren heißen immer `this` this(T t, U u) { data = t; other = u; } // getters @property T data() { return _data; } @property U other() { return _other; } // setters // @property kann genauso gut am ende der Methodensignatur stehen void data(T t) @property { _data = t; } void other(U u) @property { _other = u; } } // Und so kann man sie dann verwenden void main() { auto mc = MyClass!(int, string); mc.data = 7; mc.other = "seven"; writeln(mc.data); writeln(mc.other); } ``` Mit properties können wir sehr viel Logik hinter unseren gettern und settern hinter einer schönen Syntax verstecken Andere Objektorientierte features sind beispielsweise `interface`s, `abstract class` und `override`. Vererbung funktioniert in D wie in Java: Erben von einer Klasse, so viele Interfaces wie man will. Jetzt haben wir Objektorientierung in D gesehen, aber schauen wir uns noch was anderes an. D bietet funktionale Programmierung mit _first-class functions_ puren Funktionen und unveränderbaren Daten. Zusätzlich können viele funktionale Algorithmen wie z.B map, filter, reduce und friends im `std.algorithm` Modul gefunden werden! ```d import std.algorithm : map, filter, reduce; import std.range : iota; // builds an end-exclusive range void main() { // Wir wollen die Summe aller Quadratzahlen zwischen // 1 und 100 ausgeben. Nichts leichter als das! // Einfach eine Lambda-Funktion als Template Parameter übergeben // Es ist genau so gut möglich eine normale Funktion hier zu übergeben // Lambdas bieten sich hier aber an. auto num = iota(1, 101).filter!(x => x % 2 == 0) .map!(y => y ^^ 2) .reduce!((a, b) => a + b); writeln(num); } ``` Ist dir aufgefallen, wie wir eine Haskell-Style Pipeline gebaut haben um num zu berechnen? Das war möglich durch die Uniform Function Call Syntax. Mit UFCS können wir auswählen, ob wir eine Funktion als Methode oder als freie Funktion aufrufen. Walters Artikel dazu findet ihr [hier.](http://www.drdobbs.com/cpp/uniform-function-call-syntax/232700394) Kurzgesagt kann man Funktionen, deren erster Parameter vom typ A ist, als Methode auf A anwenden. Parallel Computing ist eine tolle Sache, findest du nicht auch? ```d import std.stdio; import std.parallelism : parallel; import std.math : sqrt; void main() { // Wir wollen die Wurzel von jeder Zahl in unserem Array berechnen // und dabei alle Kerne verwenden, die wir zur Verfügung haben auto arr = new double[1_000_000]; // Wir verwenden den Index und das Element als Referenz // und rufen einfach parallel auf! foreach(i, ref elem; parallel(arr)) { ref = sqrt(i + 1.0); } } ``` ================================================ FILE: de/dhall.md ================================================ --- contributors: - ["Gabriel Gonzalez", "http://www.haskellforall.com/"] translators: - ["Profpatsch", "http://profpatsch.de"] --- Dhall ist eine programmierbare Konfigurationssprache und bietet eine nicht-repetetive Alternative zu YAML. Man kann Dhall sehen als: JSON + Funktionen + Typen + Importsystem Obwohl Dhall programmierbar ist, ist die Sprache nicht turingvollständig. Viele von Dhalls Features benutzen diese Einschränkung, um stärkere Sicherheitsgarantien zu bieten und besseres Tooling zu ermöglichen. ```haskell -- einzeiliger Kommentar {- mehrzeiliger Kommentar Unicode funktioniert 🙂 Diese Datei ist eine valide Dhall-Expression und evaluiert zu einem großen Record, welcher die Ergebnisse jedes Schritts beinhaltet. Das Ergebnis kann angezeigt werden, indem man die Datei evaluiert: $ dhall --file learndhall.dhall {- Kommentare können verschachtelt sein -} -} let greeting = "Hallo, Welt!" let fruits = "🍋🍓🍍🍉🍌" let interpolation = "Ein paar leckere Früchte: ${fruits}" let multilineText {- Inline-Kommentare funktionieren ebenfalls -} = '' In Multiline-Text-Literals wird Whitespace am Anfang der Zeile entfernt. Das bedeutet Text kann frei eingerückt oder ausgerückt werden, ohne dass sich der Inhalt des Strings ändert. Relative Einrückungen bleiben erhalten. Ansonsten wird das Text-Literal verbatim erhalten, ähnlich zu “literal”-Multiline-Strings in YAML. '' let bool = True -- Typannotationen für Bindings sind optional, aber hilfreich, also -- benutzen wir sie hier. let annotation : Bool = True let renderedBool : Text = if bool then "True" else "False" -- Natürliche Zahlen sind nicht-negativ und vorzeichenlos. let naturalNumber : Natural = 42 -- Integer können negativ sein, brauchen aber ein explizites Vorzeichen. let positiveInteger : Integer = +1 let negativeInteger : Integer = -12 let pi : Double = 3.14159265359 {- Identifier dürfen eine große Anzahl an verschiedenen Zeichen beinhalten (wie z.B. Anführungszeichen oder Whitespace), wenn man sie mit Backticks umschließt. -} let `Avogadro's Number` : Double = 6.0221409e+23 let origin : { x : Double, y : Double } = { x = 0.0, y = 0.0 } let somePrimes : List Natural = [ 2, 3, 5, 7, 11 ] {- Ein Schema ist das gleiche wie ein Typ. Typnamen beginnen konventionell mit einem Großbuchstaben, was jedoch nicht erzwungen wird. -} let Profile : Type = { person : { name : Text , age : Natural } , address : { country : Text , state : Text , city : Text } } let bernd : Profile = { person = { name = "Bernd Lauert" , age = 67 } , address = { country = "Deutschland" , state = "Bayern" , city = "Augsburg" } } let augsburg : Text = bernd.address.city {- Enum-Alternativen beginnen konventionell auch mit einem Großbuchstaben. Das wird ebenfalls nicht erzwungen. -} let DNA : Type = < Adenine | Cytosine | Guanine | Thymine > let dnaSequence : List DNA = [ DNA.Thymine, DNA.Guanine, DNA.Guanine ] let compactDNASequence : List DNA = let a = DNA.Adenine let c = DNA.Cytosine let g = DNA.Guanine let t = DNA.Thymine in [ c, t, t, a, t, c, g, g, c ] -- Enums werden transformiert, indem man einen Record mit einem Feld -- pro Alternative angibt. let theLetterG : Text = merge { Adenine = "A" , Cytosine = "C" , Guanine = "G" , Thymine = "T" } DNA.Guanine let presentOptionalValue : Optional Natural = Some 1 let absentOptionalValue : Optional Natural = None Natural let points : List { x : Double, y : Double } = [ { x = 1.1, y = -4.2 } , { x = 4.4, y = -3.0 } , { x = 8.2, y = -5.5 } ] {- `Natural -> List Natural` ist der Funktionstyp mit Eingabetyp `Natural` und Ausgabetyp `List Natural`. Alle Funktionen in Dhall sind Anonyme Funktionen (aka. „Lambdas“), denen man optional einen Namen geben kann. Die folgende Funktion beispielsweise ist äquivalent zu diesem Python Code: lambda n : [ n, n + 1 ] ... und diesem JavaScript Code: function (n) { return [ n, n + 1 ]; } -} let exampleFunction : Natural -> List Natural = \(n : Natural) -> [ n, n + 1 ] -- Dhall unterstützt auch Unicode-Syntax, aber dieses Tutorial nutzt -- die ASCII-Syntax. let unicodeFunction : Natural → List Natural = λ(n : Natural) → [ n, n + 1 ] -- Funktionsargumente brauchen keine Klammern. let exampleFunctionApplication : List Natural = exampleFunction 2 let functionOfMultipleArguments : Natural -> Natural -> List Natural = \(x : Natural) -> \(y : Natural) -> [ x, y ] let functionAppliedToMultipleArguments : List Natural = functionOfMultipleArguments 2 3 {- Wie `exampleFunction`, aber wir geben dem Eingabetypen einen Namen, `n`. -} let namedArgumentType : forall (n : Natural) -> List Natural = \(n : Natural) -> [ n, n + 1 ] {- Bekommt der Eingabetyp einen Namen, kann man ihn weiter hinten in der gleichen Typdefinition wiederverwenden. Das ermöglicht Funktionen, die mit mehr als einem Eingabetypen arbeiten können (aka. „polymorphe“ Funktionen). -} let duplicate : forall (a : Type) -> a -> List a = \(a : Type) -> \(x : a) -> [ x, x ] let duplicatedNumber : List Natural = duplicate Natural 2 let duplicatedBool : List Bool = duplicate Bool False {- Die Sprache hat auch eine handvoll eingebauter polymorpher Funktionen, wie zum Beispiel: List/head : forall (a : Type) -> List a -> Optional a -} let firstPrime : Optional Natural = List/head Natural somePrimes let functionOfARecord : { x : Natural, y : Natural } -> List Natural = \(args : { x : Natural, y : Natural }) -> [ args.x, args.y ] let functionAppliedToARecord : List Natural = functionOfARecord { x = 2, y = 5 } {- Alle Typkonversionen sind explizit. `Natural/show` ist eine eingebaute Funktion mit dem Typ: Natural/show : Natural -> Text ... welche `Natural`s in ihre `Text`-Repräsentation konvertiert. -} let typeConversion : Natural -> Text = \(age : Natural) -> "Ich bin ${Natural/show age} Jahre alt!" -- Ein „Template“ ist einfach eine Funktion mit Ausgabetyp `Text`. let mitLicense : { year : Natural, copyrightHolder : Text } -> Text = \(args : { year : Natural, copyrightHolder : Text }) -> '' Copyright ${Natural/show args.year} ${args.copyrightHolder} Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. '' -- Template-Instanziierung ist das gleiche wie Funktionsanwendung. let templatedLicense : Text = mitLicense { year = 2019, copyrightHolder = "Jane Smith" } {- Expressions können via URL importiert werden. Ähnlich wie in Bash kann man Code aus dem lokalen Dateisystem importieren (wird nicht gezeigt). Sicherheitsbewusste Nutzer können via URLs importierte Expressions mit einem semantischen Integritätscheck versehen („pinnen“). Für gepinnte Imports wird der Dhall-Interpreter jeden Versuch vereiteln, auf der Remote-Seite die Expression zu manipulieren. Jedoch werden Änderungen, die den Inhalt der importierten Expression nicht verändern trotzdem akzeptiert. Auf diese Weise gepinnte Expressions werden auch in einem Content-Adressable Store lokal gecached (standardmäßig in `~/.cache/dhall`). -} let Natural/sum : List Natural -> Natural = https://prelude.dhall-lang.org/Natural/sum sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037 let twentyEight : Natural = Natural/sum somePrimes -- Ein „Paket“ ist einfach ein (möglicherweise verschachtelter) -- Record, den man importiert. let Prelude = https://prelude.dhall-lang.org/package.dhall let false : Bool = Prelude.Bool.not True -- Durch das Anhängen von `as Text` wird eine Datei verbatim -- importiert und nicht als Dhall-Code interpretiert. let sourceCode : Text = https://prelude.dhall-lang.org/Bool/not as Text -- Environment-Variablen können auch importiert werden. let presentWorkingDirectory = env:PWD as Text -- Mit `?` kann man eine “Fallback-Expression” angeben, für den Fall -- dass ein Import fehlschlägt. let home : Optional Text = Some env:HOME ? None Text -- Fallback-Expressions können auch alternative Imports enthalten. let possiblyCustomPrelude = env:DHALL_PRELUDE ? https://prelude.dhall-lang.org/package.dhall {- Ein ausführliches Beispiel, welches mithilfe der `generate`-Funktion eine Konfiguration für 10 Build-User generiert: Prelude.List.generate : Natural -> forall (a : Type) -> (Natural -> a) -> List a -} let buildUsers = let makeUser = \(user : Text) -> let home = "/home/${user}" let privateKey = "${home}/.ssh/id_ed25519" let publicKey = "${privateKey}.pub" in { home = home , privateKey = privateKey , publicKey = publicKey } let buildUser = \(index : Natural) -> makeUser "build${Natural/show index}" let Config = { home : Text , privateKey : Text , publicKey : Text } in Prelude.List.generate 10 Config buildUser -- Alle Ergebnisse in einem großen Record in { greeting = greeting , fruits = fruits , interpolation = interpolation , multilineText = multilineText , bool = bool , annotation = annotation , renderedBool = renderedBool , naturalNumber = naturalNumber , positiveInteger = positiveInteger , negativeInteger = negativeInteger , pi = pi , `Avogadro's Number` = `Avogadro's Number` , origin = origin , somePrimes = somePrimes , bernd = bernd , augsburg = augsburg , dnaSequence = dnaSequence , compactDNASequence = compactDNASequence , theLetterG = theLetterG , presentOptionalValue = presentOptionalValue , absentOptionalValue = absentOptionalValue , points = points , exampleFunction = exampleFunction , unicodeFunction = unicodeFunction , exampleFunctionApplication = exampleFunctionApplication , functionOfMultipleArguments = functionOfMultipleArguments , functionAppliedToMultipleArguments = functionAppliedToMultipleArguments , namedArgumentType = namedArgumentType , duplicate = duplicate , duplicatedNumber = duplicatedNumber , duplicatedBool = duplicatedBool , firstPrime = firstPrime , functionOfARecord = functionOfARecord , functionAppliedToARecord = functionAppliedToARecord , typeConversion = typeConversion , mitLicense = mitLicense , templatedLicense = templatedLicense , twentyEight = twentyEight , false = false , sourceCode = sourceCode , presentWorkingDirectory = presentWorkingDirectory , home = home , buildUsers = buildUsers } ``` Mehr Infos und Lernmaterialien gibt es auf der offiziellen Website (Englisch), auf der man Dhall auf im Browser ausprobieren kann: * [https://dhall-lang.org](http://dhall-lang.org/) ================================================ FILE: de/dynamic-programming.md ================================================ --- contributors: - ["Akashdeep Goel", "http://github.com/akashdeepgoel"] translators: - ["Henrik Jürges", "http://github.com/santifa"] --- # Dynamische Programmierung ## Einführung Dynamische Programmierung ist eine leistungsfähige Technik, die zur Lösung einer bestimmten Klasse von Problemen verwendet wird. Die Idee ist sehr einfach, wenn Sie ein Problem mit der gegebenen Eingabe gelöst haben, dann speichern Sie das Ergebnis für die spätere Referenz, um zu vermeiden, das gleiche Problem noch einmal zu lösen. Denken Sie immer daran! "Diejenigen, die sich nicht an die Vergangenheit erinnern können, sind dazu verdammt, sie zu wiederholen." ## Wege zur Lösung solcher Probleme 1. *Top-Down*: Lösen Sie das gegebene Problem, indem Sie es aufteilen. Wenn Sie sehen, dass das Problem bereits gelöst ist, geben Sie einfach die gespeicherte Antwort zurück. Wenn es nicht gelöst wurde, lösen Sie es und speichern Sie die Antwort. Dieser Ansatz ist leicht zu verfolgen und sehr intuitiv. Er wird als Memoization bezeichnet. 2. *Bottom-Up*: Analysieren Sie das Problem und beobachten Sie, in welcher Reihenfolge die Teilprobleme gelöst werden können. Beginnen Sie mit der Lösung vom trivialen Teilproblem bis zum gegebenen Problem. Dabei wird sichergestellt, dass die Teilprobleme vor der Problemlösung gelöst werden. Dies wird als Dynamische Programmierung bezeichnet. ## Ein Beispiel für Dynamische Programmierung Das Problem mit der längsten ansteigenden Subsequenz besteht darin, die längste ansteigende Subsequenz einer gegebenen Sequenz zu finden. Gegeben die Sequenz `S= {a1, a2, a3, a3, a4,..............., an-1, an }`, müssen wir die größte Teilmenge finden, sodass für alle `j` und `i`, `j a[j] and LS[i] {:eggs 2 :butter 1 :flour 5} ; Definiere die Leserfunktion, um markierte Elemente zu transformieren ; und übergebe eine Map, die Tags den Lesefunktionen als edn / read-string zuweisen (edn/read-string {:readers {'MyYelpClone/MenuItem map->menu-item}} "#MyYelpClone/MenuItem {:name \"eggs-benedict\" :rating 10}") ; -> #user.MenuItem{:name "eggs-benedict", :rating 10} ``` # Referenzen - [EDN spec](https://github.com/edn-format/edn) - [Implementationen](https://github.com/edn-format/edn/wiki/Implementations) - [markierte Elemente](http://www.compoundtheory.com/clojure-edn-walkthrough/) ================================================ FILE: de/elixir.md ================================================ --- contributors: - ["Joao Marques", "http://github.com/mrshankly"] translators: - ["Gregor Große-Bölting", "http://www.ideen-und-soehne.de"] --- Elixir ist eine moderne, funktionale Sprache für die Erlang VM. Sie ist voll kompatibel mit Erlang, verfügt aber über eine freundlichere Syntax und bringt viele Features mit. ```ruby # Einzeilige Kommentare werden mit der Raute gesetzt. # Es gibt keine mehrzeiligen Kommentare; # es ist aber problemlos möglich mehrere einzeilige Kommentare hintereinander # zu setzen (so wie hier). # Mit 'iex' ruft man die Elixir-Shell auf. # Zum kompilieren von Modulen dient der Befehl 'elixirc'. # Beide Befehle sollten als Umgebungsvariable gesetzt sein, wenn Elixir korrekt # installiert wurde. ## --------------------------- ## -- Basistypen ## --------------------------- # Es gibt Nummern: 3 # Integer 0x1F # Integer 3.0 # Float # Für bessere Lesbarkeit des Codes können Unterstriche "_" als Trennzeichen verwendet werden 1_000_000 == 1000000 # Integer 1_000.567 == 1000.567 # Float # Atome, das sind Literale, sind Konstanten mit Namen. Sie starten mit einem # ':'. :hello # Atom # Außerdem gibt es Tupel, deren Werte im Arbeitsspeicher vorgehalten werden. {1,2,3} # Tupel # Die Werte innerhalb eines Tupels können mit der 'elem'-Funktion ausgelesen # werden: elem({1, 2, 3}, 0) # => 1 # Listen sind als verkettete Listen implementiert. [1, 2, 3] # list # Auf Kopf und Rest einer Liste kann wie folgt zugegriffen werden: [ kopf | rest ] = [1,2,3] kopf # => 1 rest # => [2, 3] # In Elixir, wie auch in Erlang, kennzeichnet '=' ein 'pattern matching' # (Musterabgleich) und keine Zuweisung. # Das heißt, dass die linke Seite auf die rechte Seite 'abgeglichen' wird. # Auf diese Weise kann im Beispiel oben auf Kopf und Rest der Liste zugegriffen # werden. # Ein Musterabgleich wird einen Fehler werfen, wenn die beiden Seiten nicht # zusammenpassen. # Im folgenden Beispiel haben die Tupel eine unterschiedliche Anzahl an # Elementen: {a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2} # Es gibt außerdem 'binaries', <<1,2,3>> # binary. # Strings und 'char lists' "hello" # String 'hello' # Char-Liste # ... und mehrzeilige Strings """ Ich bin ein mehrzeiliger String. """ #=> "Ich bin ein\nmehrzeiliger String.\n" # Alles Strings werden in UTF-8 enkodiert: "héllò" #=> "héllò" # Eigentlich sind Strings in Wahrheit nur binaries und 'char lists' einfach # Listen. <> #=> "abc" [?a, ?b, ?c] #=> 'abc' # In Elixir gibt `?a` den ASCII-Integer für den Buchstaben zurück. ?a #=> 97 # Um Listen zu verbinden gibt es den Operator '++', für binaries nutzt man '<>' [1,2,3] ++ [4,5] #=> [1,2,3,4,5] 'hello ' ++ 'world' #=> 'hello world' <<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>> "hello " <> "world" #=> "hello world" ## --------------------------- ## -- Operatoren ## --------------------------- # Einfache Arithmetik 1 + 1 #=> 2 10 - 5 #=> 5 5 * 2 #=> 10 10 / 2 #=> 5.0 # In Elixir gibt der Operator '/' immer einen Float-Wert zurück. # Für Division mit ganzzahligen Ergebnis gibt es 'div' div(10, 2) #=> 5 # Um den Rest der ganzzahligen Division zu erhalten gibt es 'rem' rem(10, 3) #=> 1 # Natürlich gibt es auch Operatoren für Booleans: 'or', 'and' und 'not'. Diese # Operatoren erwarten einen Boolean als erstes Argument. true and true #=> true false or true #=> true # 1 and true #=> ** (ArgumentError) argument error # Elixir bietet auch '||', '&&' und '!', die Argumente jedweden Typs # akzeptieren. Alle Werte außer 'false' und 'nil' werden zu wahr evaluiert. 1 || true #=> 1 false && 1 #=> false nil && 20 #=> nil !true #=> false # Für Vergleiche gibt es die Operatoren `==`, `!=`, `===`, `!==`, `<=`, `>=`, # `<` und `>` 1 == 1 #=> true 1 != 1 #=> false 1 < 2 #=> true # '===' und '!==' sind strikter beim Vergleich von Integern und Floats: 1 == 1.0 #=> true 1 === 1.0 #=> false # Es ist außerdem möglich zwei verschiedene Datentypen zu vergleichen: 1 < :hello #=> true # Die gesamte Ordnung über die Datentypen ist wie folgt definiert: # number < atom < reference < functions < port < pid < tuple < list < bitstring # Um Joe Armstrong zu zitieren: "The actual order is not important, but that a # total ordering is well defined is important." ## --------------------------- ## -- Kontrollstrukturen ## --------------------------- # Es gibt die `if`-Verzweigung if false do "Dies wird nie jemand sehen..." else "...aber dies!" end # Du erinnerst dich an 'pattern matching'? Viele Kontrollstrukturen in Elixir # arbeiten damit. # 'case' erlaubt es uns Werte mit vielerlei Mustern zu vergleichen. case {:one, :two} do {:four, :five} -> "Das wird nicht passen" {:one, x} -> "Das schon und außerdem wird es ':two' dem Wert 'x' zuweisen." _ -> "Dieser Fall greift immer." end # Es ist eine übliche Praxis '_' einen Wert zuzuweisen, sofern dieser Wert # nicht weiter verwendet wird. # Wenn wir uns zum Beispiel nur für den Kopf einer Liste interessieren: [kopf | _] = [1,2,3] kopf #=> 1 # Für bessere Lesbarkeit können wir auch das Folgende machen: [kopf | _rest] = [:a, :b, :c] kopf #=> :a # Mit 'cond' können diverse Bedingungen zur selben Zeit überprüft werden. Man # benutzt 'cond' statt viele if-Verzweigungen zu verschachteln. cond do 1 + 1 == 3 -> "Ich werde nie aufgerufen." 2 * 5 == 12 -> "Ich auch nicht." 1 + 2 == 3 -> "Aber ich!" end # Es ist üblich eine letzte Bedingung einzufügen, die immer zu wahr evaluiert. cond do 1 + 1 == 3 -> "Ich werde nie aufgerufen." 2 * 5 == 12 -> "Ich auch nicht." true -> "Aber ich! (dies ist im Grunde ein 'else')" end # 'try/catch' wird verwendet um Werte zu fangen, die zuvor 'geworfen' wurden. # Das Konstrukt unterstützt außerdem eine 'after'-Klausel die aufgerufen wird, # egal ob zuvor ein Wert gefangen wurde. try do throw(:hello) catch nachricht -> "#{nachricht} gefangen." after IO.puts("Ich bin die 'after'-Klausel.") end #=> Ich bin die 'after'-Klausel. # ":hello gefangen" ## --------------------------- ## -- Module und Funktionen ## --------------------------- # Anonyme Funktionen (man beachte den Punkt) square = fn(x) -> x * x end square.(5) #=> 25 # Anonyme Funktionen unterstützen auch 'pattern' und 'guards'. Guards erlauben # es die Mustererkennung zu justieren und werden mit dem Schlüsselwort 'when' # eingeführt: f = fn x, y when x > 0 -> x + y x, y -> x * y end f.(1, 3) #=> 4 f.(-1, 3) #=> -3 # Elixir bietet zahlreiche eingebaute Funktionen. Diese sind im gleichen # Geltungsbereich ('scope') verfügbar. is_number(10) #=> true is_list("hello") #=> false elem({1,2,3}, 0) #=> 1 # Mehrere Funktionen können in einem Modul gruppiert werden. Innerhalb eines # Moduls ist es möglich mit dem Schlüsselwort 'def' eine Funktion zu # definieren. defmodule Math do def sum(a, b) do a + b end def square(x) do x * x end end Math.sum(1, 2) #=> 3 Math.square(3) #=> 9 # Um unser einfaches Mathe-Modul zu kompilieren muss es unter 'math.ex' # gesichert werden. Anschließend kann es mit 'elixirc' im Terminal aufgerufen # werden: elixirc math.ex # Innerhalb eines Moduls definieren wir private Funktionen mit 'defp'. Eine # Funktion, die mit 'def' erstellt wurde, kann von anderen Modulen aufgerufen # werden; eine private Funktion kann nur lokal angesprochen werden. defmodule PrivateMath do def sum(a, b) do do_sum(a, b) end defp do_sum(a, b) do a + b end end PrivateMath.sum(1, 2) #=> 3 # PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError) # Auch Funktionsdeklarationen unterstützen 'guards' und Mustererkennung: defmodule Geometry do def area({:rectangle, w, h}) do w * h end def area({:circle, r}) when is_number(r) do 3.14 * r * r end end Geometry.area({:rectangle, 2, 3}) #=> 6 Geometry.area({:circle, 3}) #=> 28.25999999999999801048 # Geometry.area({:circle, "not_a_number"}) #=> ** (FunctionClauseError) no function clause matching in Geometry.area/1 # Wegen der Unveränderlichkeit von Variablen ist Rekursion ein wichtiger # Bestandteil von Elixir. defmodule Recursion do def sum_list([head | tail], acc) do sum_list(tail, acc + head) end def sum_list([], acc) do acc end end Recursion.sum_list([1,2,3], 0) #=> 6 # Elixir-Module unterstützen Attribute. Es gibt eingebaute Attribute, ebenso # ist es möglich eigene Attribute hinzuzufügen. defmodule MyMod do @moduledoc """ Dies ist ein eingebautes Attribut in einem Beispiel-Modul """ @my_data 100 # Dies ist ein selbst-definiertes Attribut. IO.inspect(@my_data) #=> 100 end ## --------------------------- ## -- 'Records' und Ausnahmebehandlung ## --------------------------- # 'Records' sind im Grunde Strukturen, die es erlauben einem Wert einen eigenen # Namen zuzuweisen. defrecord Person, name: nil, age: 0, height: 0 joe_info = Person.new(name: "Joe", age: 30, height: 180) #=> Person[name: "Joe", age: 30, height: 180] # Zugriff auf den Wert von 'name' joe_info.name #=> "Joe" # Den Wert von 'age' überschreiben joe_info = joe_info.age(31) #=> Person[name: "Joe", age: 31, height: 180] # Der 'try'-Block wird zusammen mit dem 'rescue'-Schlüsselwort dazu verwendet, # um Ausnahmen beziehungsweise Fehler zu behandeln. try do raise "Irgendein Fehler." rescue RuntimeError -> "Laufzeit-Fehler gefangen." _error -> "Und dies fängt jeden Fehler." end # Alle Ausnahmen haben das Attribut 'message' try do raise "ein Fehler" rescue x in [RuntimeError] -> x.message end ## --------------------------- ## -- Nebenläufigkeit ## --------------------------- # Elixir beruht auf dem Aktoren-Model zur Behandlung der Nebenläufigkeit. Alles # was man braucht um in Elixir nebenläufige Programme zu schreiben sind drei # Primitive: Prozesse erzeugen, Nachrichten senden und Nachrichten empfangen. # Um einen neuen Prozess zu erzeugen nutzen wir die 'spawn'-Funktion, die # wiederum eine Funktion als Argument entgegen nimmt. f = fn -> 2 * 2 end #=> #Function spawn(f) #=> #PID<0.40.0> # 'spawn' gibt eine pid (einen Identifikator des Prozesses) zurück. Diese kann # nun verwendet werden, um Nachrichten an den Prozess zu senden. Um # zu senden nutzen wir den '<-' Operator. Damit das alles Sinn macht müssen wir # in der Lage sein Nachrichten zu empfangen. Dies wird mit dem # 'receive'-Mechanismus sichergestellt: defmodule Geometry do def area_loop do receive do {:rectangle, w, h} -> IO.puts("Area = #{w * h}") area_loop() {:circle, r} -> IO.puts("Area = #{3.14 * r * r}") area_loop() end end end # Kompiliere das Modul, starte einen Prozess und gib die 'area_loop' Funktion # in der Shell mit, etwa so: pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0> # Sende eine Nachricht an die 'pid', die ein Muster im 'receive'-Ausdruck # erfüllt: pid <- {:rectangle, 2, 3} #=> Area = 6 # {:rectangle,2,3} pid <- {:circle, 2} #=> Area = 12.56000000000000049738 # {:circle,2} # Die Shell selbst ist ein Prozess und mit dem Schlüsselwort 'self' kann man # die aktuelle pid herausfinden. self() #=> #PID<0.27.0> ``` ## Referenzen und weitere Lektüre * [Getting started guide](http://elixir-lang.org/getting_started/1.html) auf der [elixir Website](http://elixir-lang.org) * [Elixir Documentation](http://elixir-lang.org/docs/master/) * ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) von Fred Hebert * "Programming Erlang: Software for a Concurrent World" von Joe Armstrong ================================================ FILE: de/elm.md ================================================ --- contributors: - ["Max Goldstein", "http://maxgoldste.in/"] translators: - ["waynee95", "https://waynee95.me"] --- Elm ist eine pure funktionale Programmiersprache. Mit Elm werden GUIs (grafische Benutzeroberfläche) für Webanwendungen erstellt. Durch die statische Typisierung kann Elm viele Fehler schon bei der Kompilierung abfangen. Ein Hauptmerkmal von Elm sind die ausführlichen und gut erklärten Fehlermeldungen. ```haskell -- Einzeilige Kommentare beginnen mit 2 Bindestrichen. {- So wird ein mehrzeiliger Kommentar angelegt. {- Diese können auch verschachtelt werden. -} -} {-- Die Grundlagen --} -- Arithmetik 1 + 1 -- 2 8 - 1 -- 7 10 * 2 -- 20 -- Zahlen ohne Punkt sind entweder vom Typ Int oder Float. 33 / 2 -- 16.5 mit Division von Gleitkommazahlen 33 // 2 -- 16 mit ganzzahliger Division -- Exponenten 5 ^ 2 -- 25 -- Boolesche Werte not True -- False not False -- True 1 == 1 -- True 1 /= 1 -- False 1 < 10 -- True -- Strings (Zeichenketten) und Zeichen "Das hier ist ein String." 'a' -- Zeichen -- Strings können konkateniert werden. "Hello " ++ "world!" -- "Hello world!" {-- Listen und Tupel --} -- Jedes Element einer Liste muss vom gleichen Typ sein. Listen sind homogen. ["the", "quick", "brown", "fox"] [1, 2, 3, 4, 5] -- Das zweite Beispiel kann man auch mit Hilfe der "range" Funktion schreiben. List.range 1 5 -- Listen werden genauso wie Strings konkateniert. List.range 1 5 ++ List.range 6 10 == List.range 1 10 -- True -- Mit dem "cons" Operator lässt sich ein Element an den Anfang einer Liste anfügen. 0 :: List.range 1 5 -- [0, 1, 2, 3, 4, 5] -- Die Funktionen "head" und "tail" haben als Rückgabewert den "Maybe" Typ. -- Dadurch wird die Fehlerbehandlung von fehlenden Elementen explizit, weil -- man immer mit jedem möglichen Fall umgehen muss. List.head (List.range 1 5) -- Just 1 List.tail (List.range 1 5) -- Just [2, 3, 4, 5] List.head [] -- Nothing -- List.funktionsName bedeutet, dass diese Funktion aus dem "List"-Modul stammt. -- Tupel sind heterogen, jedes Element kann von einem anderen Typ sein. -- Jedoch haben Tupel eine feste Länge. ("elm", 42) -- Das Zugreifen auf Elemente eines Tupels geschieht mittels den Funktionen -- "first" und "second". Tuple.first ("elm", 42) -- "elm" Tuple.second ("elm", 42) -- 42 -- Das leere Tupel, genannt "Unit", wird manchmal als Platzhalter verwendet. -- Es ist das einzige Element vom Typ "Unit". () {-- Kontrollfluss --} -- Eine If-Bedingung hat immer einen Else-Zweig und beide Zweige müssen den -- gleichen Typ haben. if powerLevel > 9000 then "WHOA!" else "meh" -- If-Bedingungen können verkettet werden. if n < 0 then "n is negative" else if n > 0 then "n is positive" else "n is zero" -- Mit dem Mustervergleich (pattern matching) kann man bestimmte Fälle direkt -- behandeln. case aList of [] -> "matches the empty list" [x]-> "matches a list of exactly one item, " ++ toString x x::xs -> "matches a list of at least one item whose head is " ++ toString x -- Mustervergleich geht immer von oben nach unten. Würde man [x] als letztes -- platzieren, dann würde dieser Fall niemals getroffen werden, weil x:xs diesen -- Fall schon mit einschließt (xs ist in dem Fall die leere Liste). -- Mustervergleich an einem Maybe Typ. case List.head aList of Just x -> "The head is " ++ toString x Nothing -> "The list was empty." {-- Funktionen --} -- Die Syntax für Funktionen in Elm ist minimal. Hier werden Leerzeichen anstelle -- von runden oder geschweiften Klammern verwendet. Außerdem gibt es kein "return" -- Keyword. -- Eine Funktion wird durch ihren Namen, einer Liste von Parametern gefolgt von -- einem Gleichheitszeichen und dem Funktionskörper angegeben. multiply a b = a * b -- Beim Aufruf der Funktion (auch Applikation genannt) werden die Argumente ohne -- Komma übergeben. multiply 7 6 -- 42 -- Partielle Applikation einer Funktion (Aufrufen einer Funktion mit fehlenden -- Argumenten). Hierbei entsteht eine neue Funktion, der wir einen Namen geben. double = multiply 2 -- Konstanten sind Funktionen ohne Parameter. answer = 42 -- Funktionen, die Funktionen als Parameter haben, nennt man Funktionen höherer -- Ordnung. In funktionalen Programmiersprachen werden Funktionen als "first-class" -- behandelt. Man kann sie als Argument übergeben, als Rückgabewert einer Funktion -- zurückgeben oder einer Variable zuweisen. List.map double (List.range 1 4) -- [2, 4, 6, 8] -- Funktionen können auch als anonyme Funktion (Lambda-Funktionen) übergeben werden. -- Diese werden mit einem Blackslash eingeleitet, gefolgt von allen Argumenten. -- Die Funktion "\a -> a * 2" beschreibt die Funktion f(x) = x * 2. List.map (\a -> a * 2) (List.range 1 4) -- [2, 4, 6, 8] -- Mustervergleich kann auch in der Funktionsdefinition verwendet werden. -- In diesem Fall hat die Funktion ein Tupel als Parameter. (Beachte: Hier -- werden die Werte des Tupels direkt ausgepackt. Dadurch kann man auf die -- Verwendung von "first" und "second" verzichten.) area (width, height) = width * height area (6, 7) -- 42 -- Mustervergleich auf Records macht man mit geschweiften Klammern. -- Bezeichner (lokale Variablen) werden mittels dem "let" Keyword angelegt. -- (Mehr zu Records weiter unten!) volume {width, height, depth} = let area = width * height in area * depth volume { width = 3, height = 2, depth = 7 } -- 42 -- Rekursive Funktion fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2) List.map fib (List.range 0 8) -- [1, 1, 2, 3, 5, 8, 13, 21, 34] -- Noch eine rekursive Funktion (Nur ein Beispiel, verwende stattdessen immer -- List.length!) listLength aList = case aList of [] -> 0 x::xs -> 1 + listLength xs -- Funktionsapplikation hat die höchste Präzedenz, sie binden stärker als Operatoren. -- Klammern bietet die Möglichkeit der Bevorrangung. cos (degrees 30) ^ 2 + sin (degrees 30) ^ 2 -- 1 -- Als erstes wird die Funktion "degrees" mit dem Wert 30 aufgerufen. -- Danach wird das Ergebnis davon den Funktionen "cos", bzw. "sin" übergeben. -- Dann wird das Ergebnis davon mit 2 quadriert und als letztes werden diese -- beiden Werte dann addiert. {-- Typen und Typ Annotationen --} -- Durch Typinferenz kann der Compiler jeden Typ genau bestimmen. Man kann diese -- aber auch manuell selber angeben (guter Stil!). -- Typen beginnen immer mit eine Großbuchstaben. Dabei liest man "x : Typ" als -- "x" ist vom Typ "Typ". -- Hier ein paar übliche Typen: 5 : Int 6.7 : Float "hello" : String True : Bool -- Funktionen haben ebenfalls einen Typ. Dabei ist der ganz rechte Typ der -- Rückgabetyp der Funktion und alle anderen sind die Typen der Parameter. not : Bool -> Bool round : Float -> Int -- Es ist guter Stil immer den Typ anzugeben, da diese eine Form von Dokumentation -- sind. Außerdem kann so der Compiler genauere Fehlermeldungen geben. double : Int -> Int double x = x * 2 -- Funktionen als Parameter werden durch Klammern angegeben. Die folgende Funktion -- ist nicht auf einen Typ festgelegt, sondern enthält Typvariablen (beginnend -- mit Kleinbuchstaben). Die konkreten Typen werden erst bei Anwendung der -- Funktion festgelegt. "List a" bedeutet, dass es sich um eine Liste mit -- Elementen vom Typ "a" handelt. List.map : (a -> b) -> List a -> List b -- Es gibt drei spezielle kleingeschriebene Typen: "number", "comparable" und -- "appendable". add : number -> number -> number add x y = x + y -- funktioniert mit Ints und Floats. max :: comparable -> comparable -> comparable max a b = if a > b then a else b -- funktioniert mit Typen, die vergleichbar sind. append :: appendable -> appendable -> appendable append xs ys = xs ++ ys -- funktioniert mit Typen, die konkatenierbar sind. append "hello" "world" -- "helloworld" append [1,1,2] [3,5,8] -- [1,1,2,3,5,8] {-- Eigene Datentypen erstellen --} -- Ein "Record" ist ähnlich wie ein Tupel, nur das jedes Feld einen Namen hat. -- Dabei spielt die Reihenfolge keine Rolle. { x = 3, y = 7 } -- Um auf Werte eines Records zuzugreifen, benutzt man einen Punkt gefolgt -- von dem Namen des Feldes. { x = 3, y = 7 }.x -- 3 -- Oder mit einer Zugriffsfunktion, welche aus einem Punkt und dem Feldnamen besteht. .y { x = 3, y = 7 } -- 7 -- Wert eines Feldes ändern. (Achtung: Das Feld muss aber vorher schon vorhanden sein!) { person | name = "George" } -- Mehrere Felder auf einmal ändern unter Verwendung des alten Wertes. { particle | position = particle.position + particle.velocity, velocity = particle.velocity + particle.acceleration } -- Du kannst ein Record auch als Typ Annotation verwenden. -- (Beachte: Ein Record Typ benutzt einen Doppelpunkt und ein Record Wert benutzt -- ein Gleichheitszeichen!) origin : { x : Float, y : Float, z : Float } origin = { x = 0, y = 0, z = 0 } -- Durch das "type" Keyword kann man einem existierenden Typen einen Namen geben. type alias Point3D = { x : Float, y : Float, z : Float } -- Der Name kann dann als Konstruktor verwendet werden. otherOrigin : Point3D otherOrigin = Point3D 0 0 0 -- Aber es ist immer noch derselbe Typ, da es nur ein Alias ist! origin == otherOrigin -- True -- Neben den Records gibt es auch noch so genannte Summentypen. -- Ein Summentyp hat mehrere Konstruktoren. type Direction = North | South | East | West -- Ein Konstruktor kann außerdem noch andere Typen enthalten. Rekursion ist -- auch möglich. type IntTree = Leaf | Node Int IntTree IntTree -- Diese können auch als Typ Annotation verwendet werden. root : IntTree root = Node 7 Leaf Leaf -- Außerdem können auch Typvariablen verwendet werden in einem Konstruktor. type Tree a = Leaf | Node a (Tree a) (Tree a) -- Beim Mustervergleich kann man auf die verschiedenen Konstruktoren matchen. leftmostElement : Tree a -> Maybe a leftmostElement tree = case tree of Leaf -> Nothing Node x Leaf _ -> Just x Node _ subtree _ -> leftmostElement subtree {-- Module und Imports --} -- Die Kernbibliotheken und andere Bibliotheken sind in Module aufgeteilt. -- Für große Projekte können auch eigene Module erstellt werden. -- Eine Modul beginnt ganz oben. Ohne diese Angabe befindet man sich -- automatisch im Modul "Main". module Name where -- Ohne genaue Angabe von Exports wird alles exportiert. Es können aber alle -- Exporte explizit angegeben werden. module Name (MyType, myValue) where -- Importiert das Modul "Dict". Jetzt kann man Funktionen mittels "Dict.insert" -- aufrufen. import Dict -- Importiert das "Dict" Modul und den "Dict" Typ. Dadurch muss man nicht "Dict.Dict" -- verwenden. Man kann trotzdem noch Funktionen des Moduls aufrufen, wie "Dict.insert". import Dict exposing (Dict) -- Abkürzung für den Modulnamen. Aufrufen der Funktionen mittels "C.funktionsName". import Graphics.Collage as C {-- Kommandozeilen Programme --} -- Eine Elm-Datei kompilieren. $ elm make MyFile.elm -- Beim ersten Aufruf wird Elm die "core" Bibliotheken installieren und eine -- "elm-package.json"-Datei anlegen, die alle Informationen des Projektes -- speichert. -- Der Reactor ist ein Server, welcher alle Dateien kompiliert und ausführt. $ elm reactor -- Starte das REPL (read-eval-print-loop). $ elm repl -- Bibliotheken werden durch den GitHub-Nutzernamen und ein Repository identifiziert. -- Installieren einer neuen Bibliothek. $ elm package install elm-lang/html -- Diese wird der elm-package.json Datei hinzugefügt. -- Zeigt alle Veränderungen zwischen zwei bestimmten Versionen an. $ elm package diff elm-lang/html 1.1.0 2.0.0 -- Der Paketmanager von Elm erzwingt "semantic versioning"! ``` Elm ist eine besonders kleine Programmiersprache. Jetzt hast du genug Wissen an deiner Seite, um dich in fast jedem Elm Code zurecht zu finden. Noch ein paar weitere hilfreiche Ressourcen (in Englisch): - Die [Elm Homepage](http://elm-lang.org/). Dort findest du: - [Anleitung zur Installation von Elm](http://elm-lang.org/install) - [Dokumentation](http://elm-lang.org/docs), sowie eine [Referenz zur Syntax](http://elm-lang.org/docs/syntax) - Viele hilfreiche [Beispiele](http://elm-lang.org/examples) - Dokumentation der [Elm Kernbibliotheken](http://package.elm-lang.org/packages/elm-lang/core/latest/). Insbesondere: - [Basics](http://package.elm-lang.org/packages/elm-lang/core/latest/Basics) (standardmäßig importiert) - [Maybe](http://package.elm-lang.org/packages/elm-lang/core/latest/Maybe) sowie [Result](http://package.elm-lang.org/packages/elm-lang/core/latest/Result) (benutzt für Fehlerbehandlung) - Datenstrukturen, wie [List](http://package.elm-lang.org/packages/elm-lang/core/latest/List), [Array](http://package.elm-lang.org/packages/elm-lang/core/latest/Array), [Dict](http://package.elm-lang.org/packages/elm-lang/core/latest/Dict), und [Set](http://package.elm-lang.org/packages/elm-lang/core/latest/Set) - JSON [encoding](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Encode) und [decoding](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode) - [Die Elm Architektur](https://github.com/evancz/elm-architecture-tutorial#the-elm-architecture). - Die [Elm mailing list](https://groups.google.com/forum/#!forum/elm-discuss). ================================================ FILE: de/git.md ================================================ --- contributors: - ["Jake Prather", "http://github.com/JakeHP"] translators: - ["kultprok", "http://www.kulturproktologie.de"] --- Git ist eine verteilte Versions- und Quellcodeverwaltung. Es nimmt Schnappschüsse der Projekte auf, um mit diesen Schnappschüssen verschiedene Versionen unterscheiden und den Quellcode verwalten zu können. Anmerkung des Übersetzers: Einige englische Begriffe wie *Repository*, *Commit* oder *Head* sind idiomatische Bestandteile im Umgang mit Git. Sie wurden nicht übersetzt. ## Konzepte der Versionsverwaltung ### Was ist Versionsverwaltung? Eine Versionsverwaltung erfasst die Änderungen einer Datei oder eines Verzeichnisses im Verlauf der Zeit. ### Vergleich zwischen Zentraler und verteilter Versionverwaltung * Zentrale Versionsverwaltung konzentriert sich auf das Synchronisieren, Verfolgen und Sichern von Dateien. * Verteilte Versionsverwaltung konzentriert sich auf das Teilen der Änderungen. Jede Änderung hat eine eindeutige ID. * Verteilte Systeme haben keine vorbestimmte Struktur. Ein SVN-ähnliches, zentrales System wäre mit Git ebenso umsetzbar. [Weiterführende Informationen](https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control) ### Warum Git? * Ist offline einsetzbar. * Einfache Kollaboration! * Branching ist einfach! * Branching ist schnell! * Merging ist einfach! * Git ist schnell. * Git ist flexibel. ## Die Architektur von Git ### Repository (Repo) Ein Satz von Dateien, Verzeichnissen, Historieneinträgen, Commits und Heads. Stell es dir wie eine Quellcode-Datenstruktur vor, unter anderem mit der Eigenschaft, dass alle *Elemente* dir Zugriff auf die Revisionshistorie geben. Ein Repository besteht in Git aus dem .git-Verzeichnis und dem Arbeitsverzeichnis. ### .git-Verzeichnis (Teil des Repositorys) Das .git-Verzeichnis enthält alle Einstellungen, Logs, Branches, den HEAD und mehr. [Ausführliche Übersicht](https://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html) ### Arbeitsverzeichnis (Teil des Repositorys) Dies sind die Verzeichnisse und Dateien in deinem Repository, also z.B. dein Programmcode. ### Index (Teil des .git-Verzeichnisses) Der Index ist die Staging-Area von Git. Es ist im Grunde eine Ebene, die Arbeitsverzeichnis vom Repository trennt. Sie gibt Entwicklern mehr Einfluss darüber, was ins Git-Repository eingeht. ### Commit Ein Commit ist ein Schnappschuss von Änderungen in deinem Arbeitsverzeichnis. Wenn du zum Beispiel 5 Dateien hinzugefügt und 2 andere entfernt hast, werden diese Änderungen im Commit (Schnappschuss) enthalten sein. Dieser Commit kann dann in andere Repositories gepusht werden. Oder nicht! ### Branch Ein Branch, ein Ast oder Zweig, ist im Kern ein Pointer auf den letzten Commit, den du gemacht hast. Während des Commits wird der Pointer automatisch auf diesen Stand gebracht und zeigt dann auf den neuen letzten Commit. ### HEAD und head (Teil des .git-Verzeichnisses) HEAD ist ein Pointer auf den aktuellen Branch. Ein Repository hat nur einen *aktiven* HEAD. Ein *head* ist ein Pointer, der auf einen beliebigen Commit zeigt. Ein Repository kann eine beliebige Zahl von *heads* enthalten. ## Befehle ### init Erstelle ein leeres Git-Repository im aktuellen Verzeichnis. Die Einstellungen, gespeicherte Informationen und mehr zu diesem Git-Repository werden in einem Verzeichnis namens *.git* angelegt. ```bash $ git init ``` ### config Hiermit werden Einstellungen vorgenommen. Dies kann das Repository, das System selbst oder globale Einstellungen betreffen. ```bash # Grundlegende Config-Variablen ausgeben und setzen $ git config --global user.email $ git config --global user.name $ git config --global user.email "MyEmail@Zoho.com" $ git config --global user.name "My Name" ``` [Mehr über git config](https://git-scm.com/docs/git-config) ### help Schnellzugriff auf extrem detaillierte Anleitungen zu allen Befehlen. Oder als Erinnerung zu semantischen Eigenheiten. ```bash # Übersicht gängiger Befehle $ git help # Übersicht aller verfügbaren Befehle $ git help -a # Befehlspezifische Hilfe - Bedienungsanleitung # git help $ git help add $ git help commit $ git help init ``` ### status Zeigt die Unterschiede zwischen Index (im Grunde dein Arbeitsverzeichnis/-repository) und dem aktuellen HEAD an. ```bash # Zeigt den Branch, nicht-verfolgte Dateien, Änderungen und andere Unterschiede an $ git status # Anderes Wissenswertes über git status anzeigen $ git help status ``` ### add Hinzufügen von Dateien zum Arbeitsverzeichnis/-repository. Wenn du neue Dateien nicht mit *git add* zum Arbeitsverzeichnis hinzufügst, werden sie nicht in den Commit aufgenommen! ```bash # Fügt eine Datei deinem aktuellen Arbeitsverzeichnis hinzu $ git add HelloWorld.java # Fügt eine Datei aus einem verschachtelten Verzeichnis hinzu $ git add /path/to/file/HelloWorld.c # Reguläre Ausdrücke werden unterstützt! $ git add ./*.java ``` ### branch Verwalte alle Branches. Du kannst sie mit diesem Befehl ansehen, bearbeiten, neue erzeugen oder löschen. ```bash # Liste alle bestehenden Branches und Remotes auf $ git branch -a # Erstelle einen neuen Branch $ git branch myNewBranch # Lösche einen Branch $ git branch -d myBranch # Benenne einen Branch um # git branch -m $ git branch -m myBranchName myNewBranchName # Ändere die Beschreibung eines Branchs $ git branch myBranchName --edit-description ``` ### checkout Bringt alle Dateien im Arbeitsverzeichnis auf den Stand des Index oder des angegebenen Branches. ```bash # Ein Repo auschecken - wenn nicht anders angegeben ist das der master $ git checkout # Eine Datei auschecken - sie befindet sich dann auf dem aktuellen Stand im Repository $ git checkout /path/to/file # Einen bestimmten Branch auschecken $ git checkout branchName # Erstelle einen neuen Branch und wechsle zu ihm. Wie: "git branch ; git checkout " $ git checkout -b newBranch ``` ### clone Ein bestehendes Repository in ein neues Verzeichnis klonen oder kopieren. Es fügt außerdem für jedes geklonte Repository remote-tracking Branches hinzu. Du kannst auf diese Remote-Branches pushen. ```bash # Klone learnxinyminutes-docs $ git clone https://github.com/adambard/learnxinyminutes-docs.git ``` ### commit Speichert die aktuellen Inhalte des Index in einen neuen *Commit*. Dieser Commit enthält alle Änderungen und eine vom Benutzer erstellte Beschreibung der Änderungen. ```bash # Commit mit Beschreibung erstellen. $ git commit -m "Added multiplyNumbers() function to HelloWorld.c" # Alle veränderten oder gelöschten Dateien außer neue Dateien werden gestaged und dann wird ein Commit erstellt. $ git commit -a -m "Modified foo.php and removed bar.php" # Ändert den letzten Commit (der letzte Commit wird mit einem neuen Commit ersetzt) $ git commit --amend -m "Correct message" ``` ### diff Zeigt die Unterschiede zwischen Dateien vom Arbeitsverzeichnis, dem Index und Commits an. ```bash # Unterschiede zwischen deinem Arbeitsverzeichnis und dem Index anzeigen $ git diff # Unterschiede zwischen dem Index und dem aktuellsten Commit anzeigen $ git diff --cached # Unterschiede zwischen deinem Arbeitsverzeichnis und dem aktuellsten Commit anzeigen $ git diff HEAD # Unterschiede zwischen dem Index und dem aktuellsten Commit (betrifft nur Dateien im Index) $ git diff --staged ``` ### grep Schnell ein Repository durchsuchen. Optionale Einstellungen: ```bash # Vielen Dank an Travis Jeffery für die Hinweise. # Zeilennummerierung in grep-Suchergebnissen $ git config --global grep.lineNumber true # Suchergebnisse lesbarer gestalten, auch Gruppierungen sind möglich $ git config --global alias.g "grep --break --heading --line-number" ``` ```bash # Suche nach "variableName" in allen java-Dateien $ git grep 'variableName' -- '*.java' # Suche nach eine Zeile, die "arrayListName" und "add" oder "remove" enthält $ git grep -e 'arrayListName' --and \( -e add -e remove \) ``` Google ist dein Freund; für mehr Beispiele: [Git Grep Ninja](https://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja) ### log Zeige Commits für das Repository an. ```bash # Zeige alle Commits $ git log # Zeige die Anzahl n an Commits $ git log -n 10 # Zeige nur Merges an $ git log --merges ``` ### merge *Merge*, also verschmelze, alle Änderungen von externen Commits in den aktuellen Branch. ```bash # Merge den angegebenen Branch in den aktuellen. $ git merge branchName # Erstelle immer einen Merge-Commit. $ git merge --no-ff branchName ``` ### mv Eine Datei umbenennen oder verschieben. ```bash # Umbenennen $ git mv HelloWorld.c HelloNewWorld.c # Verschieben $ git mv HelloWorld.c ./new/path/HelloWorld.c # Umbenennung oder Verschieben erzwingen # "existingFile" besteht schon im Verzeichnis, wird überschrieben mit "myFile" $ git mv -f myFile existingFile ``` ### pull Führe einen Pull (zieht alle Daten eines Repositories) aus und führt einen Merge mit einem anderen Branch durch. ```bash # Update deines lokalen Repos, indem ein Merge der neuen Änderungen # von den remote-liegenden "origin"- und "master"-Branches durchgeführt wird. # git pull # git pull => impliziter Verweis auf origin und master $ git pull origin master # Führt einen Merge von Änderungen eines remote-Branch und ein Rebase # des Branch-Commits im lokalen Repo durch. Wie: pull , git rebase " $ git pull origin master --rebase ``` ### push Führe einen Push, ein Hochladen, und einen Merge von Änderungen eines remote-Branch mit einem Branch aus. ```bash # Führe Push und Merge von Änderungen des lokalen Repo zu einem # remote-Branch namens "origin" und dem "master"-Branch aus. # git push # git push => impliziter Verweis auf => git push origin master $ git push origin master ``` ### rebase (mit Vorsicht einsetzen) Nimm alle Änderungen, die in einem Branch durch Commits vorgenommen wurden, und übertrage sie auf einen anderen Branch. Achtung: Führe keinen Rebase von Commits durch, die auf ein öffentliches Repo gepusht wurden! ```bash # Rebase "experimentBranch" in den "master"-Branch # git rebase $ git rebase master experimentBranch ``` [Weiterführende Informationen](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) ### reset (mit Vorsicht einsetzen) Setze den aktuellen HEAD auf den angegebenen Zustand zurück. So können Merges, Pulls, Commits, Hinzufügungen und andere Änderungen rückgängig gemacht werden. Es ist ein hervorragender Befehl, aber auch sehr gefährlich, wenn du nicht weißt, was du tust. ```bash # Setze die Staging-Area zurück, um dem letzten Commit zu entsprechen (das Verzeichnis bleibt unberührt) $ git reset # Setze die Staging-Area zurück, um dem letzten Commit zu entsprechen und überschreibe das Arbeitsverzeichnis $ git reset --hard # Bewegt die Spitze des Branches zu dem angegebenen Commit (das Verzeichnis bleibt unberührt) # Alle Änderungen bleiben im Verzeichnis erhalten $ git reset 31f2bb1 # Bewegt die Spitze des Branches zurück zu dem angegebenen Commit # und gleicht die Arbeitsverzeichnisse ab (löscht nicht vom Commit erfasste Änderungen und alle Commits, # die dem angegebenen Commit folgen). $ git reset --hard 31f2bb1 ``` ### rm Das Gegenteil von *git add*. *git rm* löscht Dateien vom Arbeitsverzeichnis. ```bash # Entferne HelloWorld.c $ git rm HelloWorld.c # Entferne eine Datei aus einem verschachtelten Verzeichnis $ git rm /pather/to/the/file/HelloWorld.c ``` ## Weiterführende Informationen * [git-scm - Video Tutorials](https://git-scm.com/videos) * [git-scm - Documentation](https://git-scm.com/docs) * [Atlassian Git - Tutorials & Workflows](https://www.atlassian.com/git/) * [gitflow - Ein Modell um mit Branches zu arbeiten](https://nvie.com/posts/a-successful-git-branching-model/) * [Git For Computer Scientists](https://eagain.net/articles/git-for-computer-scientists/) ================================================ FILE: de/go.md ================================================ --- contributors: - ["Joseph Adams", "https://github.com/jcla1"] - ["Dennis Keller", "https://github.com/denniskeller"] translators: - ["Jerome Meinke", "https://github.com/jmeinke"] --- Die Sprache Go (auch golang) wurde von Google entwickelt und wird seit 2007 benutzt. Go ähnelt in der Syntax der Sprache C, bietet darüber hinaus aber viele Vorteile. Einerseits verzichtet Go auf Speicherarithmetik und benutzt einen Garbage Collector. Andererseits enthält Go native Sprachelemente für die Unterstützung von Nebenläufigkeit. Durch den Fokus auf einen schnellen Kompilierprozess wird außerdem die Softwareentwicklung in Großprojekten erleichtert. Außerdem beinhaltet Go eine gut ausgestattete Standardbibliothek und hat eine aktive Community. ```go // Einzeiliger Kommentar /* Mehr- zeiliger Kommentar */ // Wie bei Java gehört jede Quelldatei einem Paket an (Modularisierung). // "main" ist ein besonderer Paketname, da er ein ausführbares Programm // einleitet, im Gegensatz zu jedem anderen Namen, der eine Bibliothek // deklariert. package main // Ein "import" wird verwendet, um Pakete zu deklarieren, die in dieser // Quelldatei Anwendung finden. import ( "fmt" // Ein Paket in der Go Standardbibliothek "net/http" // Ja, ein Webserver. "strconv" // Zeichenkettenmanipulation ) // Es folgt die Definition einer Funktion, in diesem Fall von "main". Auch hier // ist der Name wieder besonders. "main" markiert den Eintrittspunkt des // Programms. func main() { // Println gibt eine Zeile zu stdout aus. // Der Prefix "fmt" bestimmt das Paket aus welchem die Funktion stammt. fmt.Println("Hello world!") // Aufruf einer weiteren Funktion definiert innerhalb dieses Pakets. beyondHello() } // Funktionen können Parameter akzeptieren. Diese werden in Klammern deklariert, // die aber auch ohne Parameter erforderlich sind. func beyondHello() { var x int // Deklaration einer Variable, muss vor Gebrauch geschehen. x = 3 // Zuweisung eines Werts. // Kurze Deklaration: Benutzen Sie ":=", um die Typisierung automatisch zu // folgern, die Variable zu deklarieren und ihr einen Wert zuzuweisen. y := 4 // Eine Funktion mit mehreren Rückgabewerten. sum, prod := learnMultiple(x, y) fmt.Println("sum:", sum, "prod:", prod) // Simple Ausgabe learnTypes() // In < y Minuten lernen Sie mehr! } // Funktionen können mehrere Parameter und (mehrere!) Rückgabewerte haben. func learnMultiple(x, y int) (sum, prod int) { return x + y, x * y // Wiedergabe zweier Werte } // Überblick über einige eingebaute Typen und Literale. func learnTypes() { // Kurze Deklarationen sind die Norm. s := "Lernen Sie Go!" // Zeichenketten-Typ s2 := `Eine "raw" Zeichenkette kann Zeilenumbrüche beinhalten.` // Selber Zeichenketten-Typ // nicht-ASCII Literal. Go Quelltext ist UTF-8 kompatibel. g := 'Σ' // Ein Runen-Typ, alias int32, gebraucht für unicode code points. f := 3.14159 // float64, eine IEEE-754 64-bit Dezimalzahl c := 3 + 4i // complex128, besteht intern aus zwei float64-er // "var"-Syntax mit Initialwert var u uint = 7 // Vorzeichenlos, aber die Größe ist implementationsabhängig var pi float32 = 22. / 7 // Umwandlungs-Syntax mit kurzer Deklaration n := byte('\n') // byte ist ein Alias für uint8 // Arrays haben bei Kompile-Zeit festgelegte Größen var a4 [4]int // Ein Array mit 4 ints, alle mit Initialwert 0 a3 := [...]int{3, 1, 5} // Ein Array mit 3 ints, Initialwerte wie angezeigt // "slices" haben eine dynamische Größe. Arrays und Slices haben beide ihre // Vorzüge, aber slices werden viel häufiger verwendet s3 := []int{4, 5, 9} // Vergleichen Sie mit a3, hier: keine Ellipse s4 := make([]int, 4) // Weist Speicher für 4 ints zu, alle mit Wert 0 var d2 [][]float64 // Nur eine Deklaration, keine Speicherzuweisung bs := []byte("eine slice") // Umwandlungs-Syntax p, q := learnMemory() // Deklariert p & q als Zeiger zu einer int. fmt.Println(*p, *q) // Die gibt die zwei Werte aus. "*" für den Zugriff // "Maps" sind dynamische Datenstrukturen mit variabler Größe. Sie sind wie // "hashs" oder "dictionaries" aus anderen Sprachen. m := map[string]int{"drei": 3, "vier": 4} m["eins"] = 1 // Ungebrauchte Variablen sind Fehler in Go // Der Unterstrich wird verwendet, um einen Wert zu verwerfen. _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs // Die Ausgabe zählt natürlich auch als Gebrauch fmt.Println(s, c, a4, s3, d2, m) learnFlowControl() // Auf zum Kontrollfluss! } // Go ist komplett "garbage collected". Sie unterstützt Zeiger (pointers) aber // keine Zeiger-Rechnungen. Fehler können sich durch "nil" einschleichen, jedoch // nicht durch erhöhen eines Zeigers. func learnMemory() (p, q *int) { // Die benannten Rückgabewerte p & q sind vom Typ *int p = new(int) // Eingebaute Funktion "new" weist neuen Speicherplatz zu // Der zugewiesene Speicher ist mit 0 initialisiert, p ist nicht länger nil s := make([]int, 20) // So weist man 20 ints nebeneinander (im Speicher) zu s[3] = 7 // Einer von ihnen wird ein Wert zugewiesen r := -2 // Deklaration einer weiteren lokalen Variable return &s[3], &r // & gibt die Adresse einer Variable } func expensiveComputation() int { return 1e6 } func learnFlowControl() { // Bedingte Anweisungen verlangen nach geschweiften Klammern, normale // Klammern um die Bedingung werden aber nicht gebraucht. if true { fmt.Println("hab's dir ja gesagt!") } // Die Formatierung ist durch den Befehl "go fmt" standardisiert if false { // nicht hier } else { // sondern hier! spielt die Musik } // Benutzen Sie ein "switch" Statement anstatt eine Anreihung von if-s x := 1 switch x { case 0: case 1: // Einzelne Fälle fallen nicht zum nächsten durch! case 2: // wird nicht ausgeführt } // Wie bei "if", braucht "for" auch keine Klammern um die Bedingung for x := 0; x < 3; x++ { // ++ ist ein Statement fmt.Println(x, "-te Iteration") } // Ab hier gilt wieder: x == 1 // For ist die einzige Schleifenform in Go, sie hat aber mehrere Formen: for { // Endlosschleife break // nur ein Spaß continue // wird nie ausgeführt } // Wie bei for, bedeutet := in einer bedingten Anweisung zunächst die // Zuweisung und erst dann die Überprüfung der Bedingung. if y := expensiveComputation(); y > x { x = y } // Funktionsliterale sind "closures" xBig := func() bool { return x > 100 // Verweist auf x, deklariert vor dem switch } fmt.Println("xBig:", xBig()) // true (im moment gilt: x == 1e6) x /= 1e5 // dies macht x == 10 fmt.Println("xBig:", xBig()) // jetzt: false // Wenn Sie's brauchen, werden Sie's lieben! goto love love: learnInterfaces() // Jetzt zum interessanten Teil! } // Definiere "Stringer" als ein Interface mit einer Methode: String type Stringer interface { String() string } // Definiere ein Paar als struct mit zwei Feldern, Integers mit Namen x & y. type pair struct { x, y int } // Definiere eine Methode von "pair". // Dieser Typ erfüllt jetzt das Stringer interface. func (p pair) String() string { // p ist der Empfänger // Sprintf ist eine weitere öffentliche Funktion von fmt. // Der Syntax mit Punkt greift auf die Felder zu. return fmt.Sprintf("(%d, %d)", p.x, p.y) } func learnInterfaces() { // Der Klammer-Syntax ist ein "struct literal". Es ist ein vollkommen // initialisiertes struct. Der := Syntax deklariert und initialisiert p. p := pair{3, 4} fmt.Println(p.String()) // Aufruf der String() Methode von p. var i Stringer // Deklariere i vom Typ: Stringer i = p // Ok, weil p auch vom Typ Stringer ist. // Aufruf der String Methode von i, gleiche Ausgabe wie zuvor. fmt.Println(i.String()) // Funktionen des fmt-Pakets rufen die String() Methode auf um eine // druckbare Variante des Empfängers zu erhalten. fmt.Println(p) // gleiche Ausgabe wie zuvor fmt.Println(i) // und wieder die gleiche Ausgabe wie zuvor learnErrorHandling() } func learnErrorHandling() { // Das ", ok" Idiom wird häufig verwendet um zu überprüfen ob etwas schief // gegangen ist. m := map[int]string{3: "drei", 4: "vier"} if x, ok := m[1]; !ok { // ok wird false sein, da 1 nicht in der map ist. fmt.Println("keine eins gefunden") } else { fmt.Print(x) // x wäre der Wert, wenn er in der map wäre. } // Ein Fehler-Wert (error value) gibt mehr Informationen über den Grund für // das Problem an. if _, err := strconv.Atoi("nicht-int"); err != nil { // _ verwirft den Wert // Gibt: "strconv.ParseInt: parsing "nicht-int": invalid syntax" aus fmt.Println(err) } // Wir kommen bald nochmal auf Interfaces zurück. Aber inzwischen: learnConcurrency() } // c ist ein Kanal, ein sicheres Kommunikationsmedium. func inc(i int, c chan int) { c <- i + 1 // <- ist der "send" Operator, wenn ein Kanal auf der Linken ist } // Wir verwenden "inc" um Zahlen parallel zu erhöhen. func learnConcurrency() { // Die selbe "make"-Funktion wie vorhin. Sie initialisiert Speicher für // maps, slices und Kanäle. c := make(chan int) // Starte drei parallele "Goroutines". // Die Zahlen werden parallel (concurrently) erhöht. // Alle drei senden ihr Ergebnis in den gleichen Kanal. go inc(0, c) // "go" ist das Statement zum Start einer neuen Goroutine go inc(10, c) go inc(-805, c) // Auslesen und dann Ausgeben der drei berechneten Werte. // Man kann nicht im voraus feststellen in welcher Reihenfolge die Werte // ankommen. fmt.Println(<-c, <-c, <-c) // mit dem Kanal rechts ist <- der Empfangs-Operator cs := make(chan string) // ein weiterer Kanal, diesmal für strings cc := make(chan chan string) // ein Kanal für string Kanäle // Start einer neuen Goroutine, nur um einen Wert zu senden go func() { c <- 84 }() go func() { cs <- "wortreich" }() // schon wieder, diesmal für // "select" hat eine Syntax wie ein switch Statement, aber jeder Fall ist // eine Kanaloperation. Es wählt einen Fall zufällig aus allen, die // kommunikationsbereit sind, aus. select { case i := <-c: // der empfangene Wert kann einer Variable zugewiesen werden fmt.Printf("es ist ein: %T", i) case <-cs: // oder der Wert kann verworfen werden fmt.Println("es ist eine Zeichenkette!") case <-cc: // leerer Kanal, nicht bereit für den Empfang fmt.Println("wird nicht passieren.") } // Hier wird eine der beiden Goroutines fertig sein, die andere nicht. // Sie wird warten bis der Wert den sie sendet von dem Kanal gelesen wird. learnWebProgramming() // Go kann es und Sie hoffentlich auch bald. } // Eine einzige Funktion aus dem http-Paket kann einen Webserver starten. func learnWebProgramming() { // Der erste Parameter von "ListenAndServe" ist eine TCP Adresse, an die // sich angeschlossen werden soll. // Der zweite Parameter ist ein Interface, speziell: ein http.Handler err := http.ListenAndServe(":8080", pair{}) fmt.Println(err) // Fehler sollte man nicht ignorieren! } // Wir lassen "pair" das http.Handler Interface erfüllen, indem wir seine einzige // Methode implementieren: ServeHTTP func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Senden von Daten mit einer Methode des http.ResponseWriter w.Write([]byte("Sie haben Go in Y Minuten gelernt!")) } ``` ## Weitere Resourcen Informationen zu Go findet man auf der [offiziellen Go Webseite](https://go.dev/). Dort gibt es unter anderem ein Tutorial und interaktive Quelltext-Beispiele, vor allem aber Dokumentation zur Sprache und den Paketen. Auch zu empfehlen ist die Spezifikation von Go, die nach heutigen Standards sehr kurz und gut verständlich formuliert ist. Auf der Leseliste von Go-Neulingen ist außerdem der Quelltext der [Go standard Bibliothek](https://go.dev/src/) einzusehen. Dieser kann als Referenz für leicht zu verstehendes und im idiomatischen Stil verfasstes Go dienen. Erreichbar ist der Quelltext auch durch das Klicken der Funktionsnamen in der [offiziellen Dokumentation von Go](https://go.dev/pkg/). ================================================ FILE: de/hack.md ================================================ --- contributors: - ["Stephen Holdaway", "https://github.com/stecman"] - ["David Lima", "https://github.com/davelima"] translators: - ["Jerome Meinke", "https://github.com/jmeinke"] --- Hack ist eine von Facebook neu entwickelte Programmiersprache auf Basis von PHP. Sie wird von der HipHop Virtual Machine (HHVM) ausgeführt. Die HHVM kann aufgrund der Ähnlichkeit der Programmiersprachen nicht nur Hack, sondern auch PHP-Code ausführen. Der wesentliche Unterschied zu PHP besteht in der statischen Typisierung der Sprache, die eine wesentlich höhere Performance erlaubt. Hier werden nur Hack-spezifische Eigenschaften beschrieben. Details über PHP's Syntax findet man im [PHP Artikel](/php/) dieser Seite. ```php id = $id; } } // Kurzgefasste anonyme Funktionen (lambdas) $multiplier = 5; array_map($y ==> $y * $multiplier, [1, 2, 3]); // Weitere, spezielle Felder (Generics) // Diese kann man sich als ein zugreifbares Interface vorstellen class Box { protected T $data; public function __construct(T $data) { $this->data = $data; } public function getData(): T { return $this->data; } } function openBox(Box $box) : int { return $box->getData(); } // Formen // // Hack fügt das Konzept von Formen hinzu, wie struct-ähnliche arrays // mit einer typ-geprüften Menge von Schlüsseln type Point2D = shape('x' => int, 'y' => int); function distance(Point2D $a, Point2D $b) : float { return sqrt(pow($b['x'] - $a['x'], 2) + pow($b['y'] - $a['y'], 2)); } distance( shape('x' => -1, 'y' => 5), shape('x' => 2, 'y' => 50) ); // Typen-Definition bzw. Aliasing // // Hack erlaubt es Typen zu definieren und sorgt somit für bessere Lesbarkeit newtype VectorArray = array>; // Ein Tupel mit zwei Integern newtype Point = (int, int); function addPoints(Point $p1, Point $p2) : Point { return tuple($p1[0] + $p2[0], $p1[1] + $p2[1]); } addPoints( tuple(1, 2), tuple(5, 6) ); // Erstklassige Aufzählungen (enums) enum RoadType : int { Road = 0; Street = 1; Avenue = 2; Boulevard = 3; } function getRoadType() : RoadType { return RoadType::Avenue; } // Automatische Erstellung von Klassen-Eigenschaften durch Konstruktor-Argumente // // Wiederkehrende Definitionen von Klassen-Eigenschaften können durch die Hack- // Syntax vermieden werden. Hack erlaubt es die Klassen-Eigenschaften über // Argumente des Konstruktors zu definieren. class ArgumentPromotion { public function __construct(public string $name, protected int $age, private bool $isAwesome) {} } class WithoutArgumentPromotion { public string $name; protected int $age; private bool $isAwesome; public function __construct(string $name, int $age, bool $isAwesome) { $this->name = $name; $this->age = $age; $this->isAwesome = $isAwesome; } } // Kooperatives Multitasking // // Die Schlüsselworte "async" and "await" führen Multitasking ein. // Achtung, hier werden keine Threads benutzt, sondern nur Aktivität getauscht. async function cooperativePrint(int $start, int $end) : Awaitable { for ($i = $start; $i <= $end; $i++) { echo "$i "; // Geben anderen Tasks die Möglichkeit aktiv zu werden await RescheduleWaitHandle::create(RescheduleWaitHandle::QUEUE_DEFAULT, 0); } } // Die Ausgabe von folgendem Code ist "1 4 7 2 5 8 3 6 9" AwaitAllWaitHandle::fromArray([ cooperativePrint(1, 3), cooperativePrint(4, 6), cooperativePrint(7, 9) ])->getWaitHandle()->join(); // Attribute // // Attribute repräsentieren eine Form von Metadaten für Funktionen. // Hack bietet Spezial-Attribute, die nützliche Eigenschaften mit sich bringen. // Das __Memoize Attribut erlaubt es die Ausgabe einer Funktion zu cachen. <<__Memoize>> function doExpensiveTask() : ?string { return file_get_contents('http://example.com'); } // Der Funktionsrumpf wird im Folgenden nur ein einziges mal ausgeführt: doExpensiveTask(); doExpensiveTask(); // Das __ConsistentConstruct Attribut signalisiert dem type-checker, dass // die Funktionsdeklaration von __construct für alle Unterklassen dieselbe ist. <<__ConsistentConstruct>> class ConsistentFoo { public function __construct(int $x, float $y) { // ... } public function someMethod() { // ... } } class ConsistentBar extends ConsistentFoo { public function __construct(int $x, float $y) { // Der Type-checker erzwingt den Aufruf des Eltern-Klassen-Konstruktors parent::__construct($x, $y); // ... } // Das __Override Attribut ist ein optionales Signal an den Type-Checker, // das erzwingt, dass die annotierte Methode die Methode der Eltern-Klasse // oder des Traits verändert. <<__Override>> public function someMethod() { // ... } } class InvalidFooSubclass extends ConsistentFoo { // Wenn der Konstruktor der Eltern-Klasse nicht übernommen wird, // wird der Type-Checker einen Fehler ausgeben: // // "This object is of type ConsistentBaz. It is incompatible with this object // of type ConsistentFoo because some of their methods are incompatible" // public function __construct(float $x) { // ... } // Auch bei der Benutzung des __Override Attributs für eine nicht veränderte // Methode wird vom Type-Checker eine Fehler ausgegeben: // // "InvalidFooSubclass::otherMethod() is marked as override; no non-private // parent definition found or overridden parent is defined in non-> public function otherMethod() { // ... } } // Ein Trait ist ein Begriff aus der objektorientierten Programmierung und // beschreibt eine wiederverwendbare Sammlung von Methoden und Attributen, // ähnlich einer Klasse. // Anders als in PHP können Traits auch als Schnittstellen (Interfaces) // implementiert werden und selbst Schnittstellen implementieren. interface KittenInterface { public function play() : void; } trait CatTrait implements KittenInterface { public function play() : void { // ... } } class Samuel { use CatTrait; } $cat = new Samuel(); $cat instanceof KittenInterface === true; // True ``` ## Weitere Informationen Die Hack [Programmiersprachen-Referenz](http://docs.hhvm.com/manual/de/hacklangref.php) erklärt die neuen Eigenschaften der Sprache detailliert auf Englisch. Für allgemeine Informationen kann man auch die offizielle Webseite [hacklang.org](http://hacklang.org/) besuchen. Die offizielle Webseite [hhvm.com](http://hhvm.com/) bietet Infos zum Download und zur Installation der HHVM. Hack's [nicht-unterstützte PHP Syntax-Elemente](http://docs.hhvm.com/manual/en/hack.unsupported.php) werden im offiziellen Handbuch beschrieben. ================================================ FILE: de/haml.md ================================================ --- contributors: - ["Simon Neveu", "https://github.com/sneveu"] - ["Sol Bekic", "https://github.com/S0lll0s"] --- Haml ist eine Markup- und Templatingsprache, aufgesetzt auf Ruby, mit der HTML Dokumente einfach beschrieben werden können. Haml vermindert Wiederholung und Fehleranfälligkeit, indem es Tags basierend auf der Markup-Struktur schließt und schachtelt. Dadurch ergibt sich kurzes, präzises und logisches Markup. Haml kann außerhalb eines Ruby-projekts verwendet werden. Mit dem installierten Haml gem kann man das Terminal benutzen um Haml zu HTML umzuwandeln: $ haml input_file.haml output_file.html ```haml / ------------------------------------------- / Einrückung / ------------------------------------------- / Einrückung ist ein wichtiges Element des Haml Syntax, deswegen ist es wichtig ein konsequentes Schema zu verwenden. Meistens werden zwei spaces verwendet, solange die Einrückungen das gleiche Schema verfolgen können aber auch andere Breiten und Tabs verwendet werden / ------------------------------------------- / Kommentare / ------------------------------------------- / Kommentare beginnen mit einem Slash / Mehrzeilige Kommentare werden eingerückt und mit einem Slash eingeführt -# Diese Zeile ist ein "stummes" Kommentar, es wird nicht mitgerendert / ------------------------------------------- / HTML Elemente / ------------------------------------------- / Tags werden durch ein Prozentzeichen und den Tagnamen erzeugt %body %header %nav / Die Zeilen oben würden folgendes ergeben:
/ Text kann direkt nach dem Tagnamen eingefügt werden: %h1 Headline copy / Mehrzeilige Inhalte müssen stattdessen eingerückt werden: %p This is a lot of content that we could probably split onto two separate lines. / HTML kann mit &= escaped werden. So werden HTML-sensitive Zeichen enkodiert. Zum Beispiel: %p &= "Ja & Nein" / würde 'Ja & Nein' ergeben / HTML kann mit != dekodiert werden: %p != "so schreibt man ein Paragraph-Tag:

" / ...was 'This is how you write a paragraph tag

' ergeben würde / CSS Klassen können mit '.classname' an Tags angehängt werden: %div.foo.bar / oder über einen Ruby Hash: %div{:class => 'foo bar'} / Das div Tag wird standardmäßig verwendet, divs können also verkürzt werden: .foo / andere Attribute können über den Hash angegeben werden: %a{:href => '#', :class => 'bar', :title => 'Bar'} / Boolesche Attribute können mit 'true' gesetzt werden: %input{:selected => true} / data-Attribute können in einem eigenen Hash im :data key angegeben werden: %div{:data => {:attribute => 'foo'}} / ------------------------------------------- / Verwendung von Ruby / ------------------------------------------- / Mit dem = Zeichen können Ruby-werte evaluiert und als Tag-text verwendet werden: %h1= book.name %p = book.author = book.publisher / Code nach einem Bindestrich wird ausgeführt aber nicht gerendert: - books = ['book 1', 'book 2', 'book 3'] / So können zum Beispiel auch Blöcke verwendet werden: - books.shuffle.each_with_index do |book, index| %h1= book if book do %p This is a book / Auch hier werden wieder keine End-Tags benötigt! Diese ergeben sich aus der Einrückung. / ------------------------------------------- / Inline Ruby / Ruby Interpolation / ------------------------------------------- / Ruby variablen können mit #{} in Text interpoliert werden: %p dein bestes Spiel ist #{best_game} / ------------------------------------------- / Filter / ------------------------------------------- / Mit dem Doppelpunkt können Haml Filter benutzt werden. Zum Beispiel gibt es den :javascript Filter, mit dem inline JS geschrieben werden kann: :javascript console.log('Dies ist ein ``` ### Optimizar todo un proyecto usando r.js Muchas personas prefieren usar AMD para la organización del código durante el desarrollo, pero quieren enviar para producción un solo fichero en vez de ejecutar cientos de XHRs en las cargas de página. `require.js` incluye un script llamado `r.js` (el que probablemente correrás en node.js, aunque Rhino también es soportado) que puede analizar el gráfico de dependencias de tu proyecto, y armar un solo fichero que contenga todos tus módulos (adecuadamente nombrados), minificado y listo para consumo. Instálalo usando `npm`: ```shell $ npm install requirejs -g ``` Ahora puedes alimentarlo con un fichero de configuración: ```shell $ r.js -o app.build.js ``` Para nuestro ejemplo anterior el archivo de configuración luciría así: ```javascript /* file : app.build.js */ ({ name : 'main', // nombre del punto de entrada out : 'main-built.js', // nombre del fichero donde se escribirá la salida baseUrl : 'app', paths : { // `empty:` le dice a r.js que esto aún debe ser cargado desde el CDN, usando // la ubicación especificada en `main.js` jquery : 'empty:', coolLibFromBower : '../bower_components/cool-lib/coollib' } }) ``` Para usar el fichero creado en producción, simplemente intercambia `data-main`: ```html ``` Un increíblemente detallado [resumen de opciones de generación](https://github.com/jrburke/r.js/blob/master/build/example.build.js) está disponible en el repositorio de GitHub. ### Temas no cubiertos en este tutorial * [Cargador de plugins / transformaciones](http://requirejs.org/docs/plugins.html) * [Cargando y exportando estilos CommonJS](http://requirejs.org/docs/commonjs.html) * [Configuración avanzada](http://requirejs.org/docs/api.html#config) * [Configuración de Shim (cargando módulos no-AMD)](http://requirejs.org/docs/api.html#config-shim) * [Cargando y optimizando CSS con require.js](http://requirejs.org/docs/optimization.html#onecss) * [Usando almond.js para construcciones](https://github.com/jrburke/almond) ### Otras lecturas: * [Especificaciones oficiales](https://github.com/amdjs/amdjs-api/wiki/AMD) * [¿Por qué AMD?](http://requirejs.org/docs/whyamd.html) * [Definición Universal de Módulos](https://github.com/umdjs/umd) ### Implementaciones: * [require.js](http://requirejs.org) * [dojo toolkit](http://dojotoolkit.org/documentation/tutorials/1.9/modules/) * [cujo.js](http://cujojs.com/) * [curl.js](https://github.com/cujojs/curl) * [lsjs](https://github.com/zazl/lsjs) * [mmd](https://github.com/alexlawrence/mmd) ================================================ FILE: es/asciidoc.md ================================================ --- contributors: - ["Ryan Mavilia", "http://unoriginality.rocks/"] translators: - ["Abel Salgado Romero", "https://twitter.com/abelsromero"] --- AsciiDoc es un lenguaje de marcas similar a Markdown que puede ser usado para cualquier uso, desde libros a blogs. Creado en 2002 por Stuart Rackham, el lenguaje es simple pero permite un gran nivel de personalización. Cabecera de documento La cabecera es opcional y no puede contener lineas vacías. Debe estar separada del contenido por al menos una línea en blanco. Solo título ``` = Título de documento Primer contenido del documento. ``` Título y autor ``` = Título del documento Nombre Apellido(s) Inicio de este documento. ``` Múltiples autores ``` = Título del documento John Doe ; Jane Doe; Black Beard Inicio de un documento con múltiples autores. ``` Linea de versión (requiere línea de autor) ``` = Título del documento V1 Potato Man v1.0, 2016-01-13 Este artículo sobre patatas fritas será genial. ``` Párrafo ``` No necesitas nada especial para un párrafo. Inserta una línea vacía entre cada párrafo para separarlos. Para insertar un salto de línea, solo añade un + y ya lo tienes! ``` Dando formato al texto ``` _guión bajo para cursiva_ *asteriscos para negrita* *_combínalos y verás_* `usa comillas invertidas para monospace` `*combina para negrita monospace*` ``` Títulos de sección ``` = Nivel 0 (úsalo solo para el título del documento) == Nivel 1

=== Nivel 2

==== Nivel 3

===== Nivel 4

``` Listas Para crear una lista sin orden usa asteriscos. ``` * foo * bar * baz ``` Para crear una lista numerada usa puntos. ``` . item 1 . item 2 . item 3 ``` Puedes crear hasta 5 subniveles en las listas añadiendo asteriscos o puntos. ``` * foo 1 ** foo 2 *** foo 3 **** foo 4 ***** foo 5 . foo 1 .. foo 2 ... foo 3 .... foo 4 ..... foo 5 ``` ## Referencias Existen dos herramientas para procesar documentación en AsciiDoc: 1. [AsciiDoc](http://asciidoc.org/): implementación original para Python, disponible en las principales distribuciones Linux. Versión estable actualmente en modo mantenimiento. 2. [Asciidoctor](http://asciidoctor.org/): implementación alternativa para Ruby, usable también desde Java y JavaScript. Implementación completa en evolución, su objetivo es ampliar AsciiDoc con nuevas funcionalidades y conversores de salida. Los siguientes enlaces pertenecen a `Asciidoctor` (documentación en inglés): * [Comparación de sintaxis Markdown - AsciiDoc](http://asciidoctor.org/docs/user-manual/#comparison-by-example): comparativa de elements comunes entre Markdown y AsciiDoc. * [Primeros pasos](http://asciidoctor.org/docs/#get-started-with-asciidoctor): manuales de instalación e inicio para convertir documentos simples. * [Manual de usuario de Asciidoctor](http://asciidoctor.org/docs/user-manual/): referencia completa en un único documento, contiene ejemplos, guías de herramientas, etc. ================================================ FILE: es/asymptotic-notation.md ================================================ --- contributors: - ["Jake Prather", "http://github.com/JakeHP"] translators: - ["Gerson Lázaro", "https://gersonlazaro.com"] --- # Notaciones asintóticas ## ¿Qué son? Las notaciones asintóticas son lenguajes que nos permitan analizar el tiempo de ejecución de un algoritmo identificando su comportamiento si el tamaño de entrada para el algoritmo aumenta. Esto también se conoce como la tasa de crecimiento de un algoritmo. ¿El algoritmo de repente se vuelve increíblemente lento cuando el tamaño de entrada crece? ¿Tiende a mantener un rápido tiempo de ejecución a medida que el tamaño de entrada aumenta? La notación asintótica nos da la capacidad para responder a estas preguntas. ## ¿Hay alternativas que respondan a estas preguntas? Una manera sería contar el número de operaciones primitivas en diferentes tamaños de entrada. Aunque esta es una solución válida, la cantidad de trabajo que esto conlleva, incluso para los algoritmos simples, no justifica su uso. Otra manera es medir físicamente la cantidad de tiempo que un algoritmo toma para completar su ejecución dados diferentes tamaños de entrada. Sin embargo, la exactitud y la relatividad (los tiempos obtenidos sólo serían relativos a la máquina sobre la cual se calcularon) de este método está ligado a variables ambientales tales como especificaciones de hardware, capacidad de procesamiento, etc. ## Tipos de Notación Asintótica En la primera sección de este documento hemos descrito cómo una notación asintótica identifica el comportamiento de un algoritmo ante los cambios en el tamaño de la entrada. Imaginemos un algoritmo como una función f, con tamaño de entrada n, y f(n) siendo el tiempo de ejecución. Así que para un algoritmo f dado, con el tamaño de entrada n obtenemos algún tiempo de ejecución resultante f(n). Esto resulta en un gráfico donde el eje Y es el tiempo de ejecución, el eje X es el tamaño de la entrada y los puntos en el gráfico son los resultantes de la cantidad de tiempo para un tamaño de entrada dado. Puedes etiquetar una función, o un algoritmo, con una notación asintótica de muchas maneras diferentes. Algunos ejemplos son describir un algoritmo por su mejor caso, su peor caso, o el caso promedio. Lo más común es analizar un algoritmo por su peor caso. Por lo general, no se evalúa el mejor caso, porque no planeas el algoritmo para estas condiciones. Un muy buen ejemplo de esto son los algoritmos de ordenamiento; específicamente, añadir elementos a un árbol. El mejor caso para la mayoría de los algoritmos podría ser tan bajo como una sola operación. Sin embargo, en la mayoría de los casos, el elemento que está añadiendo tendrá que ser ordenado adecuadamente a través del árbol, lo que podría significar examinar toda una rama. Este es el peor de los casos, y para estos casos es que planeamos el algoritmo. ### Tipos de funciones, límites, y simplificación ``` Función logarítmica - log n Función lineal - an + b Función cuadrática - an^2 + bn + c Función polinomicas - an^z + . . . + an^2 + a*n^1 + a*n^0, donde z es constante Función exponencial - a^n, donde a es constante ``` Estas son algunas clasificaciones de funciones de crecimiento básicos utilizados en varias notaciones. La lista comienza en la función de crecimiento menor (logarítmica, el tiempo de ejecución mas rápido) y pasa a la de mayor crecimiento (exponencial, el tiempo de ejecución mas lento). Observe como al crecer 'n', o la entrada, en cada una de estas funciones, el resultado aumenta claramente mucho más rápido en las cuadráticas, polinómicas y exponenciales, en comparación con las logarítmicas y lineales. Una anotación muy importante es que en las notaciones que se discutirán debes hacer tu mejor esfuerzo por utilizar los términos más simples. Esto significa hacer caso omiso de las constantes y terminos de orden inferior, porque a medida que el tamaño de entrada (o n en f(n)) aumenta hacia el infinito (límites matemáticos), los términos y constantes de orden inferior se vuelven de poca o ninguna importancia. Dicho esto, si tienes constantes que son 2^9001, o alguna otra cantidad ridícula, inimaginable, te daras cuenta de que la simplificación sesgará la exactitud de la notación. Como queremos algo simplificado, vamos a modificarlo un poco... ``` Logarítmico - log n Lineal - n Cuandrático - n^2 Polinómico - n^z, donde z es constante Exponencial - a^n, donde a es constante ``` ### O-grande (Big-O) O-grande (Big-O), comúnmente escrito como O, es una notación asintótica para el peor caso, o el techo de crecimiento para una función determinada. Si `f (n)` es el tiempo de ejecución del algoritmo, y `g (n)` es un tiempo de complejidad arbitraria que relacionas con el algoritmo, entonces `f (n)` es O(g(n)), si por cualquier constante real c (c > 0), `f (n)` <= `c g(n)` para cada tamaño de entrada n (n > 0 ). *Ejemplo 1* ``` f(n) = 3log n + 100 g(n) = log n ``` `f(n)` es O(g(n))? `3 log n + 100` es O(log n)? Echemos un vistazo a la definición de O-grande. ``` 3log n + 100 <= c * log n ``` ¿Hay alguna constante c que satisface esto para todo n? ``` 3log n + 100 <= 150 * log n, n > 2 (indefinido en n = 1) ``` ¡Sí! La definición de O-grande se cumple, por lo tanto `f (n)` es O(g(n)). *Ejemplo 2* ``` f(n) = 3*n^2 g(n) = n ``` `f(n)` es O(g(n))? `3 * n^2` es O(n)? Echemos un vistazo a la definición de O-grande. ``` 3 * n^2 <= c * n ``` ¿Hay alguna constante c que satisface esto para todo n? No, no la hay. `f(n)` no es O(g(n)). ### Big-Omega Big-Omega, comunmente escrito como Ω, es una notación asintótica para el mejor caso, o el piso en el crecimiento para una función dada. `f(n)` es Ω(g(n)), si para cualquier constante real c (c > 0), `f(n)` es >= `c g(n)` para cualquier tamaño de entrada n (n > 0). No dudes en dirigirte a los recursos adicionales para ejemplos sobre esto. O-grande es la notación principal utilizada para la complejidad general de tiempo algoritmico. ### Notas finales Es difícil mantener este tipo de tema corto, y sin duda deberias revisar los libros y recursos en línea en la lista. Entran en mucha mayor profundidad con definiciones y ejemplos. ## Libros * [Algoritmos (Algorithms)](http://www.amazon.com/Algorithms-4th-Robert-Sedgewick/dp/032157351X) * [Diseño de algoritmos (Algorithm Design)](http://www.amazon.com/Algorithm-Design-Foundations-Analysis-Internet/dp/0471383651) ## Recursos Online * [MIT](http://web.mit.edu/16.070/www/lecture/big_o.pdf) * [KhanAcademy](https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/asymptotic-notation) * [Apuntes Facultad de Ingeniería](https://www.scribd.com/document/317979564/Apuntes-Sobre-Analisis-de-Algoritmos) ================================================ FILE: es/awk.md ================================================ --- contributors: - ["Marshall Mason", "http://github.com/marshallmason"] translators: - ["Hugo Guillén-Ramírez", "http://github.com/HugoGuillen"] --- AWK es una herramienta estándar en cada sistema UNIX compatible con POSIX. Es como un Perl restringido, perfecto para tareas de procesamiento de texto y otras necesidades de scripting. Tiene una sintaxis similar a C, pero sin puntos y comas, manejo manual de memoria y tipado estático. Puedes llamarlo desde un script de shell o usarlo como un lenguaje stand-alone para scripting. ¿Por qué elegir AWK sobre Perl? Principalmente, porque AWK es parte de UNIX. Siempre puedes contar con él, mientras que el futuro de Perl está en duda. AWK es más fácil de leer que Perl. Para scripts sencillos de procesamiento de texto, particularmente si es para leer archivos línea a línea y dividir por delimitadores, probablemente AWK es la herramienta correcta para el trabajo. ```awk #!/usr/bin/awk -f # Los comentarios tienen este aspecto. # Los programas AWK son una colección de patrones y acciones. El patrón más # importante es BEGIN. Las acciones van en bloques delimitados por llaves. BEGIN { # BEGIN correrá al inicio del programa. Es donde pones todo el código # preliminar antes de procesar los archivos de texto. Si no tienes archivos # de texto, piensa en BEGIN como el punto de entrada principal del script. # Las variables son globales. Asígnalas o úsalas sin declararlas. count = 0 # Los operadores son justo como en C (y amigos). a = count + 1 b = count - 1 c = count * 1 d = count / 1 e = count % 1 # módulo f = count ^ 1 # exponenciación a += 1 b -= 1 c *= 1 d /= 1 e %= 1 f ^= 1 # Incremento y decremento en uno a++ b-- # Como un operador prefijo, regresa el valor modificado ++a --b # Nota que no hay puntación para terminar las instrucciones # Instrucciones de control if (count == 0) print "Iniciando count en 0" else print "Eh?" # O puedes usar el operador ternario print (count == 0) ? "Iniciando count en 0" : "Eh?" # Bloques formados por múltiples líneas usan llaves while (a < 10) { print "La concatenación de strings se hace " " con series " print " de" " strings separados por espacios" print a a++ } for (i = 0; i < 10; i++) print "El viejo confiable ciclo for" # Los operaciones de comparación son estándar... a < b # Menor que a <= b # Menor o igual que a != b # No igual a == b # Igual a > b # Mayor que a >= b # Mayor o igual que # ...así como los operadores lógicos a && b # AND a || b # OR # Además están las expresiones regulares if ("foo" ~ "^fo+$") print "Fooey!" if ("boo" !~ "^fo+$") print "Boo!" # Arrays arr[0] = "foo" arr[1] = "bar" # Desafortunadamente no hay otra manera de inicializar un array. # Tienes que inicializar cada posición del array. # También hay arrays asociativos assoc["foo"] = "bar" assoc["bar"] = "baz" # Y arrays multidimensionales con limitaciones que no mencionaré aquí multidim[0,0] = "foo" multidim[0,1] = "bar" multidim[1,0] = "baz" multidim[1,1] = "boo" # Puedes probar pertenencia a un array if ("foo" in assoc) print "Fooey!" # También puedes usar el operador 'in' para iterar las claves de un array for (key in assoc) print assoc[key] # La terminal es un array especial llamado ARGV for (argnum in ARGV) print ARGV[argnum] # Puedes eliminar elementos de un array. # Esto es útil para prevenir que AWK suponga que algunos argumentos # son archivos por procesar. delete ARGV[1] # El número de argumentos de la terminal está en la variable ARGC print ARGC # AWK tiene tres categorías de funciones incluidas. # Demostraré esas funciones posteriormente. return_value = arithmetic_functions(a, b, c) string_functions() io_functions() } # Así se define una función function arithmetic_functions(a, b, c, localvar) { # Probablemente la parte más molesta de AWK es que no hay variables locales # Todo es global. No es problema en scripts pequeños, pero sí para # scripts más grandes. # Hay un work-around (mmm... hack). Los argumentos de las funciones son # locales para la función, y AWK permite definir más argumentos de función # de los que necesita, por lo que define las variables locales en la # declaración como en la función de arriba. Como convención, agrega # espacios en blanco para distinguir los parámetros de la función de las # variables locales. En este ejemplo, a, b y c son parámetros y localvar es # una variable local. # Ahora, a demostrar las funciones aritméticas # La mayoría de las implementaciones de AWK tienen funciones # trigonométricas estándar localvar = sin(a) localvar = cos(a) localvar = atan2(b, a) # arcotangente de b / a # Y cosas logarítmicas localvar = exp(a) localvar = log(a) # Raíz cuadrada localvar = sqrt(a) # Trucar un flotante a entero localvar = int(5.34) # localvar => 5 # Números aleatorios srand() # La semilla es el argumento. Por defecto usa el tiempo del sistema localvar = rand() # Número aleatorio entre 0 y 1. # Y aquí se regresa el valor return localvar } function string_functions( localvar, arr) { # AWK tiene algunas funciones para procesamiento de strings, # y muchas dependen fuertemente en expresiones regulares. # Buscar y remplazar, primer instancia (sub) o todas las instancias (gsub) # Ambas regresan el número de matches remplazados. localvar = "fooooobar" sub("fo+", "Meet me at the ", localvar) # localvar => "Meet me at the bar" gsub("e", ".", localvar) # localvar => "M..t m. at th. bar" # Buscar una cadena que haga match con una expresión regular # index() hace lo mismo, pero no permite expresiones regulares match(localvar, "t") # => 4, dado que 't' es el cuarto caracter # Separar con base en un delimitador split("foo-bar-baz", arr, "-") # a => ["foo", "bar", "baz"] # Otras funciones útiles sprintf("%s %d %d %d", "Testing", 1, 2, 3) # => "Testing 1 2 3" substr("foobar", 2, 3) # => "oob" substr("foobar", 4) # => "bar" length("foo") # => 3 tolower("FOO") # => "foo" toupper("foo") # => "FOO" } function io_functions( localvar) { # Ya has visto print print "Hello world" # También hay printf printf("%s %d %d %d\n", "Testing", 1, 2, 3) # AWK no tiene handles de archivos en sí mismo. Automáticamente abrirá un # handle de archivo cuando use algo que necesite uno. El string que usaste # para esto puede ser tratada como un handle de archivo para propósitos # de I/O. Esto lo hace similar al scripting de shell: print "foobar" >"/tmp/foobar.txt" # Ahora el string "/tmp/foobar.txt" es un handle. Puedes cerrarlo: close("/tmp/foobar.txt") # Aquí está como correr algo en el shell system("echo foobar") # => muestra foobar # Lee una línea de la entrada estándar (stdin) y lo guarda en localvar getline localvar # Lee una línea desde un pipe "echo foobar" | getline localvar # localvar => "foobar" close("echo foobar") # Lee una línea desde un archivo y la guarda en localvar getline localvar <"/tmp/foobar.txt" close("/tmp/foobar.txt") } # Como dije al inicio, los programas en AWK son una colección de patrones y # acciones. Ya conociste el patrón BEGIN. otros patrones sólo se usan si estás # procesando líneas desde archivos o stdin. # Cuando pasas argumentos a AWK, son tratados como nombres de archivos a # procesar. Los va a procesar todos, en orden. Imagínalos como un ciclo for # implícito, iterando sobre las líneas de estos archivos. Estos patrones y # acciones son como instrucciones switch dentro del ciclo. /^fo+bar$/ { # Esta acción se ejecutará por cada línea que haga match con la expresión # regular /^fo+bar$/, y será saltada por cualquier línea que no haga match. # Vamos a sólo mostrar la línea: print # ¡Wow, sin argumento! Eso es porque print tiene uno por defecto: $0. # $0 es el nombre de la línea actual que se está procesando. # Se crea automáticamente para ti. # Probablemente puedas adivinar que hay otras variables $. Cada línea es # separada implícitamente antes de que se llame cada acción, justo como lo # hace shell. Y, como shell, cada campo puede ser accesado con $. # Esto mostrará el segundo y cuarto campos de la línea print $2, $4 # AWK automáticamente define muchas otras variables que te ayudan a # inspeccionar y procesar cada línea. La más importante es NF # Imprime el número de campos de esta línea print NF # Imprime el último campo de esta línea print $NF } # Cada patrón es realmente un prueba de verdadero/falso. La expresión regular # en el último patrón también es una prueba verdadero/falso, pero parte de eso # estaba oculto. Si no le das un string a la prueba, supondrá $0, la línea que # se está procesando. La versión completa de esto es: $0 ~ /^fo+bar$/ { print "Equivalente al último patrón" } a > 0 { # Esto se ejecutará una vez por línea, mientras a sea positivo } # Y ya te das una idea. Procesar archivos de texto, leyendo una línea a la vez, # y haciendo algo con ella, particularmente separando en un deliminator, es tan # común en UNIX que AWK es un lenguaje de scripting que hace todo eso por ti # sin que tengas que pedirlo. Basta con escribir los patrones y acciones # basados en lo que esperas de la entrada y lo quieras quieras hacer con ella. # Aquí está un ejemplo de un script simple, para lo que AWK es perfecto. # El script lee un nombre de stdin y muestra el promedio de edad para todos los # que tengan ese nombre. Digamos que como argumento pasamos el nombre de un # archivo con este contenido: # # Bob Jones 32 # Jane Doe 22 # Steve Stevens 83 # Bob Smith 29 # Bob Barker 72 # # Éste es el script: BEGIN { # Primero, pedir al usuario el nombre print "¿Para qué nombre quieres el promedio de edad?" # Recuperar una línea de stdin, no de archivos en la línea de comandos getline name <"/dev/stdin" } # Ahora, hacer match con cada línea cuyo primer campo es el nombre dado $1 == name { # Aquí dentro tenemos acceso a variables útiles precargadas: # $0 es toda la línea # $3 es el tercer campo, la edad, que es lo que nos interesa # NF es el número de campos, que debe ser 3 # NR es el número de registros (líneas) vistos hasta ahora # FILENAME es el nombre del archivo que está siendo procesado # FS es el campo separador, " " en este caso # Y muchas más que puedes conocer ejecutando 'man awk' en la terminal. # Llevar el registro de la suma y cuantas líneas han hecho match. sum += $3 nlines++ } # Otro patrón especial es END. Va a ejecutarse después de procesar todos los # archivos de texto. A diferencia de BEGIN, sólo se ejecuta si le das dado una # entrada a procesar. Se ejecutará después de que todos los archivos hayan sido # leídos y procesados según las reglas y acciones que programaste. El propósito # es usualmente para mostrar un reporte final, o hacer algo con el agregado de # los datos que has acumulado durante la ejecución del script. END { if (nlines) print "La edad promedio para " name " es " sum / nlines } ``` Más información: * [Tutorial de AWK](http://www.grymoire.com/Unix/Awk.html) * [Página man de AWK](https://linux.die.net/man/1/awk) * [La guía del usuario de GNU Awk](https://www.gnu.org/software/gawk/manual/gawk.html): GNU Awk se encuentra en la mayoría de los sistemas Linux. ================================================ FILE: es/bash.md ================================================ --- contributors: - ["Max Yankov", "https://github.com/golergka"] - ["Darren Lin", "https://github.com/CogBear"] - ["Alexandre Medeiros", "http://alemedeiros.sdf.org"] - ["Denis Arh", "https://github.com/darh"] - ["akirahirose", "https://twitter.com/akirahirose"] - ["Anton Strömkvist", "http://lutic.org/"] translators: - ["Daniel Zendejas", "https://github.com/danielzendejas"] --- Tutorial de Shell en español. Bash es el nombre del shell de unix, el cual también es distribuido como el shell del sistema operativo GNU. También es el shell por defecto de Linux y macOS. Casi todos los ejemplos abajo pueden ser parte de un script shell o ser ejecutados directamente en la terminal. ```bash #!/bin/bash # La primera línea del script es el [shebang](http://en.wikipedia.org/wiki/Shebang_(Unix)) que le indica al sistema # cómo ejecutar el script. # Como te habrás dado cuenta, los comentarios en shell empiezan con #. # El shebang también es un comentario. # Ejemplo sencillo de hola mundo: echo ¡Hola mundo! # Cada comando empieza con una nueva línea, o después de un punto y coma: echo 'Esta es la primera línea'; echo 'Esta es la segunda línea' # Para declarar una variable se hace lo siguiente: VARIABLE="Mi string" # Pero no así: VARIABLE = "Mi string" # Bash decidirá que VARIABLE es un comando a ejecutar, dando un error. # Usando la variable: echo $VARIABLE echo "$VARIABLE" echo '$VARIABLE' # Cuando la variable es usada - o asignada, exportada, etcétera - se # escribe su nombre sin $. Si se quiere saber el valor de la variables, # entonces sí se usa $. Note que ' (comilla simple) no expandirá las # variables. # Sustitución de strings en variables. echo ${VARIABLE/Mi/Una} # Esto sustituirá la primera cadena "Mi" con "Una". # Substring de una variable. echo ${VARIABLE:0:7} # Esto va a regresar sólo los primeros 7 caracteres del valor. # Valor por defecto de una variable echo ${FOO:-"DefaultValueIfFOOIsMissingOrEmpty"} # Esto trabaja para null (VARIABLE=), string vacío (VARIABLE=""), } # cero (VARIABLE=0) regresa 0 # Variables del sistema: # Aquí hay algunas variables incluídas en el sistema: echo "El valor de regreso del último programa: $?" echo "PID del sistema: $$" echo "Número de argumentos: $#" echo "Argumentos del script: $@" echo "Argumentos del script separados en variables: $1 $2..." # Para leer un valor del input: echo "¿Cuál es tu nombre?" read NOMBRE # Note que no necesitamos declarar una variable echo ¡Hola, $NOMBRE! # Tenemos la estructura 'if' usual: # use 'man test' para más información sobre condicionales if [ $NOMBRE -ne $USER ] then echo "Tu nombre es tu usuario." else echo "Tu nombre no es tu usuario." fi # También hay ejecuciones condicionadas. echo "Siempre ejecutado" || echo "Sólo ejecutado si el primer comando falla" echo "Siempre ejecutado" && echo "Sólo ejecutado si el primer comando NO falla" # Para usar && y || con condicionales, se necesitan # múltiples pares de corchetes: if [ $NOMBRE == "Steve" ] && [ $EDAD -eq 15 ] then echo "Esto correrá si $NOMBRE es Steve Y $EDAD es 15." fi if [ $NOMBRE == "Daniya" ] || [ $NOMBRE == "Zach" ] then echo "Esto correrá si $NOMBRE es Daniya O Zach." fi # Las expresiones se denotan con el siguiente formato: echo $(( 10 + 5 )) # A diferencia de otros lenguajes de programación, bash es shell , así que # funciona en un contexto de directorio actual. Puedes listar archivos y # directorios en un directorio actual con el comando 'ls': ls # Estos comandos tienen opciones que controlan su ejecución: ls -l # Lista todos los archivos y directorios en líneas distintas. # Los resultados del comando anterior pueden ser pasados al siguiente # como input. El comando 'grep' filtra el input con los comandos provistos. # Así es como podemos listar archivos .txt en el directorio actual: ls -l | grep "\.txt" # Puedes también redireccionar el input y el error lanzado de algún comando. python2 hello.py < "input.in" python2 hello.py > "output.out" python2 hello.py 2> "error.err" # El error lanzado eliminará el contenido del archivo si es que existe, # para después escribir el error. Para que se concatene (en lugar de eliminar) # use el comando ">>". # Los comandos pueden ser sustituidos dentro de otros comandos usando $(): # El siguiente ejemplo despliega el número de archivos y directorios en el # directorio actual. echo "Hay $(ls | wc -l) elementos aquí." # Lo mismo puede ser hecho usando comillas invertidas `` pero no pueden ser # anidadas. El método preferido es $(). echo "Hay `ls | wc -l` elementos aquí." # Bash usa una estructura de casos similar al switch de Java o C++: case "$VARIABLE" in # Lista de patrones que las condiciones deben cumplir: 0) echo "Hay un cero.";; 1) echo "Hay un uno.";; *) echo "No es null.";; esac # Para los ciclos, se usa la estructura 'for'. Cicla para cada argumento dado: # El contenido de $VARIABLE se imprime tres veces. for VARIABLE in {1..3} do echo "$VARIABLE" done # ciclos while: while [true] do echo "cuerpo del ciclo..." break done # También se pueden definir sub-rutinas (funciones) # Definición: function miFuncion () { echo "Los argumentos trabajan igual que argumentos de script: $@" echo "Y: $1 $2..." echo "Esto es una función" return 0 } # O simplemente: miOtraFuncion () { echo "¡Otra forma de declarar funciones!" return 0 } # Para llamar a tu función foo "Mi nombre es:" $NOMBRE # Hay muchos comandos útiles que puedes aprender: # imprime las últimas 10 líneas del archivo file.txt tail -n 10 file.txt # imprime las primeras 10 líneas del archivo file.txt head -n 10 file.txt # ordena las líneas del archivo file.txt sort file.txt # identifica u omite las líneas repetidas, con -d las reporta uniq -d file.txt # imprime sólo la primera columna antes de cada ',' en el archivo| cut -d ',' -f 1 file.txt ``` [Leer más aquí.](https://www.gnu.org/software/bash/manual/bashref.html) ================================================ FILE: es/bf.md ================================================ --- contributors: - ["Prajit Ramachandran", "http://prajitr.github.io/"] - ["Mathias Bynens", "http://mathiasbynens.be/"] translators: - ["Daniel Zendejas", "https://github.com/DanielZendejas"] --- Brainfuck (con mayúscula sólo al inicio de una oración) es un lenguaje de programación extremadamente pequeño, Turing completo con sólo 8 comandos. Puedes probar brainfuck en tu navegador con [brainfuck-visualizer](http://fatiherikli.github.io/brainfuck-visualizer/). ```bf Cualquier caracter que no sea "><+-.,[]" (sin incluir las comillas) será ignorado. Brainfuck es representado por un arreglo de 30,000 celdas inicializadas en cero y un puntero apuntando la celda actual. Existen ocho comandos: + : Incrementa 1 al valor de la celda actual. - : Decrementa 1 al valor de la celda actual. > : Mueve el apuntador a la siguiente celda. (a la derecha) < : Mueve el apuntador a la celda anterior. (a la izquierda) . : Imprime el valor en ASCII de la celda actual (p.e. 65 = 'A') , : Lee un caracter como input y lo escribe en la celda actual. [ : Si el valor en la celda actual es cero mueve el apuntador hasta el primer ']' que encuentre. Si no es cero sigue a la siguiente instrucción. ] : Si el valor en la celda actual es cero, entonces sigue con la siguiente instrucción. Si no entonces mueve el apuntador hacia atrás hasta encontrar el primer '['. [ y ] forman un while. Obviamente, deben estar balanceados. Estos son algunos ejemplos de programas escritos con brainfuck. ++++++ [ > ++++++++++ < - ] > +++++ . Este programa imprime la letra 'A'. Primero, incrementa la celda #1 a 6. La celda #1 será usada para hacer los ciclos. Después entra al ciclo ([) y se mueve a la celda #2 (>). Después incrementa la celda #2 10 veces, y se regresa a la celda #1 (<), para después decrementarla en 1 (-). Este ciclo ocurre 6 veces (le toma 6 decrementos a la celda #1 volverse 0), cuando esto pasa se salta a (]) y continúa. En este punto estamos en la celda #1, que tiene un valor de 0, mientras que la celda #2 tiene un valor de 60. Nos movemos a la celda #2 (>), la incrementamos 5 veces para tener un valor de 65 y luego imprimimos el valor de la celda #2 (.). 65 es 'A' en ASCII así que la letra 'A' se imprime. , [ > + < - ] > . Este programa lee un caracter del input y lo copia en la celda #2 (,). Después empieza un ciclo. Nos movemos a la celda #2 (>) e incrementamos su valor (+). Regresamos a la celda #1 y decrementamos su valor en 1 (-). Esto continúa hasta que la celda #1 contenga un cero. Cuando #1 contenga un cero la celda #2 tendrá el valor inicial de #1. Como este ciclo siempre terminara en la celda #1 nos movemos a la celda #2 e imprimimos (.). Ten en cuenta que los espacios son sólo para fines de legibilidad. Es lo mismo escribir el ejemplo de arriba que esto: ,[>+<-]>. Intenta descrifrar lo que hace este programa: ,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> Este programa toma dos números como input y los multiplica. Primero recibe dos números del usuario. Luego empieza el ciclo externo, condicionado en la celda #1. Luego se mueve a la celda #2, comenzando el ciclo interno condicionado en la celda #2 incrementando la celda #3. Sin embargo viene un problema: El ciclo interior no funcionará nuevamente hasta la próxima vez. Para resolver este problema también incrementamos la celda #4 y luego copiamos la celda #4 a la celda #2. La celda #3 contiene el resultado. ``` Y eso es brainfuck. No es tan difícil, ¿verdad? Como diversión, puedes escribir tu propio intérprete de brainfuck o tu propio programa en brainfuck. El intérprete es relativamente sencillo de hacer, pero si eres masoquista, puedes intentar construir tu propio intérprete de brainfuck... en brainfuck. ================================================ FILE: es/c++.md ================================================ --- contributors: - ["Steven Basart", "http://github.com/xksteven"] - ["Matt Kline", "https://github.com/mrkline"] - ["Geoff Liu", "http://geoffliu.me"] - ["Connor Waters", "http://github.com/connorwaters"] translators: - ["Gerson Lázaro", "https://gersonlazaro.com"] - ["Diego Ramirez", "https://DiddiLeija.github.io"] --- C++ es un lenguaje de programación de sistemas que, [de acuerdo a su inventor Bjarne Stroustrup](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote), fue diseñado para - ser un "mejor C" - soportar abstracción de datos - soportar programación orientada a objetos - soportar programación genérica Aunque su sintaxis puede ser más difícil o compleja que los nuevos lenguajes, es ampliamente utilizado, ya que compila instrucciones nativas que pueden ser directamente ejecutadas por el procesador y ofrece un estricto control sobre el hardware (como C), mientras ofrece características de alto nivel como genericidad, excepciones, y clases. Esta combinación de velocidad y funcionalidad hace de C ++ uno de los lenguajes de programación más utilizados. ```c++ //////////////////// // Comparación con C //////////////////// // C ++ es _casi_ un superconjunto de C y comparte su sintaxis básica para las // declaraciones de variables, tipos primitivos y funciones. // Al igual que en C, el punto de entrada de tu programa es una función llamada // main con un retorno de tipo entero. // Este valor sirve como código de salida del programa. // Mira http://en.wikipedia.org/wiki/Exit_status para mayor información. int main(int argc, char** argv) { // Los argumentos de la línea de comandos se pasan por argc y argv de la // misma manera que en C. // argc indica el número de argumentos, // y argv es un arreglo de strings de estilo C (char*) // representando los argumentos. // El primer argumento es el nombre con el que el programa es llamado. // argc y argv pueden omitirse si no te preocupan los argumentos, // dejando la definición de la función como int main () // Un estado de salida 0 indica éxito. return 0; } // Sin embargo, C ++ varía en algunas de las siguientes maneras: // En C++, los caracteres literales son caracteres sizeof('c') == sizeof(char) == 1 // En C, los caracteres literales son enteros sizeof('c') == sizeof(int) // C++ tiene prototipado estricto void func(); // función que no acepta argumentos // En C void func(); // función que puede aceptar cualquier número de argumentos // Use nullptr en lugar de NULL en C++ int* ip = nullptr; // Las cabeceras (headers) estándar de C están disponibles en C ++, // pero tienen el prefijo "c" y no tienen sufijo .h. #include int main() { printf("Hola mundo!\n"); return 0; } ////////////////////////// // Sobrecarga de funciones ////////////////////////// // C++ soporta sobrecarga de funciones // siempre que cada función tenga diferentes parámetros. void print(char const* myString) { printf("String %s\n", myString); } void print(int myInt) { printf("Mi entero es %d", myInt); } int main() { print("Hello"); // Corresponde a void print(const char*) print(15); // Corresponde a void print(int) } //////////////////////////////////// // Argumentos de función por defecto //////////////////////////////////// // Puedes proporcionar argumentos por defecto para una función si no son // proporcionados por quien la llama. void doSomethingWithInts(int a = 1, int b = 4) { // Hacer algo con los enteros aquí } int main() { doSomethingWithInts(); // a = 1, b = 4 doSomethingWithInts(20); // a = 20, b = 4 doSomethingWithInts(20, 5); // a = 20, b = 5 } // Los argumentos predeterminados deben estar al final de la lista de argumentos. void invalidDeclaration(int a = 1, int b) // Error! { } ///////////////////// // Espacios de nombre ///////////////////// // Los espacios de nombres proporcionan ámbitos separados para variable, función y // otras declaraciones. // Los espacios de nombres se pueden anidar. namespace First { namespace Nested { void foo() { printf("Esto es First::Nested::foo\n"); } } // fin del nombre de espacio Nested } // fin del nombre de espacio First namespace Second { void foo() { printf("Esto es Second::foo\n") } } void foo() { printf("Este es global: foo\n"); } int main() { // Incluye todos los símbolos del espacio de nombre Second en el ámbito // actual. Tenga en cuenta que simplemente foo() no funciona, ya que ahora // es ambigua si estamos llamando a foo en espacio de nombres Second o en // el nivel superior. using namespace Second; Second::foo(); // imprime "Esto es Second::foo" First::Nested::foo(); // imprime "Esto es First::Nested::foo" ::foo(); // imprime "Este es global: foo" } ///////////////// // Entrada/Salida ///////////////// // La entrada y salida de C++ utiliza flujos (streams) // cin, cout, y cerr representan a stdin, stdout, y stderr. // << es el operador de inserción >> es el operador de extracción. #include // Incluir para el flujo de entrada/salida using namespace std; // Los streams estan en el espacio de nombre std (libreria estandar) int main() { int myInt; // Imprime a la stdout (o terminal/pantalla) cout << "Ingresa tu número favorito:\n"; // Toma una entrada cin >> myInt; // cout puede también ser formateado cout << "Tu número favorito es " << myInt << "\n"; // imprime "Tu número favorito es " cerr << "Usado para mensajes de error"; } //////////////////// // Cadenas (Strings) //////////////////// // Las cadenas en C++ son objetos y tienen muchas funciones #include using namespace std; // Las cadenas también estan en el nombre de espacio std string myString = "Hola"; string myOtherString = " Mundo"; // + es usado para concatenar. cout << myString + myOtherString; // "Hola Mundo" cout << myString + " Tu"; // "Hola Tu" // Las cadenas en C++ son mutables y tienen valor semántico. myString.append(" Perro"); cout << myString; // "Hola Perro" ////////////// // Referencias ////////////// // Además de punteros como los de C, // C++ tiene _references_. // Estos tipos de puntero no pueden ser reasignados una vez establecidos // Y no pueden ser nulos. // También tienen la misma sintaxis que la propia variable: // No es necesaria * para eliminar la referencia y // & (dirección) no se utiliza para la asignación. using namespace std; string foo = "Yo soy foo"; string bar = "Yo soy bar"; string& fooRef = foo; // Crea una referencia a foo. fooRef += ". Hola!"; // Modifica foo través de la referencia cout << fooRef; // Imprime "Yo soy foo. Hola!" // No trate de reasignar "fooRef". Esto es lo mismo que "foo = bar", y // foo == "Yo soy bar" // después de esta linea. fooRef = bar; const string& barRef = bar; // Crea una referencia constante a bar. // Como en C, los valores constantes (y punteros y referencias) no pueden ser // modificados. barRef += ". Hola!"; // Error, una referencia constante no puede ser modificada. // Sidetrack: Antes de hablar más sobre referencias, hay que introducir un // concepto llamado objeto temporal. Supongamos que tenemos el siguiente código: string tempObjectFun() { ... } string retVal = tempObjectFun(); // Lo que pasa en la segunda línea es en realidad: // - Un objeto de cadena es retornado desde tempObjectFun // - Una nueva cadena se construye con el objeto devuelto como argumento al // constructor // - El objeto devuelto es destruido // El objeto devuelto se llama objeto temporal. Los objetos temporales son // creados cada vez que una función devuelve un objeto, y es destruido en el // fin de la evaluación de la expresión que encierra (Bueno, esto es lo que la // norma dice, pero los compiladores están autorizados a cambiar este // comportamiento. Busca "return value optimization" para ver mas detalles). // Así que en este código: foo(bar(tempObjectFun())) // Suponiendo que foo y bar existen, el objeto retornado de tempObjectFun es // pasado al bar, y se destruye antes de llamar foo. // Ahora, de vuelta a las referencias. La excepción a la regla "en el extremo // de la expresión encerrada" es si un objeto temporal se une a una // referencia constante, en cuyo caso su vida se extiende al ámbito actual: void constReferenceTempObjectFun() { // ConstRef obtiene el objeto temporal, y es válido hasta el final de esta // función. const string& constRef = tempObjectFun(); ... } // Otro tipo de referencia introducida en C ++ 11 es específicamente para // objetos temporales. No se puede tener una variable de este tipo, pero tiene // prioridad en resolución de sobrecarga: void someFun(string& s) { ... } // Referencia regular void someFun(string&& s) { ... } // Referencia a objeto temporal string foo; someFun(foo); // Llama la función con referencia regular someFun(tempObjectFun()); // Llama la función con referencia temporal // Por ejemplo, puedes ver estas dos versiones de constructores para // std::basic_string: basic_string(const basic_string& other); basic_string(basic_string&& other); // La idea es que si estamos construyendo una nueva cadena de un objeto temporal // (que va a ser destruido pronto de todos modos), podemos tener un constructor // mas eficiente que "rescata" partes de esa cadena temporal. Usted verá este // concepto denominado "movimiento semántico". //////////////////////////////////////////// // Clases y programación orientada a objetos //////////////////////////////////////////// // Primer ejemplo de clases #include // Declara una clase. // Las clases son usualmente declaradas en archivos de cabeceras (.h o .hpp) class Dog { // Variables y funciones de la clase son privados por defecto. std::string name; int weight; // Todos los miembros siguientes de este son públicos // hasta que se encuentre "private" o "protected". public: // Constructor por defecto Dog(); // Declaraciones de funciones de la clase (implementaciones a seguir) // Nota que usamos std::string aquí en lugar de colocar // using namespace std; // arriba. // Nunca ponga una declaración "using namespace" en un encabezado. void setName(const std::string& dogsName); void setWeight(int dogsWeight); // Funciones que no modifican el estado del objeto // deben marcarse como const. // Esto le permite llamarlas si se envía una referencia constante al objeto. // También tenga en cuenta que las funciones deben ser declaradas // explícitamente como _virtual_ para que sea reemplazada en las clases // derivadas. // Las funciones no son virtuales por defecto por razones de rendimiento. virtual void print() const; // Las funciones también se pueden definir en el interior // del cuerpo de la clase. // Funciones definidas como tales están entre líneas automáticamente. void bark() const { std::cout << name << " barks!\n"; } // Junto a los constructores, C++ proporciona destructores. // Estos son llamados cuando un objeto se elimina o está fuera del ámbito. // Esto permite paradigmas potentes como RAII // (mira abajo) // El destructor debe ser virtual si una clase es dervada desde el; // Si no es virtual, entonces la clase destructora derivada // no será llamada si el objeto se destruye a través de una referencia de // la clase base o puntero. virtual ~Dog(); }; // Un punto y coma debe seguir la definición de clase. // Las funciones de una clase son normalmente implementados en archivos .cpp. Dog::Dog() { std::cout << "Un perro ha sido construido\n"; } // Objetos (tales como cadenas) deben ser pasados por referencia // si los estás modificando, o referencia constante en caso contrario. void Dog::setName(const std::string& dogsName) { name = dogsName; } void Dog::setWeight(int dogsWeight) { weight = dogsWeight; } // Nota que "virtual" sólo se necesita en la declaración, no en la definición. void Dog::print() const { std::cout << "El perro es " << name << " y pesa " << weight << "kg\n"; } Dog::~Dog() { std::cout << "Adiós " << name << "\n"; } int main() { Dog myDog; // imprime "Un perro ha sido construido" myDog.setName("Barkley"); myDog.setWeight(10); myDog.print(); // imprime "El perro es Barkley y pesa 10 kg" return 0; } // imprime "Adiós Barkley" // Herencia: // Esta clase hereda todo lo público y protegido de la clase Dog class OwnedDog : public Dog { void setOwner(const std::string& dogsOwner); // Reemplaza el comportamiento de la función de impresión // de todos los OwnedDogs. Mira // http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping // para una introducción más general si no está familiarizado con el // polimorfismo de subtipo. // La palabra clave override es opcional, pero asegúrate de que estás // reemplazando el método de una clase base. void print() const override; private: std::string owner; }; // Mientras tanto, en el archivo .cpp correspondiente: void OwnedDog::setOwner(const std::string& dogsOwner) { owner = dogsOwner; } void OwnedDog::print() const { Dog::print(); // Llama a la función de impresión en la clase base Dog std::cout << "El perro es de " << owner << "\n"; // Imprime "El perro es y pesa " // "El perro es de " } //////////////////////////////////////////// // Inicialización y sobrecarga de operadores //////////////////////////////////////////// // En C ++ se puede sobrecargar el comportamiento // de los operadores como +, -, *, /, etc. // Esto se hace mediante la definición de una función que es llamada // cada vez que se utiliza el operador. #include using namespace std; class Point { public: // Las variables de la clase pueden dar valores por defecto de esta manera. double x = 0; double y = 0; // Define un constructor por defecto que no hace nada // pero inicializa el punto al valor por defecto (0, 0) Point() { }; // La siguiente sintaxis se conoce como lista de inicialización // y es la forma correcta de inicializar los valores de los miembros de la clase Point (double a, double b) : x(a), y(b) { /* No hace nada excepto inicializar los valores */ } // Sobrecarga el operador + Point operator+(const Point& rhs) const; // Sobrecarga el operador += Point& operator+=(const Point& rhs); // También tendría sentido añadir los operadores - y -=, // pero vamos a omitirlos por razones de brevedad. }; Point Point::operator+(const Point& rhs) const { // Crea un nuevo punto que es la suma de este y rhs. return Point(x + rhs.x, y + rhs.y); } Point& Point::operator+=(const Point& rhs) { x += rhs.x; y += rhs.y; return *this; } int main () { Point up (0,1); Point right (1,0); // Llama al operador + de Point // Point llama la función + con right como parámetro Point result = up + right; // Imprime "Result is upright (1,1)" cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; return 0; } ///////////////////////// // Plantillas (Templates) ///////////////////////// // Las plantillas en C++ se utilizan sobre todo en la programación genérica, // a pesar de que son mucho más poderoso que los constructores genéricos // en otros lenguajes. Ellos también soportan especialización explícita y // parcial y clases de tipo estilo funcional; de hecho, son un lenguaje // funcional Turing-completo incrustado en C ++! // Empezamos con el tipo de programación genérica que podría estar // familiarizado. // Para definir una clase o función que toma un parámetro de tipo: template class Box { public: // En este caso, T puede ser usado como cualquier otro tipo. void insert(const T&) { ... } }; // Durante la compilación, el compilador realmente genera copias de cada // plantilla con parámetros sustituidos, por lo que la definición completa // de la clase debe estar presente en cada invocación. // Es por esto que usted verá clases de plantilla definidas // enteramente en archivos de cabecera. //Para crear una instancia de una clase de plantilla en la pila: Box intBox; y puedes utilizarlo como era de esperar: intBox.insert(123); // Puedes, por supuesto, anidar plantillas: Box > boxOfBox; boxOfBox.insert(intBox); // Hasta C++11, había que colocar un espacio entre los dos '>'s, // de lo contrario '>>' serían analizados como el operador de desplazamiento // a la derecha. // A veces verás // template // en su lugar. La palabra clave "class" y la palabra clave "typename" son // mayormente intercambiables en este caso. Para la explicación completa, mira // http://en.wikipedia.org/wiki/Typename // (sí, esa palabra clave tiene su propia página de Wikipedia). // Del mismo modo, una plantilla de función: template void barkThreeTimes(const T& input) { input.bark(); input.bark(); input.bark(); } // Observe que no se especifica nada acerca de los tipos de parámetros aquí. // El compilador generará y comprobará cada invocación de la plantilla, // por lo que la función anterior funciona con cualquier tipo "T" // que tenga un método 'bark' constante! Dog fluffy; fluffy.setName("Fluffy") barkThreeTimes(fluffy); // Imprime "Fluffy barks" 3 veces. // Los parámetros de la plantilla no tienen que ser las clases: template void printMessage() { cout << "Aprende C++ en " << Y << " minutos!" << endl; } // Y usted puede especializar explícitamente plantillas // para código más eficiente. // Por supuesto, la mayor parte del mundo real que utiliza una especialización // no son tan triviales como esta. // Tenga en cuenta que usted todavía tiene que declarar la función (o clase) // como plantilla incluso si ha especificado de forma explícita todos // los parámetros. template<> void printMessage<10>() { cout << "Aprende C++ rapido en solo 10 minutos!" << endl; } printMessage<20>(); // Prints "Aprende C++ en 20 minutos!" printMessage<10>(); // Prints "Aprende C++ rapido en solo 10 minutos!" ///////////////////// // Manejador de excepciones ///////////////////// // La biblioteca estándar proporciona algunos tipos de excepción // (mira http://en.cppreference.com/w/cpp/error/exception) // pero cualquier tipo puede ser lanzado como una excepción #include #include //Todas las excepciones lanzadas dentro del bloque _try_ pueden ser // capturados por los siguientes manejadores _catch_. try { // No asigne excepciones en el heap usando _new_. throw std::runtime_error("Ocurrió un problema"); } // Captura excepciones por referencia const si son objetos catch (const std::exception& ex) { std::cout << ex.what(); } ******************************************************************************** // Captura cualquier excepción no capturada por bloques _catch_ anteriores catch (...) { std::cout << "Excepción desconocida capturada"; throw; // Re-lanza la excepción } /////// // RAII /////// // RAII significa "Resource Acquisition Is Initialization" // (Adquisición de recursos es inicialización). // A menudo se considera el paradigma más poderoso en C++ // Y el concepto es simple: un constructor de un objeto // adquiere recursos de ese objeto y el destructor les libera. // Para entender cómo esto es útil, // considere una función que utiliza un identificador de archivo C: void doSomethingWithAFile(const char* filename) { // Para empezar, asuma que nada puede fallar. FILE* fh = fopen(filename, "r"); // Abre el archivo en modo lectura doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); fclose(fh); // Cierra el manejador de archivos } // Por desgracia, las cosas se complican rápidamente por el control de errores. // Supongamos que fopen puede fallar, y que doSomethingWithTheFile y // DoSomethingElseWithIt retornan códigos de error si fallan. // (Excepciones son la mejor forma de manejar los fallos, // pero algunos programadores, especialmente los que tienen un fondo C, // estan en desacuerdo sobre la utilidad de las excepciones). // Ahora tenemos que comprobar cada llamado por fallos y cerrar el manejador // del archivo si se ha producido un problema. bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Abre el archivo en modo lectura if (fh == nullptr) // El puntero retornado es nulo o falla. return false; // Reporta el fallo a quien hizo el llamado. // Asume que cada función retorna falso si falla if (!doSomethingWithTheFile(fh)) { fclose(fh); // Cierre el manejador de archivo para que no se filtre. return false; // Propaga el error. } if (!doSomethingElseWithIt(fh)) { fclose(fh); // Cierre el manejador de archivo para que no se filtre. return false; // Propaga el error. } fclose(fh); // Cierre el archivo. return true; // Indica que todo funcionó correctamente. } // Programadores C suelen limpiar esto un poco usando goto: bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); if (fh == nullptr) return false; if (!doSomethingWithTheFile(fh)) goto failure; if (!doSomethingElseWithIt(fh)) goto failure; fclose(fh); // Cierre el archivo. return true; // Indica que todo funcionó correctamente. failure: fclose(fh); return false; // Propaga el error } // Si las funciones indican errores mediante excepciones, // las cosas son un poco más claras, pero pueden optimizarse más. void doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Abrir el archivo en modo lectura if (fh == nullptr) throw std::runtime_error("No puede abrirse el archivo."); try { doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } catch (...) { fclose(fh); // Asegúrese de cerrar el archivo si se produce un error. throw; // Luego vuelve a lanzar la excepción. } fclose(fh); // Cierra el archivo } // Compare esto con el uso de la clase de flujo de archivos de C++ (fstream) // fstream utiliza su destructor para cerrar el archivo. // Los destructores son llamados automáticamente // cuando un objeto queda fuera del ámbito. void doSomethingWithAFile(const std::string& filename) { // ifstream es la abreviatura de el input file stream std::ifstream fh(filename); // Abre el archivo // Hacer algo con el archivo doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } // El archivo se cierra automáticamente aquí por el destructor // Esto tiene ventajas _enormes_: // 1. No importa lo que pase, // el recurso (en este caso el manejador de archivo) será limpiado. // Una vez que escribes el destructor correctamente, // es _imposible_ olvidar cerrar el identificador y permitir // fugas del recurso. // 2. Tenga en cuenta que el código es mucho más limpio. // El destructor se encarga de cerrar el archivo detrás de cámaras // Sin que tenga que preocuparse por ello. // 3. El código es seguro. // Una excepción puede ser lanzado en cualquier lugar de la función // y la limpieza ocurrirá. // Todo el código idiomático C++ utiliza RAII ampliamente para todos los // recursos. // Otros ejemplos incluyen // - Memoria usando unique_ptr y shared_ptr // - Contenedores (Containers) - la biblioteca estándar linked list, // vector (es decir, array con auto-cambio de tamaño), hash maps, etc. // Destruimos todos sus contenidos de forma automática // cuando quedan fuera del ámbito. // - Mutex utilizando lock_guard y unique_lock ///////////////////// // Cosas divertidas ///////////////////// // Aspectos de C ++ que pueden sorprender a los recién llegados // (e incluso algunos veteranos). // Esta sección es, por desgracia, salvajemente incompleta; // C++ es uno de los lenguajes con los que mas facil te disparas en el pie. // Tu puedes sobreescribir métodos privados! class Foo { virtual void bar(); }; class FooSub : public Foo { virtual void bar(); // Sobreescribe Foo::bar! }; // 0 == false == NULL (La mayoria de las veces)! bool* pt = new bool; *pt = 0; // Establece los puntos de valor de 'pt' en falso. pt = 0; // Establece 'pt' al apuntador nulo. Ambas lineas compilan sin error. // nullptr se supone que arregla un poco de ese tema: int* pt2 = new int; *pt2 = nullptr; // No compila pt2 = nullptr; // Establece pt2 como null. // Hay una excepción para los valores bool. // Esto es para permitir poner a prueba punteros nulos con if (!ptr), // pero como consecuencia se puede asignar nullptr a un bool directamente! *pt = nullptr; // Esto todavía compila, a pesar de que '*pt' es un bool! // '=' != '=' != '='! // Llama Foo::Foo(const Foo&) o alguna variante (mira movimientos semanticos) // copia del constructor. Foo f2; Foo f1 = f2; // Llama Foo::Foo(const Foo&) o variante, pero solo copia el 'Foo' parte de // 'fooSub'. Cualquier miembro extra de 'fooSub' se descarta. Este // comportamiento horrible se llama "Corte de objetos." FooSub fooSub; Foo f1 = fooSub; // Llama a Foo::operator=(Foo&) o variantes. Foo f1; f1 = f2; // Cómo borrar realmente un contenedor: class Foo { ... }; vector v; for (int i = 0; i < 10; ++i) v.push_back(Foo()); // La siguiente línea establece el tamaño de v en 0, // pero los destructores no son llamados y los recursos no se liberan! v.empty(); v.push_back(Foo()); // Nuevo valor se copia en el primer Foo que insertamos // En verdad destruye todos los valores en v. // Consulta la sección acerca de los objetos temporales para la // explicación de por qué esto funciona. v.swap(vector()); ``` Otras lecturas: * Una referencia del lenguaje hasta a la fecha se puede encontrar en [CPP Reference](http://cppreference.com/w/cpp). * Recursos adicionales se pueden encontrar en [[CPlusPlus]](http://cplusplus.com). * Un tutorial que cubre los conceptos básicos del lenguaje y la configuración del entorno de codificación está disponible en [TheChernoProject - C ++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FF). ================================================ FILE: es/c.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] translators: - ["Francisco García", "http://flaskbreaker.tumblr.com/"] - ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"] --- ¡Ah!, C. Aun hoy en día sigue siendo el lenguaje por excelencia de la computación moderna de alto rendimiento. C es el lenguaje de más bajo nivel que la mayoría de los programadores llegarán a usar, pero lo compensa de sobra con pura velocidad. Solo ten en cuenta el manejo manual de memoria y te llevará tan lejos como necesites. ```c // Los comentarios de una sola línea comienzan con // /* Los comentarios multilínea tienen este aspecto. */ // Importa cabeceras con #include #include #include #include // Declara por adelantado las armaduras de las funciones en un archivo .h, // o al principio de tu archivo .c . void function_1(); void function_2(); // El punto de entrada de tu programa es una función llamada main con // retorno de tipo entero (integer). int main() { // Muestra la salida usando printf, para el "formato print" // %d es un entero, \n es una nueva línea printf("%d\n", 0); // => Muestra 0 // Todas las sentencias deben terminar con un punto y coma. /////////////////////////////////////// // Tipos /////////////////////////////////////// // Tienes que declarar una variable antes de usarla. La declaración de una // variable necesites que especifiques su tipo; el tipo de una variable // determina su tamaño en bytes. // 'ints' (enteros) son normalmente de 4 bytes int x_int = 0; // 'shorts' son normalmente de 2 bytes short x_short = 0; // 'chars' son fijo de 1 byte char x_char = 0; char y_char = 'y'; // Los caracteres literales se entrecomillan con '' // 'longs' son a menudo de 4 a 8 bytes; 'long longs' son fijo de por lo // menos 64 bits long x_long = 0; long long x_long_long = 0; // 'floats' son normalmente números de coma flotante de 32 bits float x_float = 0.0; // 'doubles' son normalmente números de coma flotante de 64 bits double x_double = 0.0; // Todos los tipos enteros pueden ser 'unsigned'. Esto significa que no // pueden ser negativos, pero el valor máximo de una variable 'unsigned' // es mayor que el de una no 'unsigned' del mismo tamaño. unsigned char ux_char; unsigned short ux_short; unsigned int ux_int; unsigned long long ux_long_long; // Todos menos 'char', que es siempre de 1 byte, varían el tamaño // dependiendo de tu máquina. sizeof(T) te dice el tamaño de una variable // de tipo T en bytes por lo que podemos expresar el tamaño de estos tipos // portatilmente. // Por ejemplo, printf("%lu\n", sizeof(int)); // => 4 (en máquinas con 'words' de 4 bytes) // Los arrays deben ser inicializados con un tamaño concreto. char my_char_array[20]; // Este array ocupa 1 * 20 = 20 bytes int my_int_array[20]; // Este array ocupa 4 * 20 = 80 bytes // (suponiendo que tenemos 'words' de 4-byte) // Puedes inicializar un array a 0 así: char my_array[20] = {0}; // Indexar un array es como en otros lenguajes -o, más bien, otros // lenguajes son como C- my_array[0]; // => 0 // Los arrays varían; ¡son sólo memoria! my_array[1] = 2; printf("%d\n", my_array[1]); // => 2 // Las cadenas (strings) son sólo arrays de 'chars' (caracteres) // terminados en un byte NUL (0x00), representado en las cadenas como el // carácter especial '\0'. // (No tenemos porqué añadir el byte nulo en cadenas literales; el // compilador lo añade al final por nosotros.) char a_string[20] = "Esto es una cadena"; printf("%s\n", a_string); // %s se sutituye por una cadena. /* Te habrás dado cuenta de que a_string es solo de 18 caracteres. El 'char' #19 es el byte nulo. El 'char' #20 es de valor indefinido. */ printf("%d\n", a_string[18]); // => 0 /////////////////////////////////////// // Operadores /////////////////////////////////////// int i1 = 1, i2 = 2; // Forma corta de declaración múltiple float f1 = 1.0, f2 = 2.0; // La aritmética es sencilla i1 + i2; // => 3 i2 - i1; // => 1 i2 * i1; // => 2 i1 / i2; // => 0 (0.5, pero es truncado tras el 0) f1 / f2; // => 0.5, más o menos épsilon // Módulo está también 11 % 3; // => 2 // Los operadores de comparación te resultaran familiares, pero no hay // booleanos en C. Usamos enteros (ints) en su lugar. 0 es falso, // cualquier otra cosa es verdadero. (Los operadores de comparación // siempre devuelven 0 o 1) 3 == 2; // => 0 (Falso) 3 != 2; // => 1 (Verdadero) 3 > 2; // => 1 3 < 2; // => 0 2 <= 2; // => 1 2 >= 2; // => 1 // La lógica funiona en enteros !3; // => 0 (not lógico) !0; // => 1 1 && 1; // => 1 (and lógico) 0 && 1; // => 0 0 || 1; // => 1 (or lógico) 0 || 0; // => 0 // ¡Operadores de bits! ~0x0F; // => 0xF0 (Negación) 0x0F & 0xF0; // => 0x00 (AND) 0x0F | 0xF0; // => 0xFF (OR) 0x04 ^ 0x0F; // => 0x0B (XOR) 0x01 << 1; // => 0x02 (desplazar hacia la izquierda (por 1)) 0x02 >> 1; // => 0x01 (desplazar hacia la derecha (por 1)) /////////////////////////////////////// // Estructuras de Control /////////////////////////////////////// if (0) { printf("Yo nunca ocurro\n"); } else if (0) { printf("Yo tampoco ocurro nunca\n"); } else { printf("Yo me muestro\n"); } // Mientras el bucle exista int ii = 0; while (ii < 10) { printf("%d, ", ii++); // ii++ incrementa ii en uno, después de usar su valor. } // => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); int kk = 0; do { printf("%d, ", kk); } while (++kk < 10); // ++kk incrementa kk en uno, antes de usar su valor. // => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // Bucles 'for' también int jj; for (jj=0; jj < 10; jj++) { printf("%d, ", jj); } // => muestra "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); /////////////////////////////////////// // Cambios de Tipo /////////////////////////////////////// // Cada valor en C tiene un tipo, pero tu puedes ingresar un valor en // otro tipo si quieres. int x_hex = 0x01; // Puedes asignar hexadecimales a variables // El cambio de tipos intentará mantener sus valores numéricos printf("%d\n", x_hex); // => Muestra 1 printf("%d\n", (short) x_hex); // => Muestra 1 printf("%d\n", (char) x_hex); // => Muestra 1 // Los tipos se desbordan sin aviso printf("%d\n", (char) 257); // => 1 (El valor máximo de un 'char' es 255) // Los tipos enteros puden cambiarse a tipos de coma flotante, y viceversa printf("%f\n", (float)100); // %f se sustituye por un 'float' printf("%lf\n", (double)100); // %lf se sustituye por un 'double' printf("%d\n", (char)100.0); /////////////////////////////////////// // Punteros /////////////////////////////////////// // Un puntero es una variable declarada para almacenar una dirección de // memoria. Su declaración además nos dirá el tipo de dato al que apunta. // Puedes obtener la dirección de memoria de tus variables, y después // enlazarlas con ellos. int x = 0; printf("%p\n", &x); // Usa & para obtener la dirección de una variable. // (%p se sustituye por un puntero) // => Muestra alguna dirección de memoria; // Los tipos de puntero terminan con * en su declaración int* px; // px es un puntero a un 'int' px = &x; // Almacena la dirección de x en px printf("%p\n", px); // => Muestra alguna dirección de memoria // Para obtener el valor de la dirección a la que apunta un puntero, pon // * delante para desreferenciarle. printf("%d\n", *px); // => Muestra 0, el valor de x y de la dirección a la // que apunta px // También puedes cambiar el valor al que está apuntando el puntero. // Tenemos que meter la desreferencia entre paréntesis porque ++ tiene // prioridad frente a *. (*px)++; // Incrementa el valor al que apunta px en 1 printf("%d\n", *px); // => Muestra 1 printf("%d\n", x); // => Muestra 1 int x_array[20]; // Los arrays son una buena manera de distribuir bloques int xx; // continuos de memoria. for (xx=0; xx<20; xx++) { x_array[xx] = 20 - xx; } // Inicializa x_array a 20, 19, 18,... 2, 1 // Declara un puntero de tipo 'int' y lo inicializa para apuntar a x_array int* x_ptr = x_array; // x_ptr ahira apunta al primer elemento del 'array' (el entero 20). // Esto funciona porque las 'arrays' actualmente son solo punteros a su // primer elemento. // Los 'arrays' son punteros a su primer elemento. printf("%d\n", *(x_ptr)); // => Muestra 20 printf("%d\n", x_array[0]); // => Muestra 20 // Los punteros aumentan y disminuyen en función de su tipo. printf("%d\n", *(x_ptr + 1)); // => Muestra 19 printf("%d\n", x_array[1]); // => Muestra 19 // Puedes también asigner dinamicamente bloques contiguos de memoria con // la función malloc de la librería estándard, que toma un entero como // argumento representando el número de bytes a asignar de la pila. int* my_ptr = (int*) malloc(sizeof(int) * 20); for (xx=0; xx<20; xx++) { *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx funcionaría también aquí } // Inicializa la memoria a 20, 19, 18, 17... 2, 1 (como 'ints') // Desreferenciando la memoria que no has asignado te dará resultados // impredecibles printf("%d\n", *(my_ptr + 21)); // => Prints who-knows-what? // Cuando hayas acabado con el bloque de memoría malloc, necesitas // liberarlo o sino nadie más podrá usarlo hasta que tu programa se cierre free(my_ptr); // Las cadenas pueden ser 'arrays' de chars, pero normalmente se // representan con punteros 'char': char* my_str = "This is my very own string"; printf("%c\n", *my_str); // => 'T' function_1(); } // fin de la función main /////////////////////////////////////// // Funciones /////////////////////////////////////// // Sintexis de la declaración de funciones: // () int add_two_ints(int x1, int x2){ return x1 + x2; // Usa 'return' para dar una salida } /* Las funciones son de paso por valor, pero puedes hacer tus propias referencias con punteros de manera que las funciones puedan cambiar sus valores. Ejemplo: invertidor de cadenas in-situ */ // Una función 'void' no retorna valor void str_reverse(char* str_in){ char tmp; int ii=0, len = strlen(str_in); // Strlen es parte de la librería for(ii=0; ii ".abeurp anu se otsE" */ /////////////////////////////////////// // Definición de tipos y estructuras /////////////////////////////////////// // Los 'Typedefs' pueden ser utilizados para crear alias de tipos. typedef int my_type; my_type my_type_var = 0; // Las estructuras son sólo grupos de datos. struct rectangle { int width; int height; }; void function_1(){ struct rectangle my_rec; // Utiliza los miembros de una estructura con . my_rec.width = 10; my_rec.height = 20; // Puedes declarar punteros a estructuras struct rectangle* my_rec_ptr = &my_rec; // Usa la desreferencia para modificar sus miembros... (*my_rec_ptr).width = 30; // ... o usa la abreviatura -> my_rec_ptr->height = 10; // Lo mismo que (*my_rec_ptr).height = 10; } // Puedes aplicar un 'typedef' a una estructura por conveniencía. typedef struct rectangle rect; int area(rect r){ return r.width * r.height; } /////////////////////////////////////// // Punteros a Funciones /////////////////////////////////////// /* En tiempo de ejecución, las funciones se localizan en unas direcciones de memoria concretas. Los punteros a funciones son como cualquier otro puntero (almacenan una dirección de memoria), pero pueden ser usados para utilizar funciones directamente, o para pasar 'handlers' (o funciones 'callback') por todos lados. Sin embargo, la sintaxis de definición parecera confusa al principio. Ejemplo: usar str_reverse desde un puntero */ void str_reverse_through_pointer(char * str_in) { // Define un puntero a una función, llamado f. void (*f)(char *); // La armadura debe coincidir exactamente con al función objetivo. // Assigna la dirección de la función (determinado en tiempo de ejecuión) f = &str_reverse; // Llamando la función desde el puntero (*f)(str_in); // Esta es una alternativa para llamarla pero con una sintaxis igual de válida. // f(str_in); } /* Tanto tiempo como las armaduras de las funciones coincidan, podrás asignar cualquier función al mismo puntero. Los punteros a funciones son normalmente envueltos en 'typedef' para simplificar su legibilidad, como sigue: */ typedef void (*my_fnp_type)(char *); // Es usado para declarar la variable puntero actual: // ... // my_fnp_type f; ``` ## Otras lecturas Lo mejor que puedes encontrar es una copia de [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language). Es *el* libro de C, escrito por Dennis Ritchie, creador de C y Brian Kernighan. Aún así, se cuidadoso, es antiguo, contiene algunas inexactitudes, y algunas prácticas han cambiado. Si tienes una pregunta, lee [compl.lang.c Frequently Asked Questions](http://c-faq.com). Es muy importante utilizar el espaciado y la sangría apropiados y ser coherente con su estilo de codificación en general. El código legible es mejor que el código rápido. Para adoptar un buen estilo de codificación, vea el [estilo de codificación del kernel Linux](https://www.kernel.org/doc/Documentation/CodingStyle). ================================================ FILE: es/chapel.md ================================================ --- contributors: - ["Ian J. Bertolacci", "https://www.cs.arizona.edu/~ianbertolacci/"] - ["Ben Harshbarger", "https://github.com/benharsh/"] translators: - ["Ivan Alburquerque", "https://github.com/AlburIvan"] --- Puede leer todo sobre Chapel en [el sitio web oficial de Chapel de Cray](https://chapel-lang.org). En resumen, Chapel es un lenguaje de programación paralela, código abierto, de alta productividad desarrolladp en Cray Inc. y está diseñado para ejecutarse en PC multi-nucleos, así como en supercomputadoras multi-kilocore. Puede encontrar más información y asistencia al final de este documento. ```chapel // Los comentarios son de estilo de la familia C // comentario de una línea /* comentario de múltiples lineas */ // Impresión básica write("Hola, "); writeln("Mundo!"); // write y writeln pueden tomar una lista de cosas para imprimir. // Cada cosa está impresa justo al lado de las demás, ¡así que incluye espacios! writeln("hay ", 3, " comas (\",\") en esta línea de código"); // Diferentes canales de salida: stdout.writeln("Esto va a la salida estándar, al igual que lo hace writeln()"); stderr.writeln("Esto va al error estándar"); // Las variables no tienen que escribirse explícitamente // mientras el compilador pueda determinar el tipo que contendrá. // 10 es un entero, asi que myVar es explícitamente un entero var myVar = 10; myVar = -10; var mySecondVar = myVar; // var anError; sería un error en tiempo de compilación // Podemos (y debemos) escribir cosas explícitamente. var myThirdVar: real; var myFourthVar: real = -1.234; myThirdVar = myFourthVar; // Tipos // Hay varios tipos básicos. var myInt: int = -1000; // Enteros firmados var myUint: uint = 1234; // Enteros sin-firmar var myReal: real = 9.876; // Números de punto flotante var myImag: imag = 5.0i; // Números imaginarios var myCplx: complex = 10 + 9i; // Números complejos myCplx = myInt + myImag; // Otra manera de formar números complejos var myBool: bool = false; // Booleanos var myStr: string = "Una cadena..."; // Cadenas var singleQuoteStr = 'Otra cadena...'; // Cadena literal con comillas simples // Algunos tipos pueden tener tamaños. var my8Int: int(8) = 10; // Entero de 8 bit (one byte); var my64Real: real(64) = 1.516; // Real de 64 bit (8 bytes) // Conversion de tipos. var intFromReal = myReal : int; var intFromReal2: int = myReal : int; // Alias de tipo. type chroma = int; // Tipo de un solo tono type RGBColor = 3*chroma; // Tipo que representa un color completo var black: RGBColor = (0,0,0); var white: RGBColor = (255, 255, 255); // Constantes y Parámetros // una variable const es una constante y no se puede cambiar después de // establecerla en tiempo de ejecución. const almostPi: real = 22.0/7.0; // Un parámetro es una constante cuyo valor debe conocerse estáticamente // en tiempo de compilación. param compileTimeConst: int = 16; // El modificador de configuración permite establecer valores en la línea de comando. // Establece valores con --varCmdLineArg=Value o --varCmdLineArg Value en tiempo de ejecución. config var varCmdLineArg: int = -123; config const constCmdLineArg: int = 777; // config param se puede configurar en tiempo de compilación. // Establece valores con --set paramCmdLineArg=value en tiempo de compilación. config param paramCmdLineArg: bool = false; writeln(varCmdLineArg, ", ", constCmdLineArg, ", ", paramCmdLineArg); // Referencias // ref funciona de manera muy similar a una referencia en C ++. En Chapel, // no se puede hacer una referencia como alias a una variable distinta // de la variable con la que se inicializa. // Aquí, refToActual se refiere a actual. var actual = 10; ref refToActual = actual; writeln(actual, " == ", refToActual); // imprime el mismo valor actual = -123; // modificar actual (a lo que refToActual se refiere) writeln(actual, " == ", refToActual); // imprime el mismo valor refToActual = 99999999; // modificar a qué se refiere refToActual (que es actual) writeln(actual, " == ", refToActual); // imprime el mismo valor // Operadores // Operadores matemáticos: var a: int, thisInt = 1234, thatInt = 5678; a = thisInt + thatInt; // Adicción a = thisInt * thatInt; // Multiplicación a = thisInt - thatInt; // Substracción a = thisInt / thatInt; // División a = thisInt ** thatInt; // Exponenciación a = thisInt % thatInt; // residuo (módulo) // Operadores logicos: var b: bool, thisBool = false, thatBool = true; b = thisBool && thatBool; // Lógico y b = thisBool || thatBool; // Lógico o b = !thisBool; // Lógico negación // Operadores relacionales: b = thisInt > thatInt; // Mas grande que b = thisInt >= thatInt; // Mas grande o igual que b = thisInt < a && a <= thatInt; // Menor que, y, Menor o igual que b = thisInt != thatInt; // No es igual a b = thisInt == thatInt; // es igual a // Operadores bit a bit: a = thisInt << 10; // Desplazamiento de bit izquierdo por 10 bits; a = thatInt >> 5; // Desplazamiento de bit derecho por 5 bits; a = ~thisInt; // Negación bit a bit a = thisInt ^ thatInt; // bit a bit exclusivo o // Operadores de asignación compuesta: a += thisInt; // Adición-igual (a = a + thisInt;) a *= thatInt; // Multiplicación-igual (a = a * thatInt;) b &&= thatBool; // Lógico e igual (b = b && thatBool;) a <<= 3; // Desplazamiento a la izquierda igual (a = a << 10;) // A diferencia de otros lenguajes de familia C, no hay operadores de // pre / post-incremento / decremento, tales como: // // ++j, --j, j++, j-- // Operador de intercambio: var old_this = thisInt; var old_that = thatInt; thisInt <=> thatInt; // Intercambia los valores de thisInt y thatInt writeln((old_this == thatInt) && (old_that == thisInt)); // También se pueden definir sobrecargas del operador, como veremos con los procedimientos. // Tuplas // Las tuplas pueden ser del mismo tipo o de diferentes tipos. var sameTup: 2*int = (10, -1); var sameTup2 = (11, -6); var diffTup: (int,real,complex) = (5, 1.928, myCplx); var diffTupe2 = (7, 5.64, 6.0+1.5i); // Se puede acceder a las tuplas usando corchetes o paréntesis, // y están indexadas en base 1. writeln("(", sameTup[1], ",", sameTup(2), ")"); writeln(diffTup); // Las tuplas también se pueden escribir. diffTup(1) = -1; // Los valores de tupla se pueden expandir a sus propias variables. var (tupInt, tupReal, tupCplx) = diffTup; writeln(diffTup == (tupInt, tupReal, tupCplx)); // También son útiles para imprimit una lista de variables, // como es común en la depuración. writeln((a,b,thisInt,thatInt,thisBool,thatBool)); // Flujo de control // if - then - else funciona como cualquier otro lenguaje de la familia C. if 10 < 100 then writeln("All is well"); if -1 < 1 then writeln("Continuando creyendo en la realidad"); else writeln("¡Envia un matemático!, algo está mal"); // Puedes usar paréntesis si lo prefieres. if (10 > 100) { writeln("El Universo está roto, Por favor reinicie el universo."); } if a % 2 == 0 { writeln(a, " es par."); } else { writeln(a, " es impar."); } if a % 3 == 0 { writeln(a, " es divisible entre 3."); } else if a % 3 == 1 { writeln(a, " es divisible entre 3 con un residuo de 1."); } else { writeln(b, " es divisible entre 3 con un residuo de 2."); } // Ternario: if - then - else en una declaración. var maximum = if thisInt < thatInt then thatInt else thisInt; // las declaraciones select son muy parecidas a las declaraciones switch // en otros idiomas. Sin embargo, las declaraciones select no caen // en cascada como en C o Java. var inputOption = "anOption"; select inputOption { when "anOption" do writeln("Escoge 'anOption'"); when "otherOption" { writeln("Escoge 'otherOption'"); writeln("Que tiene un cuerpo"); } otherwise { writeln("Cualquier otra entrada"); writeln("El caso otherwise no necesita hacerse si el cuerpo es de una línea"); } } // Los bucles while y do-while también se comportan como sus contrapartes en C. var j: int = 1; var jSum: int = 0; while (j <= 1000) { jSum += j; j += 1; } writeln(jSum); do { jSum += j; j += 1; } while (j <= 10000); writeln(jSum); // Los bucles for son muy parecidos a los de Python porque iteran en un rango. // Los rangos (como la expresión 1..10 a continuación) son un objeto de primera clase // en Chapel, y como tal pueden almacenarse en variables. for i in 1..10 do write(i, ", "); writeln(); var iSum: int = 0; for i in 1..1000 { iSum += i; } writeln(iSum); for x in 1..10 { for y in 1..10 { write((x,y), "\t"); } writeln(); } // Rangos y Dominios // Los bucles y matrices utilizan rangos y dominios para definir un conjunto de índices // que se pueden iterar. Los rangos son índices enteros unidimensionales, mientras // que los dominios pueden ser multidimensionales y representan índices // de diferentes tipos. // Son tipos ciudadanos de primera clase y pueden asignarse a variables. var range1to10: range = 1..10; // 1, 2, 3, ..., 10 var range2to11 = 2..11; // 2, 3, 4, ..., 11 var rangeThisToThat: range = thisInt..thatInt; // usando variables var rangeEmpty: range = 100..-100; // esto es válido pero no contiene índices // Los rangos pueden ser ilimitados. var range1toInf: range(boundedType=BoundedRangeType.boundedLow) = 1.. ; // 1, 2, 3, 4, 5, ... var rangeNegInfTo1 = ..1; // ..., -4, -3, -2, -1, 0, 1 // Los rangos se pueden andar (y revertir) utilizando el operador by. var range2to10by2: range(stridable=true) = 2..10 by 2; // 2, 4, 6, 8, 10 var reverse2to10by2 = 2..10 by -2; // 10, 8, 6, 4, 2 var trapRange = 10..1 by -1; // No te dejes engañar, esto sigue siendo un rango vacío writeln("Size of range ", trapRange, " = ", trapRange.length); // Note: range(boundedType= ...) and range(stridable= ...) solo son necesarios // si escribimos explícitamente la variable. // El punto final de un rango se puede determinar utilizando el operador de conteo (#). var rangeCount: range = -5..#12; // intervalo de -5 to 6 // Los operadores pueden ser mixtos. var rangeCountBy: range(stridable=true) = -5..#12 by 2; // -5, -3, -1, 1, 3, 5 writeln(rangeCountBy); // Se pueden consultar las propiedades del rango. // En este ejemplo, imprime el primer índice, el último índice, el número de índices, // el paso y si 2 se incluye en el rango. writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.length, rangeCountBy.stride, rangeCountBy.member(2))); for i in rangeCountBy { write(i, if i == rangeCountBy.last then "\n" else ", "); } // Los dominios rectangulares se definen usando la misma sintaxis de rango, // pero se requiere que estén delimitados (a diferencia de los rangos). var domain1to10: domain(1) = {1..10}; // 1D domain from 1..10; var twoDimensions: domain(2) = {-2..2,0..2}; // 2D domain over product of ranges var thirdDim: range = 1..16; var threeDims: domain(3) = {thirdDim, 1..10, 5..10}; // using a range variable // Los dominios también pueden ser redimensionados var resizedDom = {1..10}; writeln("antes, resizedDom = ", resizedDom); resizedDom = {-10..#10}; writeln("despues, resizedDom = ", resizedDom); // Los índices pueden iterarse como tuplas. for idx in twoDimensions do write(idx, ", "); writeln(); // Estas tuplas también pueden ser deconstruidas. for (x,y) in twoDimensions { write("(", x, ", ", y, ")", ", "); } writeln(); // Los dominios asociativos actúan como conjuntos. var stringSet: domain(string); // empty set of strings stringSet += "a"; stringSet += "b"; stringSet += "c"; stringSet += "a"; // Redundant add "a" stringSet -= "c"; // Remove "c" writeln(stringSet.sorted()); // Los dominios asociativos también pueden tener una sintaxis literal var intSet = {1, 2, 4, 5, 100}; // Tanto los rangos como los dominios se pueden dividir para producir un rango // o dominio con la intersección de los índices. var rangeA = 1.. ; // range from 1 to infinity var rangeB = ..5; // range from negative infinity to 5 var rangeC = rangeA[rangeB]; // resulting range is 1..5 writeln((rangeA, rangeB, rangeC)); var domainA = {1..10, 5..20}; var domainB = {-5..5, 1..10}; var domainC = domainA[domainB]; writeln((domainA, domainB, domainC)); // Matrices // Las matrices son similares a otros lenguajes. // Sus tamaños son definidos usndo dominions que repretsenten sus indices. var intArray: [1..10] int; var intArray2: [{1..10}] int; // equivalent // Pueden ser accedidos usando brackets o paréntesis for i in 1..10 do intArray[i] = -i; writeln(intArray); // No podemos acceder a intArray[0] porque existe fuera del conjunto de índices, // {1..10}, que definimos al principio. // intArray [11] es ilegal por la misma razón. var realDomain: domain(2) = {1..5,1..7}; var realArray: [realDomain] real; var realArray2: [1..5,1..7] real; // equivalent var realArray3: [{1..5,1..7}] real; // equivalent for i in 1..5 { for j in realDomain.dim(2) { // Solo use la segunda dimensión del dominio realArray[i,j] = -1.61803 * i + 0.5 * j; // Acceso usando la lista de índice var idx: 2*int = (i,j); // Nota: 'índice' es una palabra reservada realArray[idx] = - realArray[(i,j)]; // Indice usando tuplas } } // Las matrices tienen dominios como miembros y pueden ser iterados de manera normal. for idx in realArray.domain { // De nuevo, idx es una tupla 2*int realArray[idx] = 1 / realArray[idx[1], idx[2]]; // Acceso por tupla y lista } writeln(realArray); // Los valores de una matriz también se pueden iterar directamente. var rSum: real = 0; for value in realArray { rSum += value; // Read a value value = rSum; // Write a value } writeln(rSum, "\n", realArray); // Las matrices asociativas (diccionarios) se pueden crear utilizando dominios asociativos. var dictDomain: domain(string) = { "one", "two" }; var dict: [dictDomain] int = ["one" => 1, "two" => 2]; dict["three"] = 3; // Adiciona 'three' a 'dictDomain' implícitamente for key in dictDomain.sorted() do writeln(dict[key]); // Las matrices se pueden asignar entre sí de diferentes maneras. // Estos arreglos se usarán en el ejemplo. var thisArray : [0..5] int = [0,1,2,3,4,5]; var thatArray : [0..5] int; // Primero, simplemente asigna uno al otro. Esto copia esta matriz en // thatArray, en lugar de simplemente crear una referencia. Por lo tanto, modificando // thisArray tampoco modifica thatArray. thatArray = thisArray; thatArray[1] = -1; writeln((thisArray, thatArray)); // Asigna un segmento de una matriz a un segmento (del mismo tamaño) en el otro. thatArray[4..5] = thisArray[1..2]; writeln((thisArray, thatArray)); // Las operaciones también se pueden promover para trabajar en arreglos. // 'thisPlusThat' también es una matriz. var thisPlusThat = thisArray + thatArray; writeln(thisPlusThat); // Continuando, las matrices y los bucles también pueden ser expresiones, donde // la expresión del cuerpo del bucle es el resultado de cada iteración. var arrayFromLoop = for i in 1..10 do i; writeln(arrayFromLoop); // Una expresión puede resultar en nada, como cuando se filtra con una expresión if. var evensOrFives = for i in 1..10 do if (i % 2 == 0 || i % 5 == 0) then i; writeln(arrayFromLoop); // Las expresiones de matriz también se pueden escribir con una notación de paréntesis. // Nota: esta sintaxis utiliza el concepto paralelo forall discutido más adelante. var evensOrFivesAgain = [i in 1..10] if (i % 2 == 0 || i % 5 == 0) then i; // They can also be written over the values of the array. arrayFromLoop = [value in arrayFromLoop] value + 1; // Procedimientos // Los procedimientos de Chapel tienen funciones de sintaxis similares en otros idiomas. proc fibonacci(n : int) : int { if n <= 1 then return n; return fibonacci(n-1) + fibonacci(n-2); } // Los parámetros de entrada pueden estar sin tipo para crear un procedimiento genérico. proc doublePrint(thing): void { write(thing, " ", thing, "\n"); } // Se puede inferir el tipo de retorno, siempre que el compilador pueda resolverlo. proc addThree(n) { return n + 3; } doublePrint(addThree(fibonacci(20))); // También es posible tomar un número variable de parámetros. proc maxOf(x ...?k) { // x se refiere a una tupla de un tipo, con k elementos var maximum = x[1]; for i in 2..k do maximum = if maximum < x[i] then x[i] else maximum; return maximum; } writeln(maxOf(1, -10, 189, -9071982, 5, 17, 20001, 42)); // Los procedimientos pueden tener valores de parámetros predeterminados, y // los parámetros pueden nombrarse en la llamada, incluso fuera de orden. proc defaultsProc(x: int, y: real = 1.2634): (int,real) { return (x,y); } writeln(defaultsProc(10)); writeln(defaultsProc(x=11)); writeln(defaultsProc(x=12, y=5.432)); writeln(defaultsProc(y=9.876, x=13)); // El operador ? se llama operador de consulta y se usa para tomar valores // indeterminados como tuplas o tamaños de matriz y tipos genéricos. // Por ejemplo, tomar matrices como parámetros. // El operador de consulta se utiliza para determinar el dominio de A. // Esto es útil para definir el tipo de retorno, aunque no es obligatorio. proc invertArray(A: [?D] int): [D] int{ for a in A do a = -a; return A; } writeln(invertArray(intArray)); // Podemos consultar el tipo de argumentos a los procedimientos genéricos. // Aquí definimos un procedimiento que toma dos argumentos del mismo tipo, // pero no definimos cuál es ese tipo. proc genericProc(arg1 : ?valueType, arg2 : valueType): void { select(valueType) { when int do writeln(arg1, " and ", arg2, " are ints"); when real do writeln(arg1, " and ", arg2, " are reals"); otherwise writeln(arg1, " and ", arg2, " are somethings!"); } } genericProc(1, 2); genericProc(1.2, 2.3); genericProc(1.0+2.0i, 3.0+4.0i); // También podemos imponer una forma de polimorfismo con la cláusula where // Esto permite que el compilador decida qué función usar. // Nota: Eso significa que toda la información debe conocerse en tiempo de compilación. // El modificador param en el argumento se usa para imponer esta restricción. proc whereProc(param N : int): void where (N > 0) { writeln("N is greater than 0"); } proc whereProc(param N : int): void where (N < 0) { writeln("N is less than 0"); } whereProc(10); whereProc(-1); // whereProc(0) daría lugar a un error del compilador porque no hay funciones // que satisfagan la condición de la cláusula where. // Podríamos haber definido un whereProc sin una cláusula where que // hubiera servido como captura para todos los demás casos (de los cuales solo hay uno). // Las cláusulas where también se pueden usar para restringir según el tipo de argumento. proc whereType(x: ?t) where t == int { writeln("Inside 'int' version of 'whereType': ", x); } proc whereType(x: ?t) { writeln("Inside general version of 'whereType': ", x); } whereType(42); whereType("hello"); // Intenciones /* Los modificadores de intención en los argumentos transmiten cómo esos argumentos se pasan al procedimiento. * in: copia arg adentro, pero no afuera * out: copia arg, pero no dentro * inout: copia arg adentro, copia arg afuera * ref: pasa arg por referencia */ proc intentsProc(in inarg, out outarg, inout inoutarg, ref refarg) { writeln("Adentro antes: ", (inarg, outarg, inoutarg, refarg)); inarg = inarg + 100; outarg = outarg + 100; inoutarg = inoutarg + 100; refarg = refarg + 100; writeln("Adentro después: ", (inarg, outarg, inoutarg, refarg)); } var inVar: int = 1; var outVar: int = 2; var inoutVar: int = 3; var refVar: int = 4; writeln("Afuera antes: ", (inVar, outVar, inoutVar, refVar)); intentsProc(inVar, outVar, inoutVar, refVar); writeln("Afuera después: ", (inVar, outVar, inoutVar, refVar)); // Del mismo modo, podemos definir intentos en el tipo de retorno. // refElement devuelve una referencia a un elemento de la matriz. Esto tiene más sentido // práctico para los métodos de clase donde las referencias a elementos en una estructura // de datos se devuelven a través de un método o iterador. proc refElement(array : [?D] ?T, idx) ref : T { return array[idx]; } var myChangingArray : [1..5] int = [1,2,3,4,5]; writeln(myChangingArray); ref refToElem = refElement(myChangingArray, 5); // Almacena una referencia al elemento en variable de referencia writeln(refToElem); refToElem = -2; // modifica referencia que, a su vez, modifica el valor real en la matriz writeln(refToElem); writeln(myChangingArray); // Definiciones del operador // Chapel permite que los operadores se sobrecarguen. // Podemos definir los operadores unarios: // + - ! ~ // y los operadores binarios: // + - * / % ** == <= >= < > << >> & | ˆ by // += -= *= /= %= **= &= |= ˆ= <<= >>= <=> // Exclusivo u operador booleano. proc ^(left : bool, right : bool): bool { return (left || right) && !(left && right); } writeln(true ^ true); writeln(false ^ true); writeln(true ^ false); writeln(false ^ false); // Define un operador * en cualquiera de los dos tipos que devuelve una tupla de esos tipos. proc *(left : ?ltype, right : ?rtype): (ltype, rtype) { writeln("\tIn our '*' overload!"); return (left, right); } writeln(1 * "a"); // Utiliza nuestro * operador. writeln(1 * 2); // Utiliza el operador predeterminado *. // Note: Podrías romper todo si te descuidas con tus sobrecargas. // Esto aquí lo romperá todo. No lo hagas /* proc +(left: int, right: int): int { return left - right; } */ // Iteradores // Los iteradores son hermanas del procedimiento, y casi todo lo relacionado // con los procedimientos también se aplica a los iteradores. Sin embargo, en lugar de // devolver un solo valor, los iteradores pueden generar múltiples valores en un bucle. // Esto es útil cuando se necesita un conjunto u orden complicado de iteraciones, // ya que permite que el código que define las iteraciones // se separe del cuerpo del bucle. iter oddsThenEvens(N: int): int { for i in 1..N by 2 do yield i; // yield values instead of returning. for i in 2..N by 2 do yield i; } for i in oddsThenEvens(10) do write(i, ", "); writeln(); // Los iteradores también pueden ceder condicionalmente, cuyo resultado puede ser nada iter absolutelyNothing(N): int { for i in 1..N { if N < i { // Always false yield i; // Yield statement never happens } } } for i in absolutelyNothing(10) { writeln("Woa there! absolutelyNothing yielded ", i); } // Podemos comprimir dos o más iteradores (que tienen el mismo número de iteraciones) // usando zip () para crear un solo iterador comprimido, donde cada iteración // del iterador comprimido produce una tupla de un valor de cada iterador. for (positive, negative) in zip(1..5, -5..-1) do writeln((positive, negative)); // La iteración de la cremallera es bastante importante en la asignación de matrices, // segmentos de matrices y expresiones de matriz / bucle. var fromThatArray : [1..#5] int = [1,2,3,4,5]; var toThisArray : [100..#5] int; // Algunas operaciones de cierre implementan otras operaciones. // La primera declaración y el bucle son equivalentes. toThisArray = fromThatArray; for (i,j) in zip(toThisArray.domain, fromThatArray.domain) { toThisArray[i] = fromThatArray[j]; } // Estos dos pedazos también son equivalentes. toThisArray = [j in -100..#5] j; writeln(toThisArray); for (i, j) in zip(toThisArray.domain, -100..#5) { toThisArray[i] = j; } writeln(toThisArray); /* Esto es muy importante para entender por qué esta declaración exhibe un error de tiempo de ejecución. */ /* var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i; */ // Aunque el dominio de la matriz y la expresión de bucle son del mismo tamaño, // el cuerpo de la expresión puede considerarse como un iterador. // Debido a que los iteradores pueden producir nada, ese iterador produce un número // diferente de cosas que el dominio de la matriz o bucle, que no está permitido. // Clases // Las clases son similares a las de C ++ y Java, asignadas en el montón. class MyClass { // Variables miembro var memberInt : int; var memberBool : bool = true; // Inicializador definido explícitamente. // También obtenemos el inicializador generado por el compilador, con un argumento por campo. // Tenga en cuenta que pronto no habrá un inicializador generado por el compilador // cuando definamos los inicializadores explícitamente. proc init(val : real) { this.memberInt = ceil(val): int; } // Desinicializador explícitamente definido. // Si no escribiéramos uno, obtendríamos el desinicializador generado por el compilador, // que tiene un cuerpo vacío. proc deinit() { writeln("MyClass deinitializer called ", (this.memberInt, this.memberBool)); } // Métodos de clase. proc setMemberInt(val: int) { this.memberInt = val; } proc setMemberBool(val: bool) { this.memberBool = val; } proc getMemberInt(): int{ return this.memberInt; } proc getMemberBool(): bool { return this.memberBool; } } // termina MyClass // Llame al inicializador generado por el compilador, // utilizando el valor predeterminado para memberBool. var myObject = new MyClass(10); myObject = new MyClass(memberInt = 10); // Equivalente writeln(myObject.getMemberInt()); // Same, but provide a memberBool value explicitly. var myDiffObject = new MyClass(-1, true); myDiffObject = new MyClass(memberInt = -1, memberBool = true); // Equivalente writeln(myDiffObject); // Llame al inicializador que escribimos. var myOtherObject = new MyClass(1.95); myOtherObject = new MyClass(val = 1.95); // Equivalente writeln(myOtherObject.getMemberInt()); // También podemos definir un operador en nuestra clase, // pero la definición tiene que estar fuera de la definición de la clase. proc +(A : MyClass, B : MyClass) : MyClass { return new MyClass(memberInt = A.getMemberInt() + B.getMemberInt(), memberBool = A.getMemberBool() || B.getMemberBool()); } var plusObject = myObject + myDiffObject; writeln(plusObject); // Destrucción. delete myObject; delete myDiffObject; delete myOtherObject; delete plusObject; // Las clases pueden heredar de una o más clases primarias class MyChildClass : MyClass { var memberComplex: complex; } // Aquí hay un ejemplo de clases genéricas. class GenericClass { type classType; var classDomain: domain(1); var classArray: [classDomain] classType; // Constructor explícito. proc GenericClass(type classType, elements : int) { this.classDomain = {1..#elements}; } // Copiar constructor. // Nota: Todavía tenemos que poner el tipo como argumento, pero podemos usar // el operador de consulta (?) como predeterminado para el tipo del otro objeto. // Además, podemos aprovechar esto para permitir a nuestro constructor de copias // copiar clases de diferentes tipos y emitir sobre la marcha. proc GenericClass(other : GenericClass(?otherType), type classType = otherType) { this.classDomain = other.classDomain; // Copiar y Convertir for idx in this.classDomain do this[idx] = other[idx] : classType; } // Defina la notación de corchetes en un objeto GenericClass // para que pueda comportarse como una matriz normal // i.e. objVar[i] or objVar(i) proc this(i : int) ref : classType { return this.classArray[i]; } // Definir un iterador implícito para que la clase produzca // valores de la matriz a un bucle // i.e. for i in objVar do ... iter these() ref : classType { for i in this.classDomain do yield this[i]; } } // end GenericClass // Podemos asignar a la matriz de miembros del objeto usando la notación de // corchete que definimos. var realList = new GenericClass(real, 10); for i in realList.classDomain do realList[i] = i + 1.0; // Podemos iterar sobre los valores en nuestra lista con el iterador // que definimos. for value in realList do write(value, ", "); writeln(); // Haga una copia de realList usando el constructor de copias. var copyList = new GenericClass(realList); for value in copyList do write(value, ", "); writeln(); // Haga una copia de realList y cambie el tipo, también utilizando el constructor de copias. var copyNewTypeList = new GenericClass(realList, int); for value in copyNewTypeList do write(value, ", "); writeln(); // Módulos // Los módulos son la forma en que Chapel administra los espacios de nombres. // Los archivos que contienen estos módulos no necesitan ser nombrados después // de los módulos (como en Java), pero los archivos implícitamente nombran módulos. // Por ejemplo, este archivo nombra implícitamente el módulo learnChapelInYMinutes module OurModule { // Podemos usar módulos dentro de otros módulos. // Time es uno de los módulos estándar. use Time; // Usaremos este procedimiento en la sección de paralelismo. proc countdown(seconds: int) { for i in 1..seconds by -1 { writeln(i); sleep(1); } } // Es posible crear nidos de módulos arbitrariamente profundos. // i.e. submódulos de OurModule module ChildModule { proc foo() { writeln("ChildModule.foo()"); } } module SiblingModule { proc foo() { writeln("SiblingModule.foo()"); } } } // end OurModule // Usando OurModule también usa todos los módulos que usa. // Como OurModule usa Time, nosotros también usamos Time. use OurModule; // En este punto no hemos usado ChildModule o SiblingModule, por lo que sus símbolos // (es decir, foo) no están disponibles para nosotros. Sin embargo, los nombres de // los módulos están disponibles y podemos llamar explícitamente a foo () a través de ellos. SiblingModule.foo(); OurModule.ChildModule.foo(); // Ahora usamos ChildModule, que permite llamadas no calificadas. use ChildModule; foo(); // Paralelismo // En otros idiomas, el paralelismo generalmente se realiza con librerias complicadas // y extrañas jerarquías de estructura de clases. // Chapel lo tiene directamente en el idioma. // Podemos declarar un procedimiento principal, pero todo el código anterior // a main todavía se ejecuta. proc main() { // Una declaración de inicio hará girar el cuerpo de esa declaración en una nueva tarea. // Una declaración de sincronización garantizará que el progreso de la tarea principal // no avance hasta que los hijos hayan sincronizado nuevamente. sync { begin { // Inicio del cuerpo de la nueva tarea. var a = 0; for i in 1..1000 do a += 1; writeln("Done: ", a); } // Fin del nuevo cuerpo de tareas writeln("escindió una tarea!"); } writeln("De nuevo juntos"); proc printFibb(n: int) { writeln("fibonacci(",n,") = ", fibonacci(n)); } // Una declaración de cobegin girará cada declaración del cuerpo en una nueva tarea. // Observe aquí que las impresiones de cada declaración pueden ocurrir en // cualquier orden. cobegin { printFibb(20); // nueva tarea printFibb(10); // nueva tarea printFibb(5); // nueva tarea { // Este es un cuerpo de declaración anidado y, por lo tanto, es una // declaración única para la declaración principal, ejecutada // por una sola tarea. writeln("esto se "); writeln("ejecuta"); writeln("como un todo"); } } // Un bucle coforall creará una nueva tarea para CADA iteración. // Nuevamente vemos que las impresiones suceden en cualquier orden. // NOTA: ¡coforall debe usarse solo para crear tareas! // ¡Usarlo para iterar sobre una estructura es una muy mala idea! var num_tasks = 10; // Number of tasks we want coforall taskID in 1..#num_tasks { writeln("Hola de tarea# ", taskID); } // los bucles forall son otro bucle paralelo, pero solo crean un número // menor de tareas, específicamente --dataParTasksPerLocale = número de tareas. forall i in 1..100 { write(i, ", "); } writeln(); // Aquí vemos que hay secciones que están en orden, seguidas de una sección // que no seguiría (por ejemplo, 1, 2, 3, 7, 8, 9, 4, 5, 6,). // Esto se debe a que cada tarea está asumiendo un fragmento del rango 1..10 // (1..3, 4..6 o 7..9) haciendo ese fragmento en serie, pero cada tarea ocurre en paralelo. // Sus resultados pueden depender de su máquina y configuración // Para los bucles forall y coforall, la ejecución de la tarea principal // no continuará hasta que todos los hijos se sincronicen. // los bucles forall son particularmente útiles para la iteración paralela sobre matrices. // Hagamos un experimento para ver qué tan rápido es un ciclo paralelo. use Time; // Importe el módulo Time para usar objetos de Timer var timer: Timer; var myBigArray: [{1..4000,1..4000}] real; // Gran matriz en la que escribiremos // Experimento en serie: timer.start(); // Iniciar temporizador for (x,y) in myBigArray.domain { // Iteración en serie myBigArray[x,y] = (x:real) / (y:real); } timer.stop(); // Detener temporizador writeln("Serial: ", timer.elapsed()); // Imprimir tiempo transcurrido timer.clear(); // Limpia el temporizador para bucle paralelo // Experimento Paralelo: timer.start(); // Iniciar temporizador forall (x,y) in myBigArray.domain { // Iteración paralela myBigArray[x,y] = (x:real) / (y:real); } timer.stop(); // Detener temporizador writeln("Parallel: ", timer.elapsed()); // Imprimir tiempo transcurrido timer.clear(); // Puede que hayas notado que (dependiendo de cuántos núcleos tengas) // el ciclo paralelo fue más rápido que el ciclo serial. // La expresión de bucle estilo corchete descrita mucho antes utiliza // implícitamente un bucle forall. [val in myBigArray] val = 1 / val; // Operación paralela // Las variables atómicas, comunes a muchos idiomas, son aquellas cuyas operaciones // ocurren sin interrupciones. Por lo tanto, varios subprocesos pueden modificar // las variables atómicas y pueden saber que sus valores son seguros. // Las variables atómicas de la capilla pueden ser de tipo bool, int, uint y real. var uranium: atomic int; uranium.write(238); // escribir atómicamente una variable writeln(uranium.read()); // leer atómicamente una variable // Las operaciones atómicas se describen como funciones, por lo que puede definir // las suyas propias. uranium.sub(3); // restar atómicamente una variable writeln(uranium.read()); var replaceWith = 239; var was = uranium.exchange(replaceWith); writeln("El uranio era", was, ", pero ahora es ", replaceWith); var isEqualTo = 235; if uranium.compareExchange(isEqualTo, replaceWith) { writeln("El uranio era igual a ", isEqualTo, " pero valor reemplazado por", replaceWith); } else { writeln("uranio no era igual a ", isEqualTo, " así que el valor permanece igual... sea lo que sea"); } sync { begin { // Tarea del lector writeln("Lector: esperando que el uranio sea ", isEqualTo); uranium.waitFor(isEqualTo); writeln("Lector: el uranio fue configurado (por alguien) para ", isEqualTo); } begin { // Tarea de escritor writeln("Escritor: establecerá uranio en el valor ", isEqualTo, " en..."); countdown(3); uranium.write(isEqualTo); } } // las variables de sincronización tienen dos estados: vacío y lleno. // Si lee una variable vacía o escribe una variable completa, // se espera hasta que la variable esté llena o vacía nuevamente. var someSyncVar$: sync int; // varName$ Es una convención, no una ley. sync { begin { // Tarea del lector writeln("Lector: esperando leer."); var read_sync = someSyncVar$; writeln("Lector: el valor es ", read_sync); } begin { // Tarea de escritor writeln("Escritor: escribirá en..."); countdown(3); someSyncVar$ = 123; } } // las variales individuales solo se pueden escribir una vez. // Una lectura en un solo no escrito da como resultado una espera, // pero cuando la variable tiene un valor, puede leerse indefinidamente. var someSingleVar$: single int; // varName$ Es una convención, no una ley. sync { begin { // Tarea del lector writeln("Lector: esperando leer."); for i in 1..5 { var read_single = someSingleVar$; writeln("Lector: iteración ", i,", y el valor es ", read_single); } } begin { // Tarea de escritor writeln("Escritor: escribirá en ..."); countdown(3); someSingleVar$ = 5; // primero y único escrito. } } // Aquí hay un ejemplo usando atómica y una variable de sincronización // para crear un mutex de cuenta regresiva // (también conocido como multiplexor). var count: atomic int; // nuestro mostrador var lock$: sync bool; // la cerradura mutex count.write(2); // Solo deje dos tareas a la vez. lock$.writeXF(true); // Establezca lock$ en completo (desbloqueado) // Nota: el valor en realidad no importa, solo el estado // (completo: desbloqueado / vacio: bloqueado) // Además, writeXF() llena (F) la variable de sincronización independientemente de su estado (X) coforall task in 1..#5 { // Generar tareas // Create a barrier do { lock$; // Leer lock$ (espera) } while (count.read() < 1); // Sigue esperando hasta que se abra un lugar count.sub(1); //disminuir el contador lock$.writeXF(true); // Establezca lock$ en completo (señal) // 'Trabajo' actual writeln("Tarea #", task, " trabajando"); sleep(2); count.add(1); // Incrementa el contador lock$.writeXF(true); // Establezca lock$ en completo (señal) } // Podemos definir las operaciones + * & | ^ && || min max minloc maxloc // sobre una matriz completa usando escaneos y reducciones. // Las reducciones aplican la operación en toda la matriz // y dan como resultado un valor escalar. var listOfValues: [1..10] int = [15,57,354,36,45,15,456,8,678,2]; var sumOfValues = + reduce listOfValues; var maxValue = max reduce listOfValues; // 'max' da solo el valor máximo // maxloc proporciona el valor máximo y el índice del valor máximo. // Nota: Tenemos que comprimir la matriz y el dominio junto con el iterador zip. var (theMaxValue, idxOfMax) = maxloc reduce zip(listOfValues, listOfValues.domain); writeln((sumOfValues, maxValue, idxOfMax, listOfValues[idxOfMax])); // Los escaneos aplican la operación de forma incremental y devuelven una matriz // con los valores de la operación en ese índice a medida que avanza a través // de la matriz desde array.domain.low hasta array.domain.high. var runningSumOfValues = + scan listOfValues; var maxScan = max scan listOfValues; writeln(runningSumOfValues); writeln(maxScan); } // end main() ``` ## ¿Para quién es este tutorial? Este tutorial es para personas que desean aprender las cuerdas de chapel sin tener que escuchar sobre qué mezcla de fibras son las cuerdas, o cómo fueron trenzadas, o cómo las configuraciones de trenzas difieren entre sí. No le enseñará cómo desarrollar código increíblemente eficaz, y no es exhaustivo. Referirse a [especificación de idioma](https://chapel-lang.org/docs/latest/language/spec.html)(en) y a [documentación del módulo](https://chapel-lang.org/docs/latest/)(en) para más detalles. Ocasionalmente, vuelva aquí en el [website de Chapel](https://chapel-lang.org) para ver si se han agregado más temas o se han creado más tutoriales. ### Lo que le falta a este tutorial: * Exposición de los [módulos estándar](https://chapel-lang.org/docs/latest/modules/standard.html) * Múltiples configuraciones regionales (sistema de memoria distribuida) * Registros * Iteradores paralelos ## ¡Sus comentarios, preguntas y descubrimientos son importantes para los desarrolladores! El lenguaje Chapel todavía está en desarrollo activo, por lo que ocasionalmente hay problemas con el rendimiento y las características del lenguaje. Cuanta más información brinde al equipo de desarrollo de Chapel sobre los problemas que encuentre o las características que le gustaría ver, mejor será el lenguaje. Hay varias formas de interactuar con los desarrolladores: * [Chat de Gitter](https://gitter.im/chapel-lang/chapel) * [lista de emails de Sourceforge](https://sourceforge.net/p/chapel/mailman) Si está realmente interesado en el desarrollo del compilador o en contribuir al proyecto, [consulte el repositorio maestro de GitHub](https://github.com/chapel-lang/chapel). Está bajo el [La licencia Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0). ## Instalar el compilador [La documentación oficial de Chapel detalla cómo descargar y compilar el compilador de Chapel.](https://chapel-lang.org/docs/usingchapel/QUICKSTART.html) Chapel se puede construir e instalar en su máquina promedio 'nix (y cygwin). [Descargue la última versión de lanzamiento](https://github.com/chapel-lang/chapel/releases/) y es tan fácil como 1. `tar -xvf chapel-.tar.gz` 2. `cd chapel-` 3. `source util/setchplenv.bash # or .sh or .csh or .fish` 4. `make` 5. `make check # optional` You will need to `source util/setchplenv.EXT` from within the Chapel directory (`$CHPL_HOME`) every time your terminal starts so it's suggested that you drop that command in a script that will get executed on startup (like .bashrc). Necesitará `source util/setchplenv.EXT` desde el directorio de Chapel (`$CHPL_HOME`) cada vez que se inicie su terminal, por lo que se sugiere que suelte ese comando en un script que se ejecutará al inicio (como .bashrc). Chapel se instala fácilmente con Brew para OS X 1. `brew update` 2. `brew install chapel` ## Compilando Código Construye como otros compiladores: `chpl myFile.chpl -o myExe` Argumentos notables: * `--fast`: habilita varias optimizaciones y deshabilita las comprobaciones de los límites de la matriz Solo debe habilitarse cuando la aplicación es estable. * `--set =`: establece el param de configuracion `` a ``en tiempo de compilación. * `--main-module `: use el procedimiento main() que se encuentra en el módulo `` como principal del ejecutable. * `--module-dir `: incluye `` en la ruta de búsqueda del módulo. ================================================ FILE: es/clojure.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] translators: - ["Antonio Hernández Blas", "https://twitter.com/nihilipster"] - ["Guillermo Vayá Pérez", "http://willyfrog.es"] --- Clojure es un lenguaje de la familia Lisp desarrollado para la Máquina Virtual de Java. Tiene un énfasis mayor en la [programación funcional](https://es.wikipedia.org/wiki/Programación_funcional) pura que Common Lisp, pero incluye varias utilidades de [SMT](https://es.wikipedia.org/wiki/Memoria_transacional) para manipular el estado según se presente. Esta combinación le permite gestionar el procesamiento concurrente de manera muy sencilla, y a menudo automáticamente. (Necesitas la versión de Clojure 1.2 o reciente) ```clojure ; Los comentarios comienzan con punto y coma. ; Clojure se escribe mediante patrones ("forms"), los cuales son ; listas de cosas entre paréntesis, separados por espacios en blanco. ; El lector ("reader") de Clojure asume que la primera cosa es una ; función o una macro a llamar, y el resto son argumentos. ; La primera llamada en un archivo debe ser ns, para establecer el espacio de ; nombres ("namespace") (ns learnclojure) ; Algunos ejemplos básicos: ; str crea una cadena de caracteres a partir de sus argumentos (str "Hello" " " "World") ; => "Hello World" ; Las operaciones matemáticas son sencillas (+ 1 1) ; => 2 (- 2 1) ; => 1 (* 1 2) ; => 2 (/ 2 1) ; => 2 ; La igualdad es = (= 1 1) ; => true (= 2 1) ; => false ; También es necesaria la negación para las operaciones lógicas (not true) ; => false ; Los patrones anidados funcionan como esperas (+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2 ; Tipos ;;;;;;;;;;;;; ; Clojure usa los tipos de objetos de Java para booleanos, cadenas de ; caracteres ("strings") y números. ; Usa class para inspeccionarlos. (class 1); Los números enteros literales son java.lang.Long por defecto (class 1.); Los números en coma flotante literales son java.lang.Double (class ""); Los strings siempre van entre comillas dobles, y son ; java.lang.String (class false); Los booleanos son java.lang.Boolean (class nil); El valor "null" se escribe nil ; Si quieres crear una lista literal de datos, usa ' para evitar su evaluación '(+ 1 2) ; => (+ 1 2) ; (que es una abreviatura de (quote (+ 1 2))) ; Puedes evaluar una lista precedida por una comilla con eval (eval '(+ 1 2)) ; => 3 ; Colecciones & Secuencias ;;;;;;;;;;;;;;;;;;; ; Las Listas están basadas en listas enlazadas, mientras que los Vectores en ; arreglos. ; ¡Los Vectores y las Listas también son clases de Java! (class [1 2 3]); => clojure.lang.PersistentVector (class '(1 2 3)); => clojure.lang.PersistentList ; Una lista podría ser escrita como (1 2 3), pero debemos precederle una ; comilla para evitar que el lector ("reader") piense que es una función. ; Además, (list 1 2 3) es lo mismo que '(1 2 3) ; Las Colecciones ("collections") son solo grupos de datos ; Tanto las Listas como los Vectores son colecciones: (coll? '(1 2 3)) ; => true (coll? [1 2 3]) ; => true ; Las Secuencias ("seqs") son descripciones abstractas de listas de datos. ; Solo las listas son secuencias ("seqs"). (seq? '(1 2 3)) ; => true (seq? [1 2 3]) ; => false ; Una secuencia solo necesita proporcionar uno de sus elementos cuando es ; accedido. ; Así que, las secuencias pueden ser perezosas -- pueden definir series ; infinitas: (range 4) ; => (0 1 2 3) (range) ; => (0 1 2 3 4 ...) (una serie infinita) (take 4 (range)) ; (0 1 2 3) ; Usa cons para agregar un elemento al inicio de una Lista o Vector (cons 4 [1 2 3]) ; => (4 1 2 3) (cons 4 '(1 2 3)) ; => (4 1 2 3) ; conj agregará un elemento a una colección en la forma más eficiente. ; Para Listas, se añade al inicio. Para vectores, al final. (conj [1 2 3] 4) ; => [1 2 3 4] (conj '(1 2 3) 4) ; => (4 1 2 3) ; Usa concat para concatenar Listas o Vectores (concat [1 2] '(3 4)) ; => (1 2 3 4) ; Usa filter y map para actuar sobre colecciones (map inc [1 2 3]) ; => (2 3 4) (filter even? [1 2 3]) ; => (2) ; Usa reduce para combinar sus elementos (reduce + [1 2 3 4]) ; = (+ (+ (+ 1 2) 3) 4) ; => 10 ; reduce puede tomar un argumento como su valor inicial también (reduce conj [] '(3 2 1)) ; = (conj (conj (conj [] 3) 2) 1) ; => [3 2 1] ; Funciones ;;;;;;;;;;;;;;;;;;;;; ; Usa fn para crear nuevas funciones. Una función siempre devuelve ; su última expresión (fn [] "Hello World") ; => fn ; (Necesitas rodearlo con paréntesis para llamarla) ((fn [] "Hello World")) ; => "Hello World" ; Puedes definir una variable ("var") mediante def (def x 1) x ; => 1 ; Asignar una función a una variable ("var") (def hello-world (fn [] "Hello World")) (hello-world) ; => "Hello World" ; Puedes usar defn como atajo para lo anterior (defn hello-world [] "Hello World") ; El [] es el Vector de argumentos de la función. (defn hello [name] (str "Hello " name)) (hello "Steve") ; => "Hello Steve" ; Puedes usar esta abreviatura para definir funciones: (def hello2 #(str "Hello " %1)) (hello2 "Fanny") ; => "Hello Fanny" ; Puedes tener funciones multi-variables ("multi-variadic") también (defn hello3 ([] "Hello World") ([name] (str "Hello " name))) (hello3 "Jake") ; => "Hello Jake" (hello3) ; => "Hello World" ; Las funciones pueden empaquetar argumentos extras en una secuencia para ti (defn count-args [& args] (str "You passed " (count args) " args: " args)) (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" ; Puedes combinar los argumentos regulares y los empaquetados (defn hello-count [name & args] (str "Hello " name ", you passed " (count args) " extra args")) (hello-count "Finn" 1 2 3) ; => "Hello Finn, you passed 3 extra args" ; Mapas ;;;;;;;;;; ; Los Mapas de Hash ("HashMap") y Mapas de Arreglo ("ArrayMap") comparten una ; interfaz. Los Mapas de Hash tienen búsquedas más rápidas pero no mantienen el ; orden de las llaves. (class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap (class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap ; Los Mapas de Arreglo se convierten automáticamente en Mapas de Hash en la ; mayoría de operaciones si crecen mucho, por lo que no debes preocuparte. ; Los Mapas pueden usar cualquier tipo para sus llaves, pero generalmente las ; Claves ("keywords") son lo habitual. ; Las Claves son como strings con algunas ventajas de eficiencia (class :a) ; => clojure.lang.Keyword (def stringmap {"a" 1, "b" 2, "c" 3}) stringmap ; => {"a" 1, "b" 2, "c" 3} (def keymap {:a 1, :b 2, :c 3}) keymap ; => {:a 1, :c 3, :b 2} ; Por cierto, las comas son equivalentes a espacios en blanco y no hacen ; nada. ; Recupera un valor de un Mapa tratándola como una función (stringmap "a") ; => 1 (keymap :a) ; => 1 ; ¡Las Claves pueden ser usadas para recuperar su valor del mapa, también! (:b keymap) ; => 2 ; No lo intentes con strings. ;("a" stringmap) ; => Exception: java.lang.String cannot be cast to clojure.lang.IFn ; Recuperando una clave no existente nos devuelve nil (stringmap "d") ; => nil ; Usa assoc para añadir nuevas claves a los Mapas de Hash (def newkeymap (assoc keymap :d 4)) newkeymap ; => {:a 1, :b 2, :c 3, :d 4} ; Pero recuerda, ¡los tipos de Clojure son inmutables! keymap ; => {:a 1, :b 2, :c 3} ; Usa dissoc para eliminar claves (dissoc keymap :a :b) ; => {:c 3} ; Conjuntos ;;;;;; (class #{1 2 3}) ; => clojure.lang.PersistentHashSet (set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3} ; Añade un elemento con conj (conj #{1 2 3} 4) ; => #{1 2 3 4} ; Elimina uno con disj (disj #{1 2 3} 1) ; => #{2 3} ; Comprueba su existencia usando al Conjunto como una función: (#{1 2 3} 1) ; => 1 (#{1 2 3} 4) ; => nil ; Hay más funciones en el espacio de nombres clojure.sets ; Patrones útiles ;;;;;;;;;;;;;;;;; ; Los operadores lógicos en clojure son solo macros, y presentan el mismo ; aspecto que el resto de patrones. (if false "a" "b") ; => "b" (if false "a") ; => nil ; Usa let para definir ("binding") una variable temporal (let [a 1 b 2] (> a b)) ; => false ; Agrupa sentencias mediante do (do (print "Hello") "World") ; => "World" (prints "Hello") ; Las funciones tienen un do implícito (defn print-and-say-hello [name] (print "Saying hello to " name) (str "Hello " name)) (print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff") ; Y let también (let [name "Urkel"] (print "Saying hello to " name) (str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel") ; Usa las macros de tubería ("threading", "arrow", "pipeline" o "chain") ; (-> y ->>) para expresar la transformación de datos de una manera más clara. ; La macro Tubería-primero ("Thread-first") (->) inserta en cada patrón el ; resultado de los previos, como el primer argumento (segundo elemento) (-> {:a 1 :b 2} (assoc :c 3) ;=> (assoc {:a 1 :b 2} :c 3) (dissoc :b)) ;=> (dissoc (assoc {:a 1 :b 2} :c 3) :b) ; Esta expresión podría ser escrita como: ; (dissoc (assoc {:a 1 :b 2} :c 3) :b) ; y evalua a {:a 1 :c 3} ; La macro Tubería-último ("Thread-last") hace lo mismo, pero inserta el ; resultado de cada línea al *final* de cada patrón. Esto es útil para las ; operaciones de colecciones en particular: (->> (range 10) (map inc) ;=> (map inc (range 10)) (filter odd?) ;=> (filter odd? (map inc (range 10))) (into [])) ;=> (into [] (filter odd? (map inc (range 10)))) ; Result: [1 3 5 7 9] ; Cuando estés en una situación donde quieras tener más libertad en donde ; poner el resultado de transformaciones previas de datos en una expresión, ; puedes usar la macro as->. Con ella, puedes asignar un nombre especifico ; a la salida de la transformaciones y usarlo como identificador en tus ; expresiones encadenadas ("chain"). (as-> [1 2 3] input (map inc input);=> You can use last transform's output at the last position (nth input 2) ;=> and at the second position, in the same expression (conj [4 5 6] input [8 9 10])) ;=> or in the middle ! ; Módulos ;;;;;;;;;;;;;;; ; Usa use para obtener todas las funciones del módulo (use 'clojure.set) ; Ahora podemos usar más operaciones de Conjuntos (intersection #{1 2 3} #{2 3 4}) ; => #{2 3} (difference #{1 2 3} #{2 3 4}) ; => #{1} ; Puedes escoger un subgrupo de funciones a importar, también (use '[clojure.set :only [intersection]]) ; Usa require para importar un módulo (require 'clojure.string) ; Usa / para llamar las funciones de un módulo ; Aquí, el módulo es clojure.string y la función es blank? (clojure.string/blank? "") ; => true ; Puedes asignarle una sobrenombre a un modulo al importarlo (require '[clojure.string :as str]) (str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst." ; (#"" es una expresión regular literal) ; Puedes usar require (y use, pero no lo hagas) desde un espacio de nombres ; usando :require, ; No necesitas preceder con comilla tus módulos si lo haces de esta manera. (ns test (:require [clojure.string :as str] [clojure.set :as set])) ; Java ;;;;;;;;;;;;;;;;; ; Java tiene una enorme y útil librería estándar, por lo que querrás ; aprender como hacer uso de ella. ; Usa import para cargar un módulo de java (import java.util.Date) ; Puedes importar desde un ns también. (ns test (:import java.util.Date java.util.Calendar)) ; Usa el nombre de la clase con un "." al final para crear una nueva instancia (Date.) ; ; Usa "." para llamar métodos. O, usa el atajo ".método" (. (Date.) getTime) ; (.getTime (Date.)) ; exactamente lo mismo. ; Usa / para llamar métodos estáticos. (System/currentTimeMillis) ; (System siempre está presente) ; Usa doto para lidiar con el uso de clases (mutables) de una manera más ; tolerable (import java.util.Calendar) (doto (Calendar/getInstance) (.set 2000 1 1 0 0 0) .getTime) ; => A Date. set to 2000-01-01 00:00:00 ; STM ;;;;;;;;;;;;;;;;; ; La Memoria Transaccional ("Software Transactional Memory" / "STM") es un ; mecanismo que usa clojure para gestionar la persistecia de estado. Hay unas ; cuantas construcciones en clojure que hacen uso de él. ; Un atom es el más sencillo. Se le da un valor inicial (def my-atom (atom {})) ; Actualiza un atom con swap! ; swap! toma una función y la llama con el valor actual del atom ; como su primer argumento, y cualquier argumento restante como el segundo (swap! my-atom assoc :a 1) ; Establece my-atom al resultado ; de (assoc {} :a 1) (swap! my-atom assoc :b 2) ; Establece my-atom al resultado ; de (assoc {:a 1} :b 2) ; Usa '@' para no referenciar al atom y obtener su valor my-atom ;=> Atom<#...> (Regresa el objeto Atom) @my-atom ; => {:a 1 :b 2} ; Aquí está un sencillo contador usando un atom (def counter (atom 0)) (defn inc-counter [] (swap! counter inc)) (inc-counter) (inc-counter) (inc-counter) (inc-counter) (inc-counter) @counter ; => 5 ; Otras construcciones de STM son refs y agents. ; Refs: http://clojure.org/refs ; Agents: http://clojure.org/agents ``` ### Lectura adicional Ésto queda lejos de ser exhaustivo, pero ojalá que sea suficiente para que puedas empezar tu camino. Clojure.org tiene muchos artículos: [http://clojure.org](http://clojure.org) Clojuredocs.org contiene documentación con ejemplos para la mayoría de funciones principales (pertenecientes al core): [http://clojuredocs.org/quickref](http://clojuredocs.org/quickref) 4Clojure es una genial forma de mejorar tus habilidades con clojure/FP: [https://4clojure.oxal.org/](https://4clojure.oxal.org/) Clojure-doc.org (sí, de verdad) tiene un buen número de artículos con los que iniciarse en Clojure: [http://clojure-doc.org](http://clojure-doc.org) ================================================ FILE: es/coffeescript.md ================================================ --- contributors: - ["Tenor Biel", "http://github.com/L8D"] translators: - ["Pablo Elices", "http://github.com/pabloelices"] --- ``` coffeescript # CoffeeScript es un lenguaje hipster. # Tiene convenciones de muchos lenguajes modernos. # Los comentarios son como en Ruby y Python, usan almohadillas. ### Los comentarios en bloque son como estos, y se traducen directamente a '/*' y '*/' para el código JavaScript resultante. Deberías entender la mayor parte de la semántica de JavaScript antes de continuar. ### # Asignación: number = 42 #=> var number = 42; opposite = true #=> var opposite = true; # Condiciones: number = -42 if opposite #=> if(opposite) { number = -42; } # Funciones: square = (x) -> x * x #=> var square = function(x) { return x * x; } # Rangos: list = [1..5] #=> var list = [1, 2, 3, 4, 5]; # Objetos: math = root: Math.sqrt square: square cube: (x) -> x * square x #=> var math = { # "root": Math.sqrt, # "square": square, # "cube": function(x) { return x * square(x); } #} # Número de argumentos variable: race = (winner, runners...) -> print winner, runners # Existencia: alert "I knew it!" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); } # Listas: cubes = (math.cube num for num in list) #=> ... ``` ================================================ FILE: es/coldfusion.md ================================================ --- contributors: - ["Wayne Boka", "http://wboka.github.io"] - ["Kevin Morris", "https://twitter.com/kevinmorris"] translators: - ["Ivan Alburquerque", "https://github.com/AlburIvan"] --- ColdFusion es un lenguaje de scripting para desarrollo web. [Lea más aquí](http://www.adobe.com/products/coldfusion-family.html) ### CFML _**C**old**F**usion **M**arkup **L**anguage_ ColdFusion comenzó como un lenguaje basado en etiquetas. Casi toda la funcionalidad está disponible usando etiquetas. ```cfm Se han proporcionado etiquetas HTML para facilitar la lectura. " --->

Variables simples

Set miVariable to "miValor"

Set miNumero to 3.14

Muestra miVariable: #miVariable#

Muestra miNumero: #miNumero#


Variables complejas

Establecer miArreglo1 en una matriz de 1 dimensión utilizando la notación literal o de corchete

Establecer miArreglo2 en una matriz de 1 dimensión usando la notación de funciones

Contenidos de miArreglo1

Contenidos de miArreglo2

Operadores

Aritméticos

1 + 1 = #1 + 1#

10 - 7 = #10 - 7#

15 * 10 = #15 * 10#

100 / 5 = #100 / 5#

120 % 5 = #120 % 5#

120 mod 5 = #120 mod 5#


Comparación

Notación estándar

Is 1 eq 1? #1 eq 1#

Is 15 neq 1? #15 neq 1#

Is 10 gt 8? #10 gt 8#

Is 1 lt 2? #1 lt 2#

Is 10 gte 5? #10 gte 5#

Is 1 lte 5? #1 lte 5#

Notación alternativa

Is 1 == 1? #1 eq 1#

Is 15 != 1? #15 neq 1#

Is 10 > 8? #10 gt 8#

Is 1 < 2? #1 lt 2#

Is 10 >= 5? #10 gte 5#

Is 1 <= 5? #1 lte 5#


Estructuras de Control

Condición a probar: "#miCondicion#"

#miCondicion#. Estamos probando. #miCondicion#. Procede con cuidado!!! miCondicion es desconocido

Bucles

Bucle For

Index equals #i#

Bucle For Each (Variables complejas)

Establecer miArreglo3 to [5, 15, 99, 45, 100]

Index equals #i#

Establecer myArray4 to ["Alpha", "Bravo", "Charlie", "Delta", "Echo"]

Index equals #s#

Declaración Switch

Establecer miArreglo5 to [5, 15, 99, 45, 100]

#i# es un múltiplo de 5.

#i# es noventa y nueve.

#i# no es 5, 15, 45, or 99.


Conversión de tipos

Valor Como booleano Como número Como fecha Como cadena
"Si" TRUE 1 Error "Si"
"No" FALSE 0 Error "No"
TRUE TRUE 1 Error "Yes"
FALSE FALSE 0 Error "No"
Número True si el número no es 0; False de lo contrario. Número Consulte "Date-time values" anteriormente en este capítulo. Representación de cadena del número (for example, "8").
Cadena Si representa una fecha y hora (ver la siguiente columna), se convierte al valor numérico del objeto de fecha y hora correspondiente.
Si es una fecha, hora o marca de tiempo ODBC (por ejemplo, "{ts '2001-06-14 11:30:13'}", o si se expresa en un formato de fecha u hora estándar de EE. UU., incluido al usar nombres de mes completos o abreviados, se convierte al valor de fecha y hora correspondiente.
Los días de la semana o la puntuación inusual dan como resultado un error.
Generalmente se permiten guiones, barras diagonales y espacios.
Cadena
Fecha Error El valor numérico del objeto fecha-hora. Fecha una marca de tiempo de ODBC.

Componentes

Código de referencia (las funciones deben devolver algo para admitir IE) ``` ```cfs sayHola()

#sayHola()#

getHola()

#getHola()#

getMundo()

#getMundo()#

setHola("Hola")

#setHola("Hola")#

setMundo("mundo")

#setMundo("mundo")#

sayHola()

#sayHola()#

getHola()

#getHola()#

getMundo()

#getMundo()#

``` ### CFScript _**C**old**F**usion **S**cript_ En los últimos años, el lenguaje ColdFusion ha agregado sintaxis de script para simular la funcionalidad de etiquetas. Cuando se utiliza un servidor CF actualizado, casi todas las funciones están disponibles mediante la sintaxis de script. ## Otras lecturas Los enlaces que se proporcionan a continuación son solo para comprender el tema, siéntase libre de buscar en Google y encuentrar ejemplos específicos. 1. [Coldfusion Reference From Adobe](https://helpx.adobe.com/coldfusion/cfml-reference/topics.html) 2. [Open Source Documentation](http://cfdocs.org/) ================================================ FILE: es/common-lisp.md ================================================ --- contributors: - ["Paul Nathan", "https://github.com/pnathan"] - ["Paul Khuong", "https://github.com/pkhuong"] - ["Rommel Martinez", "https://ebzzry.io"] translators: - ["ivanchoff", "https://github.com/ivanchoff"] - ["Andre Polykanine", "https://github.com/Menelion"] --- Common Lisp es un lenguaje de proposito general y multiparadigma adecuado para una amplia variedad de aplicaciones en la industria. Es frecuentemente referenciado como un lenguaje de programación programable. EL punto de inicio clásico es [Practical Common Lisp](http://www.gigamonkeys.com/book/). Otro libro popular y reciente es [Land of Lisp](http://landoflisp.com/). Un nuevo libro acerca de las mejores prácticas, [Common Lisp Recipes](http://weitz.de/cl-recipes/), fue publicado recientemente. ```lisp ;;;----------------------------------------------------------------------------- ;;; 0. Sintaxis ;;;----------------------------------------------------------------------------- ;;; Forma general ;;; CL tiene dos piezas fundamentales en su sintaxis: ATOM y S-EXPRESSION. ;;; Típicamente, S-expressions agrupadas son llamadas `forms`. 10 ; un atom; se evalua a sí mismo :thing ; otro atom; evaluando el símbolo :thing t ; otro atom, denotando true (+ 1 2 3 4) ; una s-expression '(4 :foo t) ; otra s-expression ;;; Comentarios ;;; comentarios de una sola línea empiezan con punto y coma; usa cuatro para ;;; comentarios a nivel de archivo, tres para descripciones de sesiones, dos ;;; adentro de definiciones, y una para líneas simples. Por ejemplo, ;;;; life.lisp ;;; Foo bar baz, porque quu quux. Optimizado para máximo krakaboom y umph. ;;; Requerido por la función LINULUKO. (defun sentido (vida) "Retorna el sentido de la vida calculado" (let ((meh "abc")) ;; llama krakaboom (loop :for x :across meh :collect x))) ; guarda valores en x, luego lo retorna ;;; Comentarios de bloques, por otro lado, permiten comentarios de forma libre. estos son ;;; delimitados con #| y |# #| Este es un comentario de bloque el cual puede abarcar multiples líneas y #| estos pueden ser anidados |# |# ;;; Entorno ;;; Existe una variedad de implementaciones; La mayoría son conformes a los estándares. SBCL ;;; es un buen punto de inicio. Bibliotecas de terceros pueden instalarse fácilmente con ;;; Quicklisp ;;; CL es usualmente desarrollado y un bucle de Lectura-Evaluación-Impresión (REPL), corriendo ;;; al mismo tiempo. El REPL permite la exploración interactiva del programa mientras este esta ;;; corriendo ;;;----------------------------------------------------------------------------- ;;; 1. Operadores y tipos de datos primitivos ;;;----------------------------------------------------------------------------- ;;; Símbolos 'foo ; => FOO Note que el símbolo es pasado a mayúsculas automáticamente. ;;; INTERN manualmente crea un símbolo a partir de una cadena. (intern "AAAA") ; => AAAA (intern "aaa") ; => |aaa| ;;; Números 9999999999999999999999 ; enteros #b111 ; binario=> 7 #o111 ; octal => 73 #x111 ; hexadecimal => 273 3.14159s0 ; simple 3.14159d0 ; double 1/2 ; proporciones #C(1 2) ; números complejos ;;; las funciones son escritas como (f x y z ...) donde f es una función y ;;; x, y, z, ... son los argumentos. (+ 1 2) ; => 3 ;;; Si deseas crear datos literales use QUOTE para prevenir que estos sean evaluados (quote (+ 1 2)) ; => (+ 1 2) (quote a) ; => A ;;; La notación abreviada para QUOTE es ' '(+ 1 2) ; => (+ 1 2) 'a ; => A ;;; Operaciones aritméticas básicas (+ 1 1) ; => 2 (- 8 1) ; => 7 (* 10 2) ; => 20 (expt 2 3) ; => 8 (mod 5 2) ; => 1 (/ 35 5) ; => 7 (/ 1 3) ; => 1/3 (+ #C(1 2) #C(6 -4)) ; => #C(7 -2) ;;; Boleanos t ; true; cualquier valor non-NIL es true nil ; false; también, la lista vacia: () (not nil) ; => T (and 0 t) ; => T (or 0 nil) ; => 0 ;;; Caracteres #\A ; => #\A #\λ ; => #\GREEK_SMALL_LETTER_LAMDA #\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA ;;; Cadenas son arreglos de caracteres de longitud fija "Hello, world!" "Benjamin \"Bugsy\" Siegel" ; la barra invertida es un carácter de escape ;;; Las cadenas pueden ser concatenadas (concatenate 'string "Hello, " "world!") ; => "Hello, world!" ;;; Una cadena puede ser tratada como una secuencia de caracteres (elt "Apple" 0) ; => #\A ;;; FORMAT es usado para crear salidas formateadas, va desde simple interpolación de cadenas ;;; hasta bucles y condicionales. El primer argumento de FORMAT determina donde irá la cadena ;;; formateada. Si este es NIL, FORMAT simplemente retorna la cadena formateada como un valor; ;;; si es T, FORMAT imprime a la salida estándar, usualmente la pantalla, luego este retorna NIL. (format nil "~A, ~A!" "Hello" "world") ; => "Hello, world!" (format t "~A, ~A!" "Hello" "world") ; => NIL ;;;----------------------------------------------------------------------------- ;;; 2. Variables ;;;----------------------------------------------------------------------------- ;;; Puedes crear una variable global (ámbito dinámico) usando DEFVAR y DEFPARAMETER ;;; el nombre de la variable puede usar cualquier carácter excepto: ()",'`;#|\ ;;; La diferencia entre DEFVAR y DEFPARAMETER es que reevaluando una expresión ;;; DEFVAR no cambia el valor de la variable. DEFPARAMETER, por otro lado sí lo hace. ;;; Por convención, variables de ámbito dinámico tienen "orejeras" en sus nombres. (defparameter *some-var* 5) *some-var* ; => 5 ;;; Puedes usar también caracteres unicode. (defparameter *AΛB* nil) ;;; Accediendo a una variable sin asignar tienen como resultado el error ;;; UNBOUND-VARIABLE, sin embargo este es el comportamiento definido. no lo hagas ;;; puedes crear enlaces locales con LET. en el siguiente código, `me` es asignado ;;; con "dance with you" solo dentro de (let ...). LET siempre retorna el valor ;;; del último `form`. (let ((me "dance with you")) me) ; => "dance with you" ;;;-----------------------------------------------------------------------------; ;;; 3. Estructuras y colecciones ;;;-----------------------------------------------------------------------------; ;;; Estructuras (defstruct dog name breed age) (defparameter *rover* (make-dog :name "rover" :breed "collie" :age 5)) *rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5) (dog-p *rover*) ; => T (dog-name *rover*) ; => "rover" ;;; DOG-P, MAKE-DOG, y DOG-NAME son creados automáticamente por DEFSTRUCT ;;; Pares ;;; CONS crea pares. CAR y CDR retornan la cabeza y la cola de un CONS-pair (cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB) (car (cons 'SUBJECT 'VERB)) ; => SUBJECT (cdr (cons 'SUBJECT 'VERB)) ; => VERB ;;; Listas ;;; Listas son estructuras de datos de listas enlazadas, hechas de pares CONS y terminan con un ;;; NIL (o '()) para marcar el final de la lista (cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3) ;;; LIST es una forma conveniente de crear listas (list 1 2 3) ; => '(1 2 3) ;;; Cuando el primer argumento de CONS es un atom y el segundo argumento es una lista, ;;; CONS retorna un nuevo par CONS con el primer argumento como el primer elemento y el ;;; segundo argumento como el resto del par CONS (cons 4 '(1 2 3)) ; => '(4 1 2 3) ;;; Use APPEND para unir listas (append '(1 2) '(3 4)) ; => '(1 2 3 4) ;;; o CONCATENATE (concatenate 'list '(1 2) '(3 4)) ; => '(1 2 3 4) ;;; las listas son un tipo de datos centrales en CL, por lo tanto hay una gran variedad ;;; de funcionalidades para ellas, algunos ejemplos son: (mapcar #'1+ '(1 2 3)) ; => '(2 3 4) (mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33) (remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4) (every #'evenp '(1 2 3 4)) ; => NIL (some #'oddp '(1 2 3 4)) ; => T (butlast '(subject verb object)) ; => (SUBJECT VERB) ;;; Vectores ;;; Vectores literales son arreglos de longitud fija #(1 2 3) ; => #(1 2 3) ;;; Use CONCATENATE para juntar vectores (concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) ;;; Arreglos ;;; Vectores y cadenas son casos especiales de arreglos. ;;; Arreglos bidimensionales (make-array (list 2 2)) ; => #2A((0 0) (0 0)) (make-array '(2 2)) ; => #2A((0 0) (0 0)) (make-array (list 2 2 2)) ; => #3A(((0 0) (0 0)) ((0 0) (0 0))) ;;; Precaución: los valores iniciales por defecto de MAKE-ARRAY son implementaciones definidas ;;; para definirlos explícitamente: (make-array '(2) :initial-element 'unset) ; => #(UNSET UNSET) ;;; Para acceder al elemento en 1, 1, 1: (aref (make-array (list 2 2 2)) 1 1 1) ; => 0 ;;; Este valor es definido por implementación: ;;; NIL en ECL, 0 en SBCL and CCL. ;;; vectores ajustables ;;; los vectores ajustables tienen la misma representación en la impresión como los vectores literales ;;; de longitud fija. (defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3) :adjustable t :fill-pointer t)) *adjvec* ; => #(1 2 3) ;;; Agregando nuevos elementos (vector-push-extend 4 *adjvec*) ; => 3 *adjvec* ; => #(1 2 3 4) ;;; Conjuntos, ingenuamente son listas: (set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1) (intersection '(1 2 3 4) '(4 5 6 7)) ; => 4 (union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7) (adjoin 4 '(1 2 3 4)) ; => (1 2 3 4) ;;; Sin embargo, necesitarás una mejor estructura de datos que listas enlazadas ;;; cuando trabajes con conjuntos de datos grandes ;;; Los Diccionarios son implementados como tablas hash. ;;; Crear tablas hash (defparameter *m* (make-hash-table)) ;;; definir valor (setf (gethash 'a *m*) 1) ;;; obtener valor (gethash 'a *m*) ; => 1, T ;;; las expresiones en CL tienen la facultad de retornar multiples valores. (values 1 2) ; => 1, 2 ;;; los cuales pueden ser asignados con MULTIPLE-VALUE-BIND (multiple-value-bind (x y) (values 1 2) (list y x)) ; => '(2 1) ;;; GETHASH es un ejemplo de una función que retorna multiples valores. El primer ;;; valor es el valor de la llave en la tabla hash: si la llave no existe retorna NIL. ;;; El segundo valor determina si la llave existe en la tabla hash. si la llave no existe ;;; en la tabla hash retorna NIL. Este comportamiento permite verificar si el valor de una ;;; llave es actualmente NIL. ;;; Obteniendo un valor no existente retorna NIL (gethash 'd *m*) ;=> NIL, NIL ;;; Puedes declarar un valor por defecto para las llaves inexistentes (gethash 'd *m* :not-found) ; => :NOT-FOUND ;;; Vamos a manejar los multiples valores de retornno en el código. (multiple-value-bind (a b) (gethash 'd *m*) (list a b)) ; => (NIL NIL) (multiple-value-bind (a b) (gethash 'a *m*) (list a b)) ; => (1 T) ;;;----------------------------------------------------------------------------- ;;; 3. Funciones ;;;----------------------------------------------------------------------------- ;;; Use LAMBDA para crear funciones anónimas. las funciones siempre retornan el valor ;;; de la última expresión. la representación imprimible de una función varia entre ;;; implementaciones. (lambda () "Hello World") ; => # ;;; Use FUNCALL para llamar funciones anónimas. (funcall (lambda () "Hello World")) ; => "Hello World" (funcall #'+ 1 2 3) ; => 6 ;;; Un llamado a FUNCALL es también realizado cuando la expresión lambda es el CAR de ;;; una lista. ((lambda () "Hello World")) ; => "Hello World" ((lambda (val) val) "Hello World") ; => "Hello World" ;;; FUNCALL es usado cuando los argumentos son conocidos de antemano. ;;; de lo contrario use APPLY (apply #'+ '(1 2 3)) ; => 6 (apply (lambda () "Hello World") nil) ; => "Hello World" ;;; Para nombrar una funcion use DEFUN (defun hello-world () "Hello World") (hello-world) ; => "Hello World" ;;; Los () en la definición anterior son la lista de argumentos (defun hello (name) (format nil "Hello, ~A" name)) (hello "Steve") ; => "Hello, Steve" ;;; las functiones pueden tener argumentos opcionales; por defecto son NIL (defun hello (name &optional from) (if from (format t "Hello, ~A, from ~A" name from) (format t "Hello, ~A" name))) (hello "Jim" "Alpacas") ; => Hello, Jim, from Alpacas ;;; Los valores por defecto pueden ser especificados (defun hello (name &optional (from "The world")) (format nil "Hello, ~A, from ~A" name from)) (hello "Steve") ; => Hello, Steve, from The world (hello "Steve" "the alpacas") ; => Hello, Steve, from the alpacas ;;; Las funciones también tienen argumentos llaves para permitir argumentos no positionados (defun generalized-greeter (name &key (from "the world") (honorific "Mx")) (format t "Hello, ~A ~A, from ~A" honorific name from)) (generalized-greeter "Jim") ; => Hello, Mx Jim, from the world (generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr") ; => Hello, Mr Jim, from the alpacas you met last summer ;;;----------------------------------------------------------------------------- ;;; 4. Igualdad ;;;----------------------------------------------------------------------------- ;;; CL tiene un sistema sofisticado de igualdad. Una parte es tratada aquí. ;;; Para números use `=` (= 3 3.0) ; => T (= 2 1) ; => NIL ;;; Para identidad de objetos (aproximadamente) use EQL (eql 3 3) ; => T (eql 3 3.0) ; => NIL (eql (list 3) (list 3)) ; => NIL ;;; para listas, cadenas y bit vectores use EQUAL (equal (list 'a 'b) (list 'a 'b)) ; => T (equal (list 'a 'b) (list 'b 'a)) ; => NIL ;;;----------------------------------------------------------------------------- ;;; 5. Control de flujo ;;;----------------------------------------------------------------------------- ;;; Condicionales (if t ; testar expresión "this is true" ; then expression "this is false") ; else expression ; => "this is true" ;;; En condicionales, todo valor non-NIL es tratado como true (member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO) (if (member 'Groucho '(Harpo Groucho Zeppo)) 'yep 'nope) ; => 'YEP ;;; COND en cadena una serie de pruebas para seleccionar un resultado (cond ((> 2 2) (error "wrong!")) ((< 2 2) (error "wrong again!")) (t 'ok)) ; => 'OK ;;; TYPECASE evalua sobre el tipo del valor (typecase 1 (string :string) (integer :int)) ; => :int ;;; Bucles ;;; Recursión (defun fact (n) (if (< n 2) 1 (* n (fact(- n 1))))) (fact 5) ; => 120 ;;; Iteración (defun fact (n) (loop :for result = 1 :then (* result i) :for i :from 2 :to n :finally (return result))) (fact 5) ; => 120 (loop :for x :across "abcd" :collect x) ; => (#\a #\b #\c #\d) (dolist (i '(1 2 3 4)) (format t "~A" i)) ; => 1234 ;;;----------------------------------------------------------------------------- ;;; 6. Mutación ;;;----------------------------------------------------------------------------- ;;; use SETF para asignar un valor nuevo a una variable existente. Esto fue demostrado ;;; previamente en el ejemplo de la tabla hash. (let ((variable 10)) (setf variable 2)) ; => 2 ;;; Un estilo bueno de lisp es minimizar el uso de funciones destructivas y prevenir ;;; la mutación cuando sea posible. ;;;----------------------------------------------------------------------------- ;;; 7. Clases y objetos ;;;----------------------------------------------------------------------------- ;;; No más clases de animales, tengamos transportes mecánicos impulsados por el humano (defclass human-powered-conveyance () ((velocity :accessor velocity :initarg :velocity) (average-efficiency :accessor average-efficiency :initarg :average-efficiency)) (:documentation "A human powered conveyance")) ;;; Los argumentos de DEFCLASS, en orden son: ;;; 1. nombre de la clase ;;; 2. lista de superclases ;;; 3. slot list ;;; 4. Especificadores opcionales ;;; cuando no hay lista de superclase, la lista vacia indica clase de ;;; objeto estándar, esto puede ser cambiado, pero no mientras no sepas ;;; lo que estas haciendo. revisar el arte del protocolo de meta-objetos ;;; para más información. (defclass bicycle (human-powered-conveyance) ((wheel-size :accessor wheel-size :initarg :wheel-size :documentation "Diameter of the wheel.") (height :accessor height :initarg :height))) (defclass recumbent (bicycle) ((chain-type :accessor chain-type :initarg :chain-type))) (defclass unicycle (human-powered-conveyance) nil) (defclass canoe (human-powered-conveyance) ((number-of-rowers :accessor number-of-rowers :initarg :number-of-rowers))) ;;; Invocando DESCRIBE en la clase HUMAN-POWERED-CONVEYANCE en REPL obtenemos: (describe 'human-powered-conveyance) ; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE ; [symbol] ; ; HUMAN-POWERED-CONVEYANCE names the standard-class #: ; Documentation: ; A human powered conveyance ; Direct superclasses: STANDARD-OBJECT ; Direct subclasses: UNICYCLE, BICYCLE, CANOE ; Not yet finalized. ; Direct slots: ; VELOCITY ; Readers: VELOCITY ; Writers: (SETF VELOCITY) ; AVERAGE-EFFICIENCY ; Readers: AVERAGE-EFFICIENCY ; Writers: (SETF AVERAGE-EFFICIENCY) ;;; Tenga en cuenta el comportamiento reflexivo disponible. CL fue diseñado ;;; para ser un systema interactivo ;;; para definir un método, encontremos la circunferencia de la rueda usando ;;; la ecuación C = d * pi (defmethod circumference ((object bicycle)) (* pi (wheel-size object))) ;;; PI es definido internamente en CL ;;; Supongamos que descubrimos que el valor de eficiencia del número de remeros ;;; en una canoa es aproximadamente logarítmico. Esto probablemente debería ;;; establecerse en el constructor / inicializador. ;;; Para inicializar su instancia después de que CL termine de construirla: (defmethod initialize-instance :after ((object canoe) &rest args) (setf (average-efficiency object) (log (1+ (number-of-rowers object))))) ;;; luego para construir una instancia y revisar la eficiencia promedio (average-efficiency (make-instance 'canoe :number-of-rowers 15)) ; => 2.7725887 ;;;----------------------------------------------------------------------------- ;;; 8. Macros ;;;----------------------------------------------------------------------------- ;;; las Macros le permiten extender la sintaxis del lenguaje, CL no viene con ;;; un bucle WHILE, por lo tanto es facil escribirlo, Si obedecemos nuestros ;;; instintos de ensamblador, terminamos con: (defmacro while (condition &body body) "While `condition` is true, `body` is executed. `condition` is tested prior to each execution of `body`" (let ((block-name (gensym)) (done (gensym))) `(tagbody ,block-name (unless ,condition (go ,done)) (progn ,@body) (go ,block-name) ,done))) ;;; revisemos la versión de alto nivel para esto: (defmacro while (condition &body body) "While `condition` is true, `body` is executed. `condition` is tested prior to each execution of `body`" `(loop while ,condition do (progn ,@body))) ;;; Sin embargo, con un compilador moderno, esto no es necesario; El LOOP se ;;; compila igualmente bien y es más fácil de leer. ;;; Tenga en cuenta que se utiliza ```, así como `,` y `@`. ``` es un operador ;;; de tipo de cita conocido como quasiquote; permite el uso de `,` . `,` permite ;;; variables "entre comillas". @ interpola las listas. ;;; GENSYM crea un símbolo único que garantiza que no existe en ninguna otra parte ;;; del sistema. Esto se debe a que las macros se expanden en el momento de la compilación ;;; y las variables declaradas en la macro pueden colisionar con las variables utilizadas ;;; en un código regular. ;;; Consulte Practical Common Lisp y On Lisp para obtener más información sobre macros. ``` ## Otras Lecturas - [Practical Common Lisp](http://www.gigamonkeys.com/book/) - [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf) ## Información extra - [CLiki](http://www.cliki.net/) - [common-lisp.net](https://common-lisp.net/) - [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl) - [Lisp Lang](http://lisp-lang.org/) ================================================ FILE: es/csharp.md ================================================ --- contributors: - ["Irfan Charania", "https://github.com/irfancharania"] - ["Max Yankov", "https://github.com/golergka"] translators: - ["Olfran Jiménez", "https://twitter.com/neslux"] --- C# es un lenguaje orientado a objetos elegante y de tipado seguro que permite a los desarrolladores construir una variedad de aplicaciones seguras y robustas que se ejecutan en el Framework .NET. [Lee más aquí.](http://msdn.microsoft.com/es-es/library/vstudio/z1zx9t92.aspx) ```c# // Los comentarios de una sola línea comienzan con // /* Los comentarios de múltiples líneas son de esta manera */ /// /// Este es un comentario de documentación XML /// // Especifica el espacio de nombres que estará usando la aplicación using System; using System.Collections.Generic; // Define un ambito para organizar el código en "paquetes" namespace Learning { // Cada archivo .cs debe contener al menos una clase con el mismo nombre que el archivo // Se permite colocar cualquier nombre, pero no deberías por cuestiones de consistencia. public class LearnCSharp { // Una aplicación de consola debe tener un método main como punto de entrada public static void Main(string[] args) { // Usa Console.WriteLine para imprimir líneas Console.WriteLine("Hello World"); Console.WriteLine( "Integer: " + 10 + " Double: " + 3.14 + " Boolean: " + true); // Para imprimir sin una nueva línea, usa Console.Write Console.Write("Hello "); Console.Write("World"); /////////////////////////////////////////////////// // Variables y Tipos // // Declara una variable usando /////////////////////////////////////////////////// // Sbyte - Entero de 8 bits con signo // (-128 <= sbyte <= 127) sbyte fooSbyte = 100; // Byte - Entero de 8 bits sin signo // (0 <= byte <= 255) byte fooByte = 100; // Short - Entero de 16 bits con signo // (-32,768 <= short <= 32,767) short fooShort = 10000; // Ushort - Entero de 16 bits sin signo // (0 <= ushort <= 65,535) ushort fooUshort = 10000; // Integer - Entero de 32 bits con signo // (-2,147,483,648 <= int <= 2,147,483,647) int fooInt = 1; // Uinteger - Entero de 32 bits sin signo // (0 <= uint <= 4,294,967,295) uint fooUint = 1; // Long - Entero de 64 bits con signo // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) long fooLong = 100000L; // L es usado para indicar que esta variable es de tipo long o ulong // un valor sin este sufijo es tratado como int o uint dependiendo del tamaño. // Ulong - Entero de 64 bits sin signo // (0 <= ulong <= 18,446,744,073,709,551,615) ulong fooUlong = 100000L; // Float - Precisión simple de 32 bits. IEEE 754 Coma flotante // Precisión: 7 dígitos float fooFloat = 234.5f; // f es usado para indicar que el valor de esta variable es de tipo float // de otra manera sería tratado como si fuera de tipo double. // Double - Doble precisión de 32 bits. IEEE 754 Coma flotante // Precisión: 15-16 dígitos double fooDouble = 123.4; // Bool - true & false (verdadero y falso) bool fooBoolean = true; bool barBoolean = false; // Char - Un solo caracter Unicode de 16 bits char fooChar = 'A'; // Strings string fooString = "My string is here!"; Console.WriteLine(fooString); // Formato de cadenas string fooFs = string.Format("Check Check, {0} {1}, {0} {1:0.0}", 1, 2); Console.WriteLine(fooFormattedString); // Formato de fechas DateTime fooDate = DateTime.Now; Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy")); // \n es un caracter de escape que comienza una nueva línea string barString = "Printing on a new line?\nNo Problem!"; Console.WriteLine(barString); // Puede ser escrito mejor usando el símbolo @ string bazString = @"Here's some stuff on a new line!"; Console.WriteLine(bazString); // Las comillas deben ser escapadas // usa \" para escaparlas string quotedString = "some \"quoted\" stuff"; Console.WriteLine(quotedString); // usa "" cuando las cadenas comiencen con @ string quotedString2 = @"some MORE ""quoted"" stuff"; Console.WriteLine(quotedString2); // Usa const o readonly para hacer las variables inmutables // los valores const son calculados en tiempo de compilación const int HOURS_I_WORK_PER_WEEK = 9001; // Tipos que aceptan valores NULL (Nullable) // cualquier tipo de dato puede ser un tipo nulo añadiendole el sufijo ? // ? = int? nullable = null; Console.WriteLine("Nullable variable: " + nullable); // Para usar valores nulos, tienes que usar la propiedad Value // o usar conversión explícita string? nullableString = "not null"; Console.WriteLine("Nullable value is: " + nullableString.Value + " or: " + (string) nullableString ); // ?? is una manera corta de especificar valores por defecto // en caso de que la variable sea null int notNullable = nullable ?? 0; Console.WriteLine("Not nullable variable: " + notNullable); // var - el compilador escogerá el tipo de dato más apropiado basado en el valor var fooImplicit = true; /////////////////////////////////////////////////// // Estructura de datos /////////////////////////////////////////////////// Console.WriteLine("\n->Data Structures"); // Arreglos // El tamaño del arreglo debe decidirse al momento de la declaración // El formato para declarar un arreglo es el siguiente: // [] = new []; int[] intArray = new int[10]; string[] stringArray = new string[1]; bool[] boolArray = new bool[100]; // Otra forma de declarar e inicializar un arreglo int[] y = { 9000, 1000, 1337 }; // Indexar arreglos - Acceder a un elemento Console.WriteLine("intArray @ 0: " + intArray[0]); // Los arreglos son de índice cero y son mutables. intArray[1] = 1; Console.WriteLine("intArray @ 1: " + intArray[1]); // => 1 // Listas // Las listas son usadas más frecuentemente que los arreglos ya que son más flexibles // El formato para declarar una lista es el siguiente: // List = new List(); List intList = new List(); List stringList = new List(); // Otra forma de declarar e inicializar una lista List z = new List { 9000, 1000, 1337 }; // Indexar una lista - Acceder a un elemento // Las listas son de índice cero y son mutables. Console.WriteLine("z @ 0: " + z[2]); // Las listas no tienen valores por defecto; // Un valor debe ser añadido antes de acceder al índice intList.Add(1); Console.WriteLine("intList @ 0: " + intList[0]); // Otras estructuras de datos a chequear: // // Pilas/Colas // Diccionarios // Colecciones de sólo lectura // Tuplas (.Net 4+) /////////////////////////////////////// // Operadores /////////////////////////////////////// Console.WriteLine("\n->Operators"); int i1 = 1, i2 = 2; // Modo corto para múltiples declaraciones // La aritmética es sencilla Console.WriteLine("1+2 = " + (i1 + i2)); // => 3 Console.WriteLine("2-1 = " + (i2 - i1)); // => 1 Console.WriteLine("2*1 = " + (i2 * i1)); // => 2 Console.WriteLine("1/2 = " + (i1 / i2)); // => 0 (0.5 truncated down) // Módulo Console.WriteLine("11%3 = " + (11 % 3)); // => 2 // Operadores de comparación Console.WriteLine("3 == 2? " + (3 == 2)); // => false Console.WriteLine("3 != 2? " + (3 != 2)); // => true Console.WriteLine("3 > 2? " + (3 > 2)); // => true Console.WriteLine("3 < 2? " + (3 < 2)); // => false Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true // Operadores a nivel de bits /* ~ Complemento a nivel de bits << Desplazamiento a la izquierda con signo >> Desplazamiento a la derecha con signo >>> Desplazamiento a la derecha sin signo & AND a nivel de bits ^ XOR a nivel de bits | OR a nivel de bits */ // Incremento int i = 0; Console.WriteLine("\n->Inc/Dec-remento"); Console.WriteLine(i++); //i = 1. Posincrementación Console.WriteLine(++i); //i = 2. Preincremento Console.WriteLine(i--); //i = 1. Posdecremento Console.WriteLine(--i); //i = 0. Predecremento /////////////////////////////////////// // Estructuras de control /////////////////////////////////////// Console.WriteLine("\n->Control Structures"); // Las condiciones if son como en lenguaje c int j = 10; if (j == 10) { Console.WriteLine("I get printed"); } else if (j > 10) { Console.WriteLine("I don't"); } else { Console.WriteLine("I also don't"); } // Operador ternario // Un simple if/else puede ser escrito de la siguiente manera; // ? : string isTrue = (true) ? "True" : "False"; Console.WriteLine("Ternary demo: " + isTrue); // Bucle while int fooWhile = 0; while (fooWhile < 100) { //Console.WriteLine(fooWhile); //Incrementar el contador //Iterar 99 veces, fooWhile 0->99 fooWhile++; } Console.WriteLine("fooWhile Value: " + fooWhile); // Bucle Do While int fooDoWhile = 0; do { //Console.WriteLine(fooDoWhile); //Incrementar el contador //Iterar 99 veces, fooDoWhile 0->99 fooDoWhile++; } while (fooDoWhile < 100); Console.WriteLine("fooDoWhile Value: " + fooDoWhile); // Bucle For int fooFor; //Estructura del bucle for => for(; ; ) for (fooFor = 0; fooFor < 10; fooFor++) { //Console.WriteLine(fooFor); //Iterated 10 times, fooFor 0->9 } Console.WriteLine("fooFor Value: " + fooFor); // Switch Case // El switch funciona con los tipos de datos byte, short, char e int // También funciona con las enumeraciones (discutidos en in Tipos Enum), // la clase string y algunas clases especiales que encapsulan // tipos primitivos: Character, Byte, Short, Integer. int month = 3; string monthString; switch (month) { case 1: monthString = "January"; break; case 2: monthString = "February"; break; case 3: monthString = "March"; break; default: monthString = "Some other month"; break; } Console.WriteLine("Switch Case Result: " + monthString); //////////////////////////////// // Conversión de tipos de datos //////////////////////////////// // Convertir datos // Convertir String a Integer // esto generará una excepción al fallar la conversión int.Parse("123");//retorna una versión entera de "123" // TryParse establece la variable a un tipo por defecto // en este caso: 0 int tryInt; int.TryParse("123", out tryInt); // Convertir Integer a String // La clase Convert tiene algunos métodos para facilitar las conversiones Convert.ToString(123); /////////////////////////////////////// // Clases y Funciones /////////////////////////////////////// Console.WriteLine("\n->Classes & Functions"); // (Definición de la clase Bicycle (Bicicleta)) // Usar new para instanciar una clase Bicycle trek = new Bicycle(); // Llamar a los métodos del objeto trek.speedUp(3); // Siempre deberías usar métodos setter y métodos getter trek.setCadence(100); // ToString es una convención para mostrar el valor del objeto. Console.WriteLine("trek info: " + trek.ToString()); // Instanciar otra nueva bicicleta Bicycle octo = new Bicycle(5, 10); Console.WriteLine("octo info: " + octo.ToString()); // Instanciar un Penny Farthing (Biciclo) PennyFarthing funbike = new PennyFarthing(1, 10); Console.WriteLine("funbike info: " + funbike.ToString()); Console.Read(); } // Fin del método main } // Fin de la clase LearnCSharp // Puedes incluir otras clases en un archivo .cs // Sintaxis para la declaración de clases: // class { // //campos, constructores, funciones todo adentro de la clase. // //las funciones son llamadas métodos como en java. // } public class Bicycle { // Campos/Variables de la clase Bicycle public int cadence; // Public: Accesible desde cualquier lado private int _speed; // Private: Sólo es accesible desde dentro de la clase protected int gear; // Protected: Accesible desde clases y subclases internal int wheels; // Internal: Accesible en el ensamblado string name; // Todo es privado por defecto: Sólo es accesible desde dentro de esta clase // Enum es un tipo valor que consiste un una serie de constantes con nombres public enum Brand { AIST, BMC, Electra, Gitane } // Definimos este tipo dentro de la clase Bicycle, por lo tanto es un tipo anidado // El código afuera de esta clase debería referenciar este tipo como Bicycle.Brand public Brand brand; // Declaramos un tipo enum, podemos declarar un campo de este tipo // Los miembros estáticos pertenecen al tipo mismo, no a un objeto en específico. static public int bicyclesCreated = 0; // Puedes acceder a ellos sin referenciar ningún objeto: // Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated); // Los valores readonly (Sólo lectura) son establecidos en tiempo de ejecución // sólo pueden ser asignados al momento de la declaración o dentro de un constructor readonly bool hasCardsInSpokes = false; // privado de sólo lectura // Los constructores son una forma de crear clases // Este es un constructor por defecto private Bicycle() { gear = 1; cadence = 50; _speed = 5; name = "Bontrager"; brand = Brand.AIST; bicyclesCreated++; } // Este es un constructor específico (contiene argumentos) public Bicycle(int startCadence, int startSpeed, int startGear, string name, bool hasCardsInSpokes, Brand brand) { this.gear = startGear; // La palabra reservada "this" señala el objeto actual this.cadence = startCadence; this._speed = startSpeed; this.name = name; // Puede ser útil cuando hay un conflicto de nombres this.hasCardsInSpokes = hasCardsInSpokes; this.brand = brand; } // Los constructores pueden ser encadenados public Bicycle(int startCadence, int startSpeed, Brand brand) : this(startCadence, startSpeed, 0, "big wheels", true) { } // Sintaxis para Funciones: // () // Las clases pueden implementar getters y setters para sus campos // o pueden implementar propiedades // Sintaxis para la declaración de métodos: // <ámbito> () public int GetCadence() { return cadence; } // Los métodos void no requieren usar return public void SetCadence(int newValue) { cadence = newValue; } // La palabra reservada virtual indica que este método puede ser sobrescrito public virtual void SetGear(int newValue) { gear = newValue; } // Los parámetros de un método pueden tener valores por defecto. // En este caso, los métodos pueden ser llamados omitiendo esos parámetros public void SpeedUp(int increment = 1) { _speed += increment; } public void SlowDown(int decrement = 1) { _speed -= decrement; } // Propiedades y valores get/set // Cuando los datos sólo necesitan ser accedidos, considera usar propiedades. // Las propiedades pueden tener get, set o ambos private bool _hasTassles; // variable privada public bool HasTassles // acceso público { get { return _hasTassles; } set { _hasTassles = value; } } // Las propiedades pueden ser auto implementadas public int FrameSize { get; // Puedes especificar modificadores de acceso tanto para get como para set // esto significa que sólo dentro de la clase Bicycle se puede modificar Framesize private set; } //Método para mostrar los valores de atributos de este objeto. public override string ToString() { return "gear: " + gear + " cadence: " + cadence + " speed: " + _speed + " name: " + name + " cards in spokes: " + (hasCardsInSpokes ? "yes" : "no") + "\n------------------------------\n" ; } // Los métodos también pueden ser estáticos. Puede ser útil para métodos de ayuda public static bool DidWeCreateEnoughBycles() { // Dentro de un método esático, // Sólo podemos hacer referencia a miembros estáticos de clases return bicyclesCreated > 9000; } // Si tu clase sólo necesita miembros estáticos, // considera establecer la clase como static. } // fin de la clase Bicycle // PennyFarthing es una subclase de Bicycle class PennyFarthing : Bicycle { // (Penny Farthings son las bicicletas con una rueda delantera enorme. // No tienen engranajes.) // llamar al constructor de la clase padre public PennyFarthing(int startCadence, int startSpeed) : base(startCadence, startSpeed, 0, "PennyFarthing", true) { } public override void SetGear(int gear) { gear = 0; } public override string ToString() { string result = "PennyFarthing bicycle "; result += base.ToString(); // Llamar a la versión base del método return reuslt; } } // Las interfaces sólo contienen las declaraciones // de los miembros, sin la implementación. interface IJumpable { void Jump(int meters); // todos los miembros de interfaces son implícitamente públicos } interface IBreakable { // Las interfaces pueden contener tanto propiedades como métodos, campos y eventos bool Broken { get; } } // Las clases sólo heredan de alguna otra clase, pero pueden implementar // cualquier cantidad de interfaces class MountainBike : Bicycle, IJumpable, IBreakable { int damage = 0; public void Jump(int meters) { damage += meters; } public void Broken { get { return damage > 100; } } } } // Fin del espacio de nombres ``` ## Temas no cubiertos * Flags * Attributes * Generics (T), Delegates, Func, Actions, lambda expressions * Static properties * Exceptions, Abstraction * LINQ * ASP.NET (Web Forms/MVC/WebMatrix) * Winforms * Windows Presentation Foundation (WPF) ## Lecturas recomendadas * [DotNetPerls](http://www.dotnetperls.com) * [C# in Depth](http://manning.com/skeet2) * [Programming C#](http://shop.oreilly.com/product/0636920024064.do) * [LINQ](http://shop.oreilly.com/product/9780596519254.do) * [MSDN Library](http://msdn.microsoft.com/es-es/library/618ayhy6.aspx) * [ASP.NET MVC Tutorials](http://www.asp.net/mvc/tutorials) * [ASP.NET Web Matrix Tutorials](http://www.asp.net/web-pages/tutorials) * [ASP.NET Web Forms Tutorials](http://www.asp.net/web-forms/tutorials) * [Windows Forms Programming in C#](http://www.amazon.com/Windows-Forms-Programming-Chris-Sells/dp/0321116208) [Convenciones de código de C#](http://msdn.microsoft.com/es-es/library/vstudio/ff926074.aspx) ================================================ FILE: es/css.md ================================================ --- contributors: - ["Mohammad Valipour", "https://github.com/mvalipour"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["Geoffrey Liu", "https://github.com/g-liu"] - ["Connor Shea", "https://github.com/connorshea"] - ["Deepanshu Utkarsh", "https://github.com/duci9y"] - ["Brett Taylor", "https://github.com/glutnix"] - ["Tyler Mumford", "https://tylermumford.com"] translators: - ["miky ackerman", "https://github.com/mikyackerman"] --- Paginas web estan contruidas en HTML, lo cual especifica el contenido de una pagina CSS(Hoja de Estilos en Cascada) es un lenguaje separado el cual especifica la **apariencia** de una pagina. codigo CSS esta hecho de *reglas* estaticas. Cada regla toma uno o mas *selectores* y da *valores* especificos a un numero de *propiedades* visuales. Esas propiedades estan entonces aplicadas a los elementos indicados en una pagina por los selectores Esta guia ha sido escrita con CSS 2 en mente, la cual es extendida por una nueva caracterica de CSS 3. **NOTA:** Debido a que CSS produce resultados visuales, para aprenderlo, necesitas Probar todo en un patio de juegos CSS como [dabblet](http://dabblet.com/). El objetivo principal de este artículo es la sintaxis y algunos consejos generales. ## Sintaxis ```css /* Los comentarios aparecen dentro de un diagonal-asterisco, justo como esta linea no hay "comentarios en una linea"; este es el unico estilo de comentario.*/ /* #################### ## SELECTORS #################### */ /* el selector es usado para apuntar a un elemento de la pagina. */ selector { property: value; /* more properties...*/ } /* Here is an example element:
*/ /* You can target it using one of its CSS classes */ .class1 { } /* or both classes! */ .class1.class2 { } /* or its name */ div { } /* or its id */ #anID { } /* or using the fact that it has an attribute! */ [attr] { font-size:smaller; } /* or that the attribute has a specific value */ [attr='value'] { font-size:smaller; } /* starts with a value (CSS 3) */ [attr^='val'] { font-size:smaller; } /* or ends with a value (CSS 3) */ [attr$='ue'] { font-size:smaller; } /* or contains a value in a space-separated list */ [otherAttr~='foo'] { } [otherAttr~='bar'] { } /* or contains a value in a dash-separated list, e.g., "-" (U+002D) */ [otherAttr|='en'] { font-size:smaller; } /* You can combine different selectors to create a more focused selector. Don't put spaces between them. */ div.some-class[attr$='ue'] { } /* You can select an element which is a child of another element */ div.some-parent > .class-name { } /* or a descendant of another element. Children are the direct descendants of their parent element, only one level down the tree. Descendants can be any level down the tree. */ div.some-parent .class-name { } /* Warning: the same selector without a space has another meaning. Can you guess what? */ div.some-parent.class-name { } /* You may also select an element based on its adjacent sibling */ .i-am-just-before + .this-element { } /* or any sibling preceding it */ .i-am-any-element-before ~ .this-element { } /* There are some selectors called pseudo classes that can be used to select an element only when it is in a particular state */ /* for example, when the cursor hovers over an element */ selector:hover { } /* or a link has been visited */ selector:visited { } /* or hasn't been visited */ selected:link { } /* or an element is in focus */ selected:focus { } /* any element that is the first child of its parent */ selector:first-child {} /* any element that is the last child of its parent */ selector:last-child {} /* Just like pseudo classes, pseudo elements allow you to style certain parts of a document */ /* matches a virtual first child of the selected element */ selector::before {} /* matches a virtual last child of the selected element */ selector::after {} /* At appropriate places, an asterisk may be used as a wildcard to select every element */ * { } /* all elements */ .parent * { } /* all descendants */ .parent > * { } /* all children */ /* #################### ## PROPERTIES #################### */ selector { /* Units of length can be absolute or relative. */ /* Relative units */ width: 50%; /* percentage of parent element width */ font-size: 2em; /* multiples of element's original font-size */ font-size: 2rem; /* or the root element's font-size */ font-size: 2vw; /* multiples of 1% of the viewport's width (CSS 3) */ font-size: 2vh; /* or its height */ font-size: 2vmin; /* whichever of a vh or a vw is smaller */ font-size: 2vmax; /* or greater */ /* Absolute units */ width: 200px; /* pixels */ font-size: 20pt; /* points */ width: 5cm; /* centimeters */ min-width: 50mm; /* millimeters */ max-width: 5in; /* inches */ /* Colors */ color: #F6E; /* short hex format */ color: #FF66EE; /* long hex format */ color: tomato; /* a named color */ color: rgb(255, 255, 255); /* as rgb values */ color: rgb(10%, 20%, 50%); /* as rgb percentages */ color: rgba(255, 0, 0, 0.3); /* as rgba values (CSS 3) Note: 0 <= a <= 1 */ color: transparent; /* equivalent to setting the alpha to 0 */ color: hsl(0, 100%, 50%); /* as hsl percentages (CSS 3) */ color: hsla(0, 100%, 50%, 0.3); /* as hsl percentages with alpha */ /* Borders */ border-width:5px; border-style:solid; border-color:red; /* similar to how background-color is set */ border: 5px solid red; /* this is a short hand approach for the same */ border-radius:20px; /* this is a CSS3 property */ /* Images as backgrounds of elements */ background-image: url(/img-path/img.jpg); /* quotes inside url() optional */ /* Fonts */ font-family: Arial; /* if the font family name has a space, it must be quoted */ font-family: "Courier New"; /* if the first one is not found, the browser uses the next, and so on */ font-family: "Courier New", Trebuchet, Arial, sans-serif; } ``` ## Usage Save a CSS stylesheet with the extension `.css`. ```html
``` ## Precedence or Cascade An element may be targeted by multiple selectors and may have a property set on it in more than once. In these cases, one of the rules takes precedence over others. Rules with a more specific selector take precedence over a less specific one, and a rule occurring later in the stylesheet overwrites a previous one (which also means that if two different linked stylesheets contain rules for an element and if the rules are of the same specificity, then order of linking would take precedence and the sheet linked latest would govern styling) . This process is called cascading, hence the name Cascading Style Sheets. Given the following CSS: ```css /* A */ p.class1[attr='value'] /* B */ p.class1 { } /* C */ p.class2 { } /* D */ p { } /* E */ p { property: value !important; } ``` and the following markup: ```html

``` The precedence of style is as follows. Remember, the precedence is for each **property**, not for the entire block. * `E` has the highest precedence because of the keyword `!important`. It is recommended that you avoid its usage. * `F` is next, because it is an inline style. * `A` is next, because it is more "specific" than anything else. It has 3 specifiers: The name of the element `p`, its class `class1`, an attribute `attr='value'`. * `C` is next, even though it has the same specificity as `B`. This is because it appears after `B`. * `B` is next. * `D` is the last one. ## Media Queries CSS Media Queries are a feature in CSS 3 which allows you to specify when certain CSS rules should be applied, such as when printed, or when on a screen with certain dimensions or pixel density. They do not add to the selector's specificity. ```css /* A rule that will be used on all devices */ h1 { font-size: 2em; color: white; background-color: black; } /* change the h1 to use less ink on a printer */ @media print { h1 { color: black; background-color: white; } } /* make the font bigger when shown on a screen at least 480px wide */ @media screen and (min-width: 480px) { h1 { font-size: 3em; font-weight: normal; } } ``` Media queries can include these features: `width`, `height`, `device-width`, `device-height`, `orientation`, `aspect-ratio`, `device-aspect-ratio`, `color`, `color-index`, `monochrome`, `resolution`, `scan`, `grid`. Most of these features can be prefixed with `min-` or `max-`. The `resolution` feature is not supported by older devices, instead use `device-pixel-ratio`. Many smartphones and tablets will attempt to render the page as if it were on a desktop unless you provide a `viewport` meta-tag. ```html ``` ## Compatibility Most of the features in CSS 2 (and many in CSS 3) are available across all browsers and devices. But it's always good practice to check before using a new feature. ## Resources * [CanIUse](http://caniuse.com) (Detailed compatibility info) * [Dabblet](http://dabblet.com/) (CSS playground) * [Mozilla Developer Network's CSS documentation](https://developer.mozilla.org/en-US/docs/Web/CSS) (Tutorials and reference) * [Codrops' CSS Reference](http://tympanus.net/codrops/css_reference/) (Reference) ## Further Reading * [Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade](http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/) * [Selecting elements using attributes](https://css-tricks.com/almanac/selectors/a/attribute/) * [QuirksMode CSS](http://www.quirksmode.org/css/) * [Z-Index - The stacking context](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context) * [SASS](http://sass-lang.com/) and [LESS](http://lesscss.org/) for CSS pre-processing * [CSS-Tricks](https://css-tricks.com) ================================================ FILE: es/csv.md ================================================ --- name: CSV contributors: - [Timon Erhart, 'https://github.com/turbotimon/'] translators: - [Luis Morales, 'https://github.com/LewisPons'] --- CSV (valores separados por comas) es un formato de archivo ligero que se utiliza para almacenar datos tabulares en texto plano, diseñado para facilitar el intercambio de datos entre programas, especialmente hojas de cálculo y bases de datos. Su simplicidad y legibilidad humana lo han convertido en una piedra angular de la interoperabilidad de datos. A menudo se utiliza para mover datos entre programas con formatos incompatibles o propietarios. Aunque el RFC 4180 proporciona un estándar para el formato, en la práctica, el término "CSV" se utiliza a menudo de forma más amplia para referirse a cualquier archivo de texto que: - Se pueda interpretar como datos tabulares - Utilice un delimitador para separar los campos (columnas) - Utilice saltos de línea para separar los registros (filas) - Opcionalmente incluya una cabecera en la primera fila ```csv Nombre, Edad, FechaDeNacimiento Alice, 30, 1993-05-14 Bob, 25, 1998-11-02 Charlie, 35, 1988-03-21 ``` ## Delimitadores para filas y columnas Las filas se separan normalmente con saltos de línea (`\n` o `\r\n`), mientras que las columnas (campos) se separan con un delimitador específico. Aunque las comas son el delimitador más común para los campos, otros caracteres, como el punto y coma (`;`), se utilizan comúnmente en regiones donde las comas son separadores decimales (por ejemplo, Alemania). Los tabuladores (`\t`) también se utilizan como delimitadores en algunos casos, y estos archivos a menudo se denominan "TSV" (valores separados por tabuladores). Ejemplo usando punto y coma como delimitador y coma para el separador decimal: ```csv Nombre; Edad; Nota Alice; 30; 50,50 Bob; 25; 45,75 Charlie; 35; 60,00 ``` ## Tipos de datos Los archivos CSV no definen inherentemente los tipos de datos. Los números y las fechas se almacenan como texto plano, y su interpretación depende del software que importa el archivo. Normalmente, los datos se interpretan de la siguiente manera: ```csv Dato, Comentario 100, Interpretado como un número (entero) 100.00, Interpretado como un número (punto flotante) 2024-12-03, Interpretado como una fecha o una cadena (dependiendo del analizador) Hola Mundo, Interpretado como texto (cadena) "1234", Interpretado como texto en lugar de un número ``` ## Entrecomillado de cadenas y caracteres especiales El entrecomillado de cadenas solo es necesario si la cadena contiene el delimitador, caracteres especiales, o si de otra manera podría ser interpretada como un número. Sin embargo, a menudo se considera una buena práctica entrecomillar todas las cadenas para mejorar la legibilidad y robustez. ```csv Ejemplos de entrecomillado de cadenas, Cadena sin comillas, "Cadena opcionalmente entrecomillada (buena práctica)", "Si contiene el delimitador, necesita ser entrecomillada", "También, si contiene caracteres especiales como \n saltos de línea o \t tabuladores", "El propio carácter de entrecomillado "" normalmente se escapa duplicando la comilla ("""")", "o en algunos sistemas con una barra invertida \" (como otros escapes)", ``` Sin embargo, asegúrese de que para un documento, el método de entrecomillado sea consistente. Por ejemplo, los dos últimos ejemplos de entrecomillado con "" o \" no serían consistentes y podrían causar problemas. ## Codificación Se utilizan diferentes codificaciones. La mayoría de los archivos CSV modernos utilizan la codificación UTF-8, pero los sistemas más antiguos podrían utilizar otras como ASCII o ISO-8859. Si el archivo se transfiere o comparte entre diferentes sistemas, es una buena práctica definir explícitamente la codificación utilizada, para evitar problemas con la malinterpretación de caracteres. ## Más recursos - [Wikipedia](https://es.wikipedia.org/wiki/Valores_separados_por_comas) - [RFC 4180](https://datatracker.ietf.org/doc/html/rfc4180) ================================================ FILE: es/curto.md ================================================ --- name: curto contributors: - ["Maleza", "https://maleza.srht.site/"] filename: learncurto.fs --- Curto es una traducción completa al español de [UF Forth](http://www.call-with-current-continuation.org/uf/uf.html) (de Felix Winkelmann), un Forth para la [Máquina Virtual UXN](https://wiki.xxiivv.com/site/uxn.html). ``` \ Este es un comentario ( Este es un comentario también pero solo es usado en definiciones de palabras. ) \ --------------------------------- La Pila ---------------------------------- \ Todo programación en Curto se hace manipulando la pila de parámetros \ (habitualmente referida como "la pila"). 5 2 3 56 76 23 65 \ ok \ estos números se añadieron a la pila de izquierda a derecha. .s \ <7> 5 2 3 56 76 23 65 ok \ En Forth, todo es o una palabra o un número. \ ------------------------------ Aritmética Básica ------------------------------ \ La aritmética (de hecho casi todas palabras que requieren datos) funciona manipulando datos \ en el pila. 5 4 + \ ok \ `.` saca el resultado del tope de la pila: . \ 9 ok \ Mas ejemplos de aritmética: 6 7 * . \ 42 ok 1360 23 - . \ 1337 ok 12 12 / . \ 1 ok 13 2 mod . \ 1 ok 99 negate . \ -99 ok -99 abs . \ 99 ok 52 23 max . \ 52 ok 52 23 min . \ 23 ok \ ----------------------------- Manipulación de Pila ----------------------------- \ Naturalmente, cuando trabajaremos con la pila, querremos algunos métodos útiles: 3 dup - \ duplica el primer valor (1ra ahora igual a 2da): 3 - 3 2 5 cambiar / \ intercambia primer y segundo valor: 5 / 2 6 4 5 rot .p \ rota los tres primeros valores: 4 5 6 4 0 soltar 2 / \ suelta el primer valor (no imprime a pantalla): 4 / 2 1 2 3 pellizcar .p \ suelta el segundo valor (similar a soltar): 1 3 \ ---------------------- Manipulación de Pila Más Avanzada ---------------------- 1 2 3 4 plegar \ duplicar el primer valor debajo del segundo: 1 2 4 3 4 ok 1 2 3 4 encima \ empuja segundo valor de la pila: 1 2 3 4 3 ok 1 2 3 4 2 elegir \ duplica el valor en esta posición al tope de la pila: 1 2 3 4 2 ok \ Los índices de la pila son basados en cero. \ ------------------------------ Creando Palabras -------------------------------- \ La palabra `:` hace que Curto entre en modo compilar hasta que se ve la palabra `;`. : cuadrado ( n -- n ) dup * ; \ ok 5 cuadrado . \ 25 ok \ También podemos ver lo que hace una palabra (código uxntal al que fué compilada): ver cuadrado \ DUP2 MUL2 JMP2r ok \ -------------------------------- Condicionales -------------------------------- \ -1 == verdadero, 0 == falso. No obstante, cualquier valor distinto de cero es \ considerado verdadero: 42 42 = \ -1 ok 12 53 = \ 0 ok \ `si` es una palabra solo de compilación. `si` `entonces` . : ?>64 ( n -- n ) dup 64 > si ." Mas que 64!" entonces ; \ ok 100 ?>64 \ Mas que 64! ok \ `sino`: : ?>64 ( n -- n ) dup 64 > si ." Mas que 64!" sino ." Menos que 64!" entonces ; 100 ?>64 \ Mas que 64! ok 20 ?>64 \ Menos que 64! ok \ ------------------------------------ Bucles ----------------------------------- \ `hacer` también es una palabra solo de compilación. : miloop ( -- ) 5 0 hacer rc ." Hola!" bucle ; \ ok miloop \ Hola! \ Hola! \ Hola! \ Hola! \ Hola! ok \ `hacer` espera dos números en el pila: el de incicio y el de terminación. \ Podemos recibir el valor del indice mientras iteramos con `i`: : uno-a-12 ( -- ) 13 1 hacer i . bucle ; \ ok uno-a-12 \ 0 1 2 3 4 5 6 7 8 9 10 11 12 ok \ `?hacer` funciona similarmente, pero salta el loop si el último y el primer \ número son iguales. : cuadrados ( n -- ) 0 ?hacer i cuadrado . bucle ; \ ok 10 cuadrados \ 0 1 4 9 16 25 36 49 64 81 ok \ cambiar el "paso" con `+bucle`: : treces ( n n -- ) ?hacer i . 3 +bucle ; \ ok 15 0 treces \ 0 3 6 9 12 ok \ Los bucles indefinidos comienzan con `empezar` `hasta`: : death ( -- ) empezar ." Ya hemos llegado?" 0 hasta ; \ ok \ ---------------------------- Constantes, Variables y Memoria ---------------------------- \ Declara una constante `dedos` igual a 5 5 constante dedos dedos . \ 5 ok \ Crea la variable `edad`. variable edad \ ok \ Ahora escribimos 21 a edad con la palabra `!`. 21 edad ! \ ok \ Podemos imprimir nuestra variable usando la palabra leer `@`, que empuja el \ valor a la pila, o `?` que lee e imprime en un solo paso. edad @ . \ 21 ok edad ? \ 21 ok \ ----------------------------------- Arreglos ----------------------------------- \ Crear arreglos es similar a crear variables, pero necesitamos alocar mas \ memoria para ellos. \ Podemos usar `2 celdas alocar` para crear un arreglo que sea de 3 celdas de tamaño: variable misnumeros 2 celdas alocar \ ok \ Inicializar todos los valores a 0 misnumeros 3 celdas borrar \ ok \ Alternativamente podemos usar `llenar`: misnumeros 3 celdas 0 llenar \ o podemos saltearnos todo lo anterior e inicializar con valores específicos: crear misnumeros 64 , 9001 , 1337 , \ ok (la última `,` es importante!) \ ...que es equivalente a: \ Manualmente escribir valores a cada indice: 64 misnumeros 0 celdas + ! \ ok 9001 misnumeros 1 celdas + ! \ ok 1337 misnumeros 2 celdas + ! \ ok \ Leyendo valores de un índice en particular: 0 celdas misnumeros + ? \ 64 ok 1 celdas misnumeros + ? \ 9001 ok \ Podemos simplificar un poco creando una palabra que ayuda a manipular arreglos: : de-arr ( n n -- n ) celdas + ; \ ok misnumeros 2 de-arr ? \ 1337 ok \ Que podemos usar cuando escribimos también: 20 misnumeros 1 de-arr ! \ ok misnumeros 1 de-arr ? \ 20 ok \ ------------------------------ La Pila de Retorno ------------------------------ \ La pila de retorno se usa para retener punteros a cosas cuando las palabras están \ ejecutando otras palabras como en los bucles. \ Ya hemos visto un uso de esto: `i`, que duplica el tope de la pila \ de retorno. `i` es equivalente a `r@`. : mibucle ( -- ) 5 0 hacer r@ . bucle ; \ ok \ También podemos agregar y retirar de la pila de retorno: 5 6 4 >r swap r> .p \ 6 5 4 ok \ NOTA: Como Curto usa la pila de retorno para retornar a palabras, `>r` debe \ siempre ser seguido por un `r>`. \ --------------------------------- Notas al Final -------------------------------- \ Usar una palabra que no existe vaciara la pila. No obstante, también hay una palabra \ específicamente para esto: limpiar \ vaciar la pantalla: pagina \ Cargando archivos Curto: \ c" archivodeforth.fs" incluido \ Puede listar cada palabra en el diccionario de Curto (pero es una lista gigante!): palabras \ Terminando Curto: chau ``` ## Listo Para Mas? * [README](https://git.sr.ht/~maleza/curto/tree/curto/item/README) * [GLOSARIO](https://git.sr.ht/~maleza/curto/tree/curto/item/GLOSARIO) ================================================ FILE: es/dart.md ================================================ --- contributors: - ["Joao Pedrosa", "https://github.com/jpedrosa/"] translators: - ["Jorge Antonio Atempa", "http://www.twitter.com/atempa09"] --- Dart es un recién llegado al ámbito de los lenguajes de programación. Toma prestado mucho de otros lenguajes principales, con el objetivo de no desviarse demasiado de su hermano JavaScript. Tal como JavaScript, Dart tiene como objetivo una gran integración en el navegador. La característica más controvertida de Dart debe ser su escritura opcional. ```dart import "dart:collection"; import "dart:math" as DM; // Bienvenido a Aprende Dart en 15 minutos. http://www.dartlang.org/ // Este es un tutorial ejecutable. Puedes ejecutarlo con Dart o en // el sitio de ¡Try Dart! solo copiando y pegando en http://try.dartlang.org/ // La declaración de función y de método tienen el mismo aspecto. // Las funciones pueden estar anidadas. // La declaración toma la forma name() {} o name() => expresionEnUnaLinea; // La declaración de la función de flecha gorda, tiene un retorno implícito // para el resultado de la expresión. example1() { nested1() { nested2() => print("example1 anidado 1 anidado 2"); nested2(); } nested1(); } // Las funciones anónimas no incluyen un nombre. example2() { nested1(fn) { fn(); } nested1(() => print("example2 anidado 1")); } // Cuando se declara un parámetro de función, la declaración puede incluir el // número de parámetros que toma la función especificando los nombres de los // parámetros que lleva. example3() { planA(fn(informSomething)) { fn("example3 plan A"); } planB(fn) { // O no declarar el número de parámetros. fn("example3 plan B"); } planA((s) => print(s)); planB((s) => print(s)); } // Las funciones tienen acceso de cierre a variables externas. var example4Something = "Example4 anidado 1"; example4() { nested1(fn(informSomething)) { fn(example4Something); } nested1((s) => print(s)); } // La declaración de la clase con un método sayIt, el cual también tiene acceso de cierre // a la variable exterior como si fuera una función como se ha visto antes. var example5method = "example5 sayIt"; class Example5Class { sayIt() { print(example5method); } } example5() { // Crear una instancia anónima de Example5Class y la llamada del método sayIt new Example5Class().sayIt(); } // La declaración de clase toma la forma NombreDeClase { [cuerpoDeClase] }. // Donde cuerpoDeClase puede incluir métodos de instancia y variables, pero también // métodos y variables de clase. class Example6Class { var instanceVariable = "Example6 variable de instancia"; sayIt() { print(instanceVariable); } } example6() { new Example6Class().sayIt(); } // Los métodos y variables de clase son declarados con términos "static". class Example7Class { static var classVariable = "Example7 variable de clase"; static sayItFromClass() { print(classVariable); } sayItFromInstance() { print(classVariable); } } example7() { Example7Class.sayItFromClass(); new Example7Class().sayItFromInstance(); } // Las literales son geniales, pero hay una restricción para lo que pueden ser las literales // fuera de los cuerpos de función/método. Literales en el ámbito exterior de clase // o fuera de clase tienen que ser constantes. Las cadenas de caracteres y los números // son constantes por defecto. Pero los arreglos y mapas no lo son. // Ellos pueden hacerse constante anteponiendo en la declaración el término "const". var example8Array = const ["Example8 arreglo constante"], example8Map = const {"algunaKey": "Example8 mapa constante"}; example8() { print(example8Array[0]); print(example8Map["algunaKey"]); } // Los bucles en Dart toman la forma estándar para for () {} o ciclos while () {} , // ligeramente más moderno for (.. in ..) {}, o llamadas funcionales con muchas // características soportadas, comenzando con forEach. var example9Array = const ["a", "b"]; example9() { for (var i = 0; i < example9Array.length; i++) { print("example9 ciclo for '${example9Array[i]}'"); } var i = 0; while (i < example9Array.length) { print("example9 ciclo while '${example9Array[i]}'"); i++; } for (var e in example9Array) { print("example9 ciclo for-in '${e}'"); } example9Array.forEach((e) => print("example9 ciclo forEach '${e}'")); } // Para recorrer los caracteres de una cadena o para extraer una subcadena. var example10String = "ab"; example10() { for (var i = 0; i < example10String.length; i++) { print("example10 Recorrido de caracteres en la cadena '${example10String[i]}'"); } for (var i = 0; i < example10String.length; i++) { print("example10 ciclo de subcadena '${example10String.substring(i, i + 1)}'"); } } // Formato de números Int y double son soportados. example11() { var i = 1 + 320, d = 3.2 + 0.01; print("example11 int ${i}"); print("example11 double ${d}"); } // DateTime ofrece aritmética de fecha/hora. example12() { var now = new DateTime.now(); print("example12 ahora '${now}'"); now = now.add(new Duration(days: 1)); print("example12 manana '${now}'"); } // Expresiones regulares son soportadas. example13() { var s1 = "alguna cadena", s2 = "alguna", re = new RegExp("^s.+?g\$"); match(s) { if (re.hasMatch(s)) { print("example13 regexp embona '${s}'"); } else { print("example13 regexp no embona '${s}'"); } } match(s1); match(s2); } // Las expresiones booleanas admiten conversiones implícitas y tipos dinámicos. example14() { var a = true; if (a) { print("true, a is $a"); } a = null; if (a) { print("true, a es $a"); } else { print("false, a es $a"); // corre aquí } // el tipado dinámico null puede convertirse a bool var b; // b es de tipo dinámico b = "abc"; try { if (b) { print("true, b es $b"); } else { print("false, b es $b"); } } catch (e) { print("error, b es $b"); // esto podría ser ejecutado pero consiguió error } b = null; if (b) { print("true, b es $b"); } else { print("false, b es $b"); // corre aquí } // tipado estático null no puede ser convertido a bool var c = "abc"; c = null; // compilación fallida // if (c) { // print("true, c is $c"); // } else { // print("false, c is $c"); // } } // try/catch/finally y throw son utilizados para el manejo de excepciones. // throw toma cualquier objeto como parámetro; example15() { try { try { throw "Algun error inesperado."; } catch (e) { print("example15 una excepcion: '${e}'"); throw e; // Re-throw } } catch (e) { print("example15 atrapa la excepcion que ha sido relanzada: '${e}'"); } finally { print("example15 aún ejecuta finally"); } } // Para ser eficiente cuando creas una cadena larga dinámicamente, usa // StringBuffer. O podrías unir un arreglo de cadena de caracteres. example16() { var sb = new StringBuffer(), a = ["a", "b", "c", "d"], e; for (e in a) { sb.write(e); } print("example16 cadena de caracteres dinamica creada con " "StringBuffer '${sb.toString()}'"); print("example16 union de arreglo de cadena de caracteres '${a.join()}'"); } // Las cadenas de caracteres pueden ser concatenadas contando solo // con literales una después de la otra sin algún otro operador necesario. example17() { print("example17 " "concatenar " "cadenas " "asi"); } // Las cadenas de caracteres utilizan comilla simple o comillas dobles como delimitadores // sin ninguna diferencia entre ambas. Esto proporciona flexibilidad que puede ser efectiva // para evitar la necesidad de 'escapar' el contenido. Por ejemplo, // las dobles comillas de los atributos HTML. example18() { print('Example18 ' "Don't can't I'm Etc" ''); } // Las cadenas de caracteres con triple comilla simple o triple comillas dobles // dividen múltiples lineas e incluyen como delimitador el salto de línea. example19() { print('''Example19 Example19 Don't can't I'm Etc Example19 '''); } // Las cadenas de caracteres cuentan con una extraordinaria característica // para la interpolación de caracteres utilizando el operador $ // Con $ { [expresion] }, devolvemos la expresion interpolada. // $ seguido por el nombre de una variable interpola el contenido de dicha variable. // $ puede ser escapado con \$ para solo agregarlo a la cadena. example20() { var s1 = "'\${s}'", s2 = "'\$s'"; print("Example20 \$ interpolation ${s1} or $s2 works."); } // Hasta ahora no hemos declarado ningún tipo de dato y los programas // han funcionado bien. De hecho, los tipos no se toman en cuenta durante // el tiempo de ejecución. // Los tipos incluso pueden estar equivocados y al programa todavía se le dará // el beneficio de la duda y se ejecutará como si los tipos no importaran. // Hay un parámetro de tiempo de ejecución que comprueba los errores de tipo que es // el modo de verificación, el cuál es útil durante el tiempo de desarrollo, // pero que también es más lento debido a la comprobación adicional y, por lo tanto // se evita durante el tiempo de ejecución de la implementación. class Example21 { List _names; Example21() { _names = ["a", "b"]; } List get names => _names; set names(List list) { _names = list; } int get length => _names.length; void add(String name) { _names.add(name); } } void example21() { Example21 o = new Example21(); o.add("c"); print("example21 nombres '${o.names}' y longitud '${o.length}'"); o.names = ["d", "e"]; print("example21 nombres '${o.names}' y longitud '${o.length}'"); } // La herencia de clases toma la forma NombreDeClase extends OtraClase {}. class Example22A { var _name = "¡Algun Nombre!"; get name => _name; } class Example22B extends Example22A {} example22() { var o = new Example22B(); print("example22 herencia de clase '${o.name}'"); } // La mezcla de clases también esta disponible y toman la forma de // NombreDeClase extends AlgunaClase with OtraClase {}. // Es necesario extender de alguna clase para poder mezclar con otra. // La clase de plantilla de mixin no puede en este momento tener un constructor. // Mixin se utiliza principalmente para compartir métodos con clases distantes, // por lo que la herencia única no interfiere con el código reutilizable. // Mixins se colocan despues de la palabra "with" durante la declaración de la clase. class Example23A {} class Example23Utils { addTwo(n1, n2) { return n1 + n2; } } class Example23B extends Example23A with Example23Utils { addThree(n1, n2, n3) { return addTwo(n1, n2) + n3; } } example23() { var o = new Example23B(), r1 = o.addThree(1, 2, 3), r2 = o.addTwo(1, 2); print("Example23 addThree(1, 2, 3) results in '${r1}'"); print("Example23 addTwo(1, 2) results in '${r2}'"); } // El método constructor de la clase utiliza el mismo nombre de la clase // y toma la forma de AlgunaClase() : super() {}, donde la parte ": super()" // es opcional y es utilizado para delegar parametros constantes // al método constructor de la clase padre o super clase. class Example24A { var _value; Example24A({value: "algunValor"}) { _value = value; } get value => _value; } class Example24B extends Example24A { Example24B({value: "algunOtroValor"}) : super(value: value); } example24() { var o1 = new Example24B(), o2 = new Example24B(value: "aunMas"); print("example24 llama al método super desde el constructor '${o1.value}'"); print("example24 llama al método super desde el constructor '${o2.value}'"); } // Hay un atajo para configurar los parámetros del constructor en el caso de clases más simples. // Simplemente use el prefijo this.nombreParametro y establecerá el parámetro // en una variable de instancia del mismo nombre. class Example25 { var value, anotherValue; Example25({this.value, this.anotherValue}); } example25() { var o = new Example25(value: "a", anotherValue: "b"); print("example25 atajo para el constructor '${o.value}' y " "'${o.anotherValue}'"); } // Los parámetros con nombre están disponibles cuando se declaran entre {}. // El orden de los parámetros puede ser opcional cuando se declara entre {}. // Los parámetros pueden hacerse opcionales cuando se declaran entre []. example26() { var _name, _surname, _email; setConfig1({name, surname}) { _name = name; _surname = surname; } setConfig2(name, [surname, email]) { _name = name; _surname = surname; _email = email; } setConfig1(surname: "Doe", name: "John"); print("example26 name '${_name}', surname '${_surname}', " "email '${_email}'"); setConfig2("Mary", "Jane"); print("example26 name '${_name}', surname '${_surname}', " "email '${_email}'"); } // Las variables declaradas con final solo se pueden establecer una vez. // En el caso de las clases, las variables de instancia final se pueden establecer // a través de la constante del parámetro constructor. class Example27 { final color1, color2; // Un poco de flexibilidad para establecer variables de instancia finales con la sintaxis // que sigue a : Example27({this.color1, color2}) : color2 = color2; } example27() { final color = "orange", o = new Example27(color1: "lilac", color2: "white"); print("example27 color es '${color}'"); print("example27 color es '${o.color1}' y '${o.color2}'"); } // Para importar una librería utiliza la palabra reservada import "rutaLibrería" o si es una biblioteca central, // import "dart:NombreLibrería". También está el "pub" administrador de paquetes con // su propia convensión import "package:NombrePaquete". // Ve import "dart:collection"; al inicio. Las importaciones deben venir antes // de la delcaración de algún otro código. IterableBase proviene de dart:collection. class Example28 extends IterableBase { var names; Example28() { names = ["a", "b"]; } get iterator => names.iterator; } example28() { var o = new Example28(); o.forEach((name) => print("example28 '${name}'")); } // Para el control de flujo tenemos: // * estandard switch // * if-else if-else y el operador ternario ..?..:.. // * closures y funciones anonimas // * sentencias break, continue y return example29() { var v = true ? 30 : 60; switch (v) { case 30: print("example29 sentencia switch"); break; } if (v < 30) { } else if (v > 30) { } else { print("example29 sentencia if-else"); } callItForMe(fn()) { return fn(); } rand() { v = new DM.Random().nextInt(50); return v; } while (true) { print("example29 callItForMe(rand) '${callItForMe(rand)}'"); if (v != 30) { break; } else { continue; } // Nunca llega aquí. } } // La sentencia int.parse, convierte de tipo double a int, o simplemente mantener int cuando se dividen los números // utilizando ~/ como operación. Vamos a jugar un juego de adivinanzas también. example30() { var gn, tooHigh = false, n, n2 = (2.0).toInt(), top = int.parse("123") ~/ n2, bottom = 0; top = top ~/ 6; gn = new DM.Random().nextInt(top + 1); // +1 porque nextInt top es exclusivo print("example30 Adivina un número entre 0 y ${top}"); guessNumber(i) { if (n == gn) { print("example30 ¡Adivinaste correctamente! El número es ${gn}"); } else { tooHigh = n > gn; print("example30 Número ${n} es demasiado " "${tooHigh ? 'high' : 'low'}. Intenta nuevamente"); } return n == gn; } n = (top - bottom) ~/ 2; while (!guessNumber(n)) { if (tooHigh) { top = n - 1; } else { bottom = n + 1; } n = bottom + ((top - bottom) ~/ 2); } } // Los programas tienen un solo punto de entrada en la función principal. // No se espera que se ejecute nada en el ámbito externo antes de que un programa // comience a funcionar con su función principal. // Esto ayuda con una carga más rápida e incluso con una carga lenta // de lo que necesita el programa para iniciar. main() { print("Learn Dart in 15 minutes!"); [example1, example2, example3, example4, example5, example6, example7, example8, example9, example10, example11, example12, example13, example14, example15, example16, example17, example18, example19, example20, example21, example22, example23, example24, example25, example26, example27, example28, example29, example30 ].forEach((ef) => ef()); } ``` ## Lecturas adicionales Dart tiene un sitio web muy completo. Cubre referencias de API, tutoriales, artículos y más, incluyendo una útil sección en línea Try Dart. [https://www.dartlang.org](https://www.dartlang.org) [https://try.dartlang.org](https://try.dartlang.org) ================================================ FILE: es/docker.md ================================================ --- contributors: - ["Ruslan López", "http://javapro.org/"] - ["Michael Chen", "https://github.com/ML-Chen"] --- ```bat :: descargar, instalar y ejecutar la imágen del hola mundo docker run hello-world :: Si esta es la primera vez, deberíais de poder ver el mensaje :: Unable to find image 'hello-world:latest' locally :: latest: Pulling from library/hello-world :: 1b930d010525: Pull complete :: Digest: sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064 :: Status: Downloaded newer image for hello-world:latest :: :: Hello from Docker! :: This message shows that your installation appears to be working correctly. :: :: To generate this message, Docker took the following steps: :: 1. The Docker client contacted the Docker daemon. :: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. :: (amd64) :: 3. The Docker daemon created a new container from that image which runs the :: executable that produces the output you are currently reading. :: 4. The Docker daemon streamed that output to the Docker client, which sent it :: to your terminal. :: :: To try something more ambitious, you can run an Ubuntu container with: :: $ docker run -it ubuntu bash :: :: Share images, automate workflows, and more with a free Docker ID: :: https://hub.docker.com/ :: :: For more examples and ideas, visit: :: https://docs.docker.com/get-started/ :: El susodicho mensaje se podría traducir como: :: :: Hola desde Docker! :: Este mensaje muestra que su instalación parece estar funcionando crrectamente. :: :: Para generar este mensaje, Docker realizó los siguientes pasos: :: 1. El cliente de Docker contactó a Docker daemon. :: 2. El Docker daemon obtubo la imágen "hello-world" desde Docker Hub. :: (amd64) :: 3. El Docker daemon creó un nuevo contenedor a partir de esa imagen con la cual ejecuta el :: ejecutable que produce la salida que estás leyendo. :: 4. El Docker daemon transmitió dicha salida el cliente Docker, el cual :: la envió a tu terminal. :: :: Para intentar algo más ambicioso, puede correr un contenedor Ubuntu mediante: :: $ docker run -it ubuntu bash :: :: Comparte imágenes, automatice flujos y más con un Docker ID gratuito: :: https://hub.docker.com/ :: ahora veamos las imágenes que se están ejecutando actualmente docker ps :: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS :: NAMES :: veamos las imágenes que hemos ejecutado previamente docker ps -a :: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS :: NAMES :: 4a76281f9c53 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago :: happy_poincare :: la parte del nombre se genera automáticamente, así que probablemente sea diferente para vos :: eliminemos nuestra imagen previamente generada docker rm happy_poincare :: verifiquemos si realmente fue borrada docker ps -a :: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS :: NAMES :: especifiquemos un nombre personalizado para el contenedor docker run --name test_container hello-world :: Hello from Docker! :: This message shows that your installation appears to be working correctly. :: :: To generate this message, Docker took the following steps: :: 1. The Docker client contacted the Docker daemon. :: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. :: (amd64) :: 3. The Docker daemon created a new container from that image which runs the :: executable that produces the output you are currently reading. :: 4. The Docker daemon streamed that output to the Docker client, which sent it :: to your terminal. :: :: To try something more ambitious, you can run an Ubuntu container with: :: $ docker run -it ubuntu bash :: :: Share images, automate workflows, and more with a free Docker ID: :: https://hub.docker.com/ :: :: For more examples and ideas, visit: :: https://docs.docker.com/get-started/ docker ps -a :: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS :: NAMES :: d345fe1a4f41 hello-world "/hello" About a minute ago Exited (0) About a minute ago :: test_container :: tal como podeis ver el nombre es el que especificamos :: obtener los registros de un contenedor nombrado docker logs test_container :: Hello from Docker! :: This message shows that your installation appears to be working correctly. :: :: To generate this message, Docker took the following steps: :: 1. The Docker client contacted the Docker daemon. :: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. :: (amd64) :: 3. The Docker daemon created a new container from that image which runs the :: executable that produces the output you are currently reading. :: 4. The Docker daemon streamed that output to the Docker client, which sent it :: to your terminal. :: :: To try something more ambitious, you can run an Ubuntu container with: :: $ docker run -it ubuntu bash :: :: Share images, automate workflows, and more with a free Docker ID: :: https://hub.docker.com/ :: :: For more examples and ideas, visit: :: https://docs.docker.com/get-started/ docker rm test_container docker run ubuntu :: Unable to find image 'ubuntu:latest' locally :: latest: Pulling from library/ubuntu :: 2746a4a261c9: Pull complete :: 4c1d20cdee96: Pull complete 0d3160e1d0de: Pull complete c8e37668deea: Pull complete Digest: sha256:250cc6f3f3ffc5cdaa9d8f4946ac79821aafb4d3afc93928f0de9336eba21aa4 :: Status: Downloaded newer image for ubuntu:latest docker ps -a :: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS :: NAMES :: c19e9e5b000a ubuntu "/bin/bash" 5 seconds ago Exited (0) 4 seconds ago :: relaxed_nobel :: ejecutando un contenedor en modo interactivo docker run -it ubuntu :: root@e2cac48323d2:/# uname :: Linux :: root@e2cac48323d2:/# exit :: exit docker rm relaxed_nobel docker ps -a :: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS :: NAMES :: e2cac48323d2 ubuntu "/bin/bash" 2 minutes ago Exited (0) About a minute ago :: nifty_goldwasser docker rm nifty_goldwasser ``` ================================================ FILE: es/dynamic-programming.md ================================================ --- contributors: - ["Akashdeep Goel", "http://github.com/akashdeepgoel"] translators: - ["Gino Amaury", "https://github.com/ginoamaury"] --- # Programación Dinámica ## Introducción La programación dinámica es una técnica poderosa usada para resolver una clase particular de problemas como veremos más adelante. La idea es muy simple: si has solucionado un problema con la entrada dada, entonces, guardaremos el resultado para una futura referencia, con el fin de evitar la solución del mismo problema de nuevo. Recuerda siempre: "Aquellos que no pueden recordar el pasado están condenados a repetirlo" ## Formas de resolver este tipo de problemas 1. *De arriba hacia abajo (Top-Down)* : Empezamos resolviendo el problema dado descomponiendolo. Si ves que el problema fue resuelto, entonces retorna la respuesta guardada. Si no se ha resuelto, resuélvelo y guarda la respuesta. Esto suele ser fácil de pensar y es muy intuitivo. A esto se le conoce como memoización. 2. *De abajo hacia arriba (Bottom-Up)* : Analiza el problema y ve el orden en que los subproblemas deben ser resueltos y empieza resolviendo el subproblema más trivial, hacia el problema dado. En este proceso, se garantiza que los subproblemas se resuelven antes de resolver el problema. Esto se conoce como Programación Dinámica. ## Ejemplo de Programación Dinámica El problema de la subsecuencia creciente máxima consiste en encontrar la subsecuencia creciente máxima en una secuencia dada. Dada la secuencia `S= {a1 , a2 , a3, a4, ............., an-1, an }`, tenemos que encontrar un subconjunto más largo tal que para todo `j` y `i`, `j a[j] and LS[i] {:huevos 2 :mantequilla 1 :harina 5} ; Para transformar los elementos de etiqueta, definir la función de lectura y pasar un mapa ; que asigna etiquetas a funciones del lector de edn/read-string al igual que. (edn/read-string {:lectores {'MyYelpClone/MenuItem map->menu-item}} "#MyYelpClone/MenuItem {:nombre \"huevos-benedict\" :clasificacion 10}") ; -> #user.MenuItem{:nombre "huevos-benedict", :clasificacion 10} ``` # Referencias - [EDN spec (EN)](https://github.com/edn-format/edn) - [Implementations (EN)](https://github.com/edn-format/edn/wiki/Implementations) - [Tagged Elements (EN)](http://www.compoundtheory.com/clojure-edn-walkthrough/) ================================================ FILE: es/elisp.md ================================================ --- contributors: - ["Bastien Guerry", "http://bzg.fr"] translators: - ["Guillermo Vayá", "http://willyfrog.es"] --- ```scheme ;; Introduccion a Emacs Lisp en 15 minutos (v0.2d) ;; ;; Autor: Bastien / @bzg2 / http://bzg.fr ;; Traducción: Guillermo Vayá / @Driadan / http://willyfrog.es ;; ;; Antes de nada, lee este texto de Peter Norvig: ;; Traducido: http://loro.sourceforge.net/notes/21-dias.html ;; Original: http://norvig.com/21-days.html ;; ;; Ahora instala GNU Emacs 24.3: ;; ;; Debian: apt-get install emacs ;; (o sigue las instrucciones de tu distribución preferida) ;; OSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg ;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip ;; ;; Puedes encontrar información general sobre Emacs en: ;; http://www.gnu.org/software/emacs/#Obtaining ;; Aviso importante: ;; ;; Seguir este tutorial no provocará daños en tu ordenador a menos que ;; te enfades tanto que que acabes tirándolo al suelo. En tal caso ;; declino cualquier responsabilidad. ¡A divertirse! ;; "N. del. T.": Algunos términos comunes de la informática se han dejado ;; sin traducir ya que es mucho más probable que el lector los conozca en ;; su forma en inglés, siendo la versión en español de muy raro uso. ;; Además "sexps" se ha decidido traducir por sexpresión. ;; Por último, añadir que no se han traducido los ejemplos de código ya que no ;; es necesario entender qué dice el string para comprender el funcionamiento ;; y podría llevar a error. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Inicia Emacs. ;; ;; Pulsa la tecla `q' para pasar el mensaje de bienvenida. ;; ;; Mira a la línea gris en la parte inferior de la ventana: ;; ;; "*scratch*" es el nombre del espacio editable donde estás. ;; A este espacio editable se le llama "buffer". ;; ;; Scratch es el buffer por defecto cuando abres Emacs. ;; En Emacs nunca editas ficheros, sino que editas buffers que ;; posteriormente pueden grabarse a un fichero. ;; can save to a file. ;; ;; "Lisp interaction" indica el conjunto de ordenes disponibles. ;; ;; Emacs dispone de un set de comandos disponibles en cualquier buffer ;; ("built-ins") y aparte varios conjuntos de ordenes disponibles ;; según el modo específico que esté activo. En nuestro caso ;; estamos usando `lisp-interaction-mode', el cual incluye las ;; ordenes necesarias para evaluar y navegar código Elisp. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Un punto y coma comienza un comentario. Pueden ponerse en cualquier ;; posicion de la linea. ;; ;; Los programas en Elisp se componen de expresiones simbólicas ;; tambien llamadas "sexps": (+ 2 2) ;; Esta expresión simbólica se lee tal que "Suma 2 y 2" ;; Las sexpresiones se rodean por paréntesis, y pueden anidarse: (+ 2 (+ 1 1)) ;; Una expresion simbólica está formada bien por átomos o bien por otras ;; expresiones simbólicas. En el ejemplo de arriba, 1 y 2 son átomos, ;; mientras que (+ 2 (+ 1 1)) y (+ 1 1) son expresiones simbólicas. ;; Gracias a `lisp-interaction-mode' puedes evaluar las sexpresiones. ;; Coloca el cursor justo despues del paréntesis de cierre y ;; mantén pulsada la tecla Control y la j (para abreviar usaremos "C-j"). (+ 3 (+ 1 2)) ;; ^ pon aquí el cursor ;; `C-j' => 6 ;; `C-j' añade el resultado de la evaluación al buffer. ;; `C-xC-e' muestra el mismo resultado pero en la linea inferior ;; la cual se llama "echo area". Este será el metodo que usaremos ;; normalmente para no llenar el buffer con texto inútil. ;; `setq' guarda un valor en una variable: (setq my-name "Bastien") ;; `C-xC-e' => "Bastien" (aparece en el echo area) ;; `insert' añade "Hello!" en el punto donde esté tu cursor: (insert "Hello!") ;; `C-xC-e' => "Hello!" ;; Aunque hemos usado `insert' con solo un parámetro "Hello!", se ;; pueden pasar más. Por ejemplo, en esta otra sexpresión usamos dos: (insert "Hello" " world!") ;; `C-xC-e' => "Hello world!" ;; Se pueden usar variables en lugar de strings: (insert "Hello, I am " my-name) ;; `C-xC-e' => "Hello, I am Bastien" ;; Puedes combinar sexpresiones en funciones: (defun hello () (insert "Hello, I am " my-name)) ;; `C-xC-e' => hello ;; Evaluemos la funcion: (hello) ;; `C-xC-e' => Hello, I am Bastien ;; Los parentesis vacios en la definicion de una funcion indican ;; que no acepta parámetros. En cualquier caso, usar `my-name' siempre ;; es aburrido, asi que vamos a hacer que la función accepte un parámetro ;; (en este caso el parametro se llama "name"): (defun hello (name) (insert "Hello " name)) ;; `C-xC-e' => hello ;; Ahora vamos a llamar a la funcion con el string "you" como valor para ;; el único parámetro que posee. (hello "you") ;; `C-xC-e' => "Hello you" ;; ¡Genial! ;; Descansa un poco y respira. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Ahora cambiaremos al nuevo buffer, llamado "*test*", en una nueva ventana. (switch-to-buffer-other-window "*test*") ;; `C-xC-e' ;; => [La pantalla ahora tiene dos ventanas y el cursor está en el buffer *test*] ;; Mueve el ratón sobre la ventana superior y pulsa el boton izdo. para volver. ;; Otra forma es usando `C-xo' (pulsa simultaneamente control y x y luego la o) ;; para ir a la otra ventana. ;; Se pueden combinar varias sexpresiones mediante `progn': (progn (switch-to-buffer-other-window "*test*") (hello "you")) ;; `C-xC-e' ;; => [De las dos ventanas de la pantalla, el cursor está en la marcada como *test*] ;; A partir de ahora, si no te importa, dejaremos de decir que pulses `C-xC-e': ;; tendrás que hacerlo para ejecutar cada sexpresión que siga. ;; También tendrás que volver al buffer *scratch* bien con el ratón o con `C-xo'. ;; En ocasiones será util limpiar el buffer: (progn (switch-to-buffer-other-window "*test*") (erase-buffer) (hello "there")) ;; O volver a la ventana anterior: (progn (switch-to-buffer-other-window "*test*") (erase-buffer) (hello "you") (other-window 1)) ;; Puedes enlazar un valor a una variable local con `let': (let ((local-name "you")) (switch-to-buffer-other-window "*test*") (erase-buffer) (hello local-name) (other-window 1)) ;; En este caso, no hace falta añadir `progn' ya que `let' permite combinar ;; varias sexpresiones. ;; Vamos a darle formato a un string: (format "Hello %s!\n" "visitor") ;; Cada %s indica la posicion donde irá un string, el cual será reemplazado ;; por "visitor". "\n" es el caracter de nueva línea. ;; Mejoremos nuestra funcion usando `format': (defun hello (name) (insert (format "Hello %s!\n" name))) (hello "you") ;; Creemos una nueva funcion que utililce `let': (defun greeting (name) (let ((your-name "Bastien")) (insert (format "Hello %s!\n\nI am %s." name ; the argument of the function your-name ; the let-bound variable "Bastien" )))) ;; Y ahora la evaluamos: (greeting "you") ;; Algunas funciones son interactivas: (read-from-minibuffer "Enter your name: ") ;; Al evaluar esta función, ésta devuelve lo que hayas introducido. ;; Ahora hagamos nuestra función `greeting' preguntar por tu nombre: (defun greeting (from-name) (let ((your-name (read-from-minibuffer "Enter your name: "))) (insert (format "Hello!\n\nI am %s and you are %s." from-name ; the argument of the function your-name ; the let-bound var, entered at prompt )))) (greeting "Bastien") ;; Y ahora la completamos mostrando el resultado en la otra ventana: (defun greeting (from-name) (let ((your-name (read-from-minibuffer "Enter your name: "))) (switch-to-buffer-other-window "*test*") (erase-buffer) (insert (format "Hello %s!\n\nI am %s." your-name from-name)) (other-window 1))) ;; Probémosla: (greeting "Bastien") ;; Descansa un poco y respira. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Creemos una lista de nombres: (setq list-of-names '("Sarah" "Chloe" "Mathilde")) ;; Para coger el primer elemento de la lista usaremos `car': (car list-of-names) ;; Para coger todos menos el primer elemento de la lista ;; usaremos `cdr': (cdr list-of-names) ;; Para añadir un elemento al comienzo de la lista utilizamos `push': (push "Stephanie" list-of-names) ;; OJO: `car' y `cdr' no modifican la lista, mientras que `push' sí. ;; ¡Es una diferencia importante! Algunas funciones no tienen efectos ;; colaterales (como `car') mientras que otras sí (como `push'). ;; "N. del T.": estos efectos colaterales se les llama `side-effects' en ;; las distintas variantes de lisp. ;; Llamemos a `hello' con cada elemento de `list-of-names': (mapcar 'hello list-of-names) ;; Retocamos `greeting' para que salude a todos los que estén en `list-of-names': (defun greeting () (switch-to-buffer-other-window "*test*") (erase-buffer) (mapcar 'hello list-of-names) (other-window 1)) (greeting) ;; ¿Te acuerdas de la función `hello' definida un poco más arriba? ;; Recibía un parámetro: `name'. Así que `mapcar' llama a `hello' con cada ;; elemento de `list-of-names' como parámetro de `hello'. ;; Ahora ordenaremos un poco lo que tenemos en el buffer: (defun replace-hello-by-bonjour () (switch-to-buffer-other-window "*test*") (goto-char (point-min)) (while (search-forward "Hello") (replace-match "Bonjour")) (other-window 1)) ;; (goto-char (point-min)) mueve el cursor al principio del buffer. ;; (search-forward "Hello") busca un string "Hello". ;; (while x y) evalua la/s sexpresion/es y mientras que x devuelva ;; alguna cosa. ;; En el momento que x devuelva `nil' (es decir nada), sale del ;; bucle `while'. (replace-hello-by-bonjour) ;; Observamos que todas las veces que teníamos la palabra "Hello" en el buffer *test* ;; han sido reemplazadas por "Bonjour". ;; Y además, hemos obtenido un error: "Search failed: Hello". ;; ;; Para evitar este error, hay que decirle a `search-forward' si debería dejar de ;; buscar en el buffer en algún momento y si debería fallar sin quejarse cuando ;; no encuentra nada. ;; (search-forward "Hello" nil t) justo hace eso: ;; El argumento `nil' significa que la busqueda no está ligada a ninguna posición. ;; Y el argumento `t' le pide que no diga nada si no encuentra el string. ;; Usaremos esta sexpresión en la función siguiente, la cual ya ;; no muestra ningún error: (defun hello-to-bonjour () (switch-to-buffer-other-window "*test*") (erase-buffer) ;; Say hello to names in `list-of-names' (mapcar 'hello list-of-names) (goto-char (point-min)) ;; Replace "Hello" by "Bonjour" (while (search-forward "Hello" nil t) (replace-match "Bonjour")) (other-window 1)) (hello-to-bonjour) ;; Añadamos algo de color a los nombres: (defun boldify-names () (switch-to-buffer-other-window "*test*") (goto-char (point-min)) (while (re-search-forward "Bonjour \\(.+\\)!" nil t) (add-text-properties (match-beginning 1) (match-end 1) (list 'face 'bold))) (other-window 1)) ;; Esta función nos presenta `re-search-forward': en vez de ;; buscar el string "Bonjour" exacto, se busca por un patrón ;; usando una "expresión regular" (lo cual se muestra abreviado ;; en el prefijo "re-" del inglés "Regular Expression"). ;; La expresión regular a utilizar es "Bonjour \\(.+\\)!" y se traduce como: ;; el string "Bonjour ", seguido de ;; un grupo de | representado por \\( ... \\) ;; cualquier caracter | representado por . ;; al menos una vez | representado por + ;; y el string "!". ;; ¿Preparado? ¡Probemoslo! (boldify-names) ;; `add-text-properties' añade propiedades al texto, como una fuente. ;; ¡Hale! ¡Ya lo tenemos! ¡Feliz hacking! ;; Si quieres saber más sobre una función o una variable: ;; ;; C-h v la-variable RET ;; C-h f la-funcion RET ;; ;; Si quieres leer el manual de Emacs Lisp desde dentro de Emacs: ;; ;; C-h i m elisp RET ;; ;; Para leer una introducción en linea de Emacs Lisp: ;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html ``` ================================================ FILE: es/elixir.md ================================================ --- contributors: - ["Joao Marques", "http://github.com/mrshankly"] - ["Dzianis Dashkevich", "https://github.com/dskecse"] - ["Ryan Plant", "https://github.com/ryanplant-au"] translators: - ["Adrian Carrascal", "https://github.com/acarrascalgarcia"] --- Elixir es un lenguaje funcional moderno construido sobre la máquina virtual de Erlang. Es completamente compatibe con Erlang, sin embargo, ofrece una sintaxis más estandar y otras características más. ```elixir # Los comentarios de única línea # comienzan con un símbolo numérico. # No hay comentarios multilinea, # pero se pueden apilar varios comentarios. # Para usar el shell de Elixir se usa el comando `iex`. # Los módulos se compilan con el comando `elixirc`. # Ambos deberían estar en la ruta si Elixir se instaló correctamente. ## --------------------------- ## -- Tipos básicos ## --------------------------- # Hay números 3 # integer 0x1F # integer 3.0 # float # Átomos, que son literales, una constante con nombre. Comienzan con `:`. :hello # atom # Tuples that are stored contiguously in memory. # Tuplas que se almacenan contiguamente en memoria. {1,2,3} # tuple # Se puede acceder a un elemento de una tupla con la función `elem`: elem({1, 2, 3}, 0) #=> 1 # Listas que se implementan como listas enlazadas. [1,2,3] # list # Se puede acceder al primer y último elemento de la lista como: [head | tail] = [1,2,3] head #=> 1 tail #=> [2,3] # En Elixir, solo como Erlang, el `=` denota la coincidencia de patrones y # no una asignación. # # This is how the above example of accessing the head and tail of a list works. # Así es como el ejemplo anterior de acceder al # primer y último elemento de una lista trabaja. # Una coincidencia de patrón errará cuando los lados no coincidan, en este ejemplo # las tuplas tienen diferentes tamaños. # {a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2} # También hay binarios <<1,2,3>> # binary # Cadenas y listas de caracteres "hello" # string 'hello' # char list # Cadenas de varias lineas """ I'm a multi-line string. """ #=> "I'm a multi-line\nstring.\n" # Todas las cadenas se codifican en UTF-8: "héllò" #=> "héllò" # Las cadenas son solo binarios realmente, y la lista de caracteres solo listas. <> #=> "abc" [?a, ?b, ?c] #=> 'abc' # `?a` en Elixir devuelve el valor ASCII para el caracter `a` ?a #=> 97 # Para concatenar listas se usa `++`, para binarios `<>` [1,2,3] ++ [4,5] #=> [1,2,3,4,5] 'hello ' ++ 'world' #=> 'hello world' <<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>> "hello " <> "world" #=> "hello world" # Los rangos se representan como `start..end` (Es inclusivo) 1..10 #=> 1..10 lower..upper = 1..10 # Se puede usar la coincidencia de patrones en los rangos también [lower, upper] #=> [1, 10] # Los mapas son pares de llave-valor genders = %{"david" => "male", "gillian" => "female"} genders["david"] #=> "male" # Los mapas con llaves de tipo átomo se pueden usar como esto genders = %{david: "male", gillian: "female"} genders.gillian #=> "female" ## --------------------------- ## -- Opetadores ## --------------------------- # Aritméticos 1 + 1 #=> 2 10 - 5 #=> 5 5 * 2 #=> 10 10 / 2 #=> 5.0 # En Elixir el operador `/` siempre devuelve un número flotante # Para hacer la división de número entero se debe usar `div` div(10, 2) #=> 5 # Para obtener el residuo de la división se debe usar `rem` rem(10, 3) #=> 1 # También hay operadores lógicos: `or`, `and` y `not`. # Estos operadores esperan un boolean como su primer argumento. true and true #=> true false or true #=> true # 1 and true #=> ** (ArgumentError) argument error # Elixir también provee `||`, `&&` y `!` donde acepta argumentos de cualquier tipo. # Todos los valores excepto `false` y `nil` se evaluarán como verdadero. 1 || true #=> 1 false && 1 #=> false nil && 20 #=> nil !true #=> false # Para comparaciones se tiene: `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<` y `>` 1 == 1 #=> true 1 != 1 #=> false 1 < 2 #=> true # `===` y `!==` son más estrictos cuando comparan números: 1 == 1.0 #=> true 1 === 1.0 #=> false # También se puede comparar dos tipos de datos diferentes: 1 < :hello #=> true # No se necesita memorizar el orden pero es importante tenerlo en cuenta: # number < atom < reference < functions < port < pid < tuple < list < bit string ## --------------------------- ## -- Control de flujo ## --------------------------- # Expresión `if` if false do "This will never be seen" else "This will" end # Se acuerda de la coincidencia de patrones? # Muchas estructuras de control de flujo en Elixir confían en ella. # `case` permite comparar un valor con muchos patrones: case {:one, :two} do {:four, :five} -> "This won't match" {:one, x} -> "This will match and bind `x` to `:two` in this clause" _ -> "This will match any value" end # Es común vincular el valor a `_` si no se necesita. # Por ejemplo, si unicamente el primer elemento de la lista es importante: [head | _] = [1,2,3] head #=> 1 # Para una mejor lectura se puede hace lo siguiente: [head | _tail] = [:a, :b, :c] head #=> :a # `cond` permite comprobar muchas condiciones al mismo tiempo. # Usar `cond` en vez de muchas expresiones `if` anidadas. cond do 1 + 1 == 3 -> "I will never be seen" 2 * 5 == 12 -> "Me neither" 1 + 2 == 3 -> "But I will" end # Es común estabecer la última condición como `true`, donde siempre va a coincidir. cond do 1 + 1 == 3 -> "I will never be seen" 2 * 5 == 12 -> "Me neither" true -> "But I will (this is essentially an else)" end # `try/catch` se usa para atrapar valores que se lanzan, también soporta una # clausula `after` que se invoca sin importar si un valor se atrapó o no. try do throw(:hello) catch message -> "Got #{message}." after IO.puts("I'm the after clause.") end #=> I'm the after clause # "Got :hello" ## --------------------------- ## -- Módulos y Funciones ## --------------------------- # Anonymous functions (notice the dot) # Funciones anónimas (Ver el punto `.`) square = fn(x) -> x * x end square.(5) #=> 25 # También aceptan muchas cláusulas y guards. # Los guards permiten afinar las coincidencias de patrones, # se indican por la palabra reservada `when`: f = fn x, y when x > 0 -> x + y x, y -> x * y end f.(1, 3) #=> 4 f.(-1, 3) #=> -3 # Elixir también provee muchas funciones incorporadas. # Esas están disponibles en el ámbito actual. is_number(10) #=> true is_list("hello") #=> false elem({1,2,3}, 0) #=> 1 # Se pueden agrupar varias funciones en un módulo. Dentro de un módulo # se usa `def` para definir las funciones. defmodule Math do def sum(a, b) do a + b end def square(x) do x * x end end Math.sum(1, 2) #=> 3 Math.square(3) #=> 9 # Para compilar el módulo simple de Math se guarda como `math.ex` y se usa `elixirc` # en la terminal: elixirc math.ex # Dentro de un módulo se puede definir funciones con `def` y funciones privadas con `defp`. # Una función definida con `def` está disponible para ser invocada desde otros módulos, # una función privada se puede solo invocar localmente. defmodule PrivateMath do def sum(a, b) do do_sum(a, b) end defp do_sum(a, b) do a + b end end PrivateMath.sum(1, 2) #=> 3 # PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError) # La declaración de funciones también soportan guards y múltiples cláusulas: defmodule Geometry do def area({:rectangle, w, h}) do w * h end def area({:circle, r}) when is_number(r) do 3.14 * r * r end end Geometry.area({:rectangle, 2, 3}) #=> 6 Geometry.area({:circle, 3}) #=> 28.25999999999999801048 # Geometry.area({:circle, "not_a_number"}) #=> ** (FunctionClauseError) no function clause matching in Geometry.area/1 # Debido a la inmutabilidad, la recursión es una gran parte de Elixir defmodule Recursion do def sum_list([head | tail], acc) do sum_list(tail, acc + head) end def sum_list([], acc) do acc end end Recursion.sum_list([1,2,3], 0) #=> 6 # Los módulos de Elixir soportan atributos, hay atributos incorporados y # se pueden agregar otros personalizados. defmodule MyMod do @moduledoc """ This is a built-in attribute on a example module. """ @my_data 100 # This is a custom attribute. IO.inspect(@my_data) #=> 100 end # El operador pipe |> permite que se pase la salida de una expresión # como el primer parámetro en una función. Range.new(1,10) |> Enum.map(fn x -> x * x end) |> Enum.filter(fn x -> rem(x, 2) == 0 end) #=> [4, 16, 36, 64, 100] ## --------------------------- ## -- Structs and Excepciones ## --------------------------- # Los Structs son extensiones de los mapas que traen valores por defecto, # garantes en tiempo de compilación y polimorfismo en Elixir. defmodule Person do defstruct name: nil, age: 0, height: 0 end joe_info = %Person{ name: "Joe", age: 30, height: 180 } #=> %Person{age: 30, height: 180, name: "Joe"} # Acceder al valor de name joe_info.name #=> "Joe" # Actualizar el valor de age older_joe_info = %{ joe_info | age: 31 } #=> %Person{age: 31, height: 180, name: "Joe"} # El bloque `try` con la palabra reservada `rescue` se usa para manejar excepciones try do raise "some error" rescue RuntimeError -> "rescued a runtime error" _error -> "this will rescue any error" end #=> "rescued a runtime error" # Todas las excepciones tienen un mensaje try do raise "some error" rescue x in [RuntimeError] -> x.message end #=> "some error" ## --------------------------- ## -- Concurrencia ## --------------------------- # Elixir confía en el modelo actor para la concurrencia. Todo lo que se necesita para escribir # programas concurrentes en Elixir son tres primitivas: procesos de desove, # envío de mensajes y recepción de mensajes. # Para empezar un nuevo proceso se usa la función `spawn`, # donde toma una función como argumento. f = fn -> 2 * 2 end #=> #Function spawn(f) #=> #PID<0.40.0> # `spawn` devuelve un pid (identificador de proceso), se puede usar este pid para enviar # mensajes para el proceso. Para hacer que un mensaje pase se usa el operador `send`. # Para que todo esto se útil se necesita estar disponibles para recibir mensajes. Esto se # alcanza con el mecanismo `receive`: # El bloque `receive do` se usa para escuchar los mensajes y procesarlos # cuando se reciben. Un bloque `receive do` solo procesará # un mensaje recibido. Para procesar múltiples mensajes, # una función con un bloque `receive do` tiene que llamarse recursivamente # para entrar en el bloque `receive do` otra vez. defmodule Geometry do def area_loop do receive do {:rectangle, w, h} -> IO.puts("Area = #{w * h}") area_loop() {:circle, r} -> IO.puts("Area = #{3.14 * r * r}") area_loop() end end end # Compilar el módulo y crear un proceso que evalue `area_loop` en el shell pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0> # Como alternativa pid = spawn(Geometry, :area_loop, []) # Enviar un mensaje al `pid` que coincidirá con un patrón en el que recibe una sentencia send pid, {:rectangle, 2, 3} #=> Area = 6 # {:rectangle,2,3} send pid, {:circle, 2} #=> Area = 12.56000000000000049738 # {:circle,2} # El shell también es un proceso, se puede usar `self` para obtener el pid actual self() #=> #PID<0.27.0> ## --------------------------- ## -- Agentes ## --------------------------- # Un agente es un proceso que mantiene el seguimiento de algún valor cambiante # Un agente se crea con `Agent.start_link`, introducuendole una función # El estado inicial del agente será lo que sea que la función devuelva {ok, my_agent} = Agent.start_link(fn -> ["red, green"] end) # `Agent.get` toma un nombre de agente y un `fn` que se pasa como el estado actual # Lo que sea que este `fn` devuelva es lo que se obtendrá de vuelta Agent.get(my_agent, fn colors -> colors end) #=> ["red, "green"] # El estado del agente se actualiza de la misma manera Agent.update(my_agent, fn colors -> ["blue" | colors] end) ``` ## Referencias * [Getting started guide](http://elixir-lang.org/getting-started/introduction.html) from the [Elixir website](http://elixir-lang.org) * [Elixir Documentation](http://elixir-lang.org/docs/master/) * ["Programming Elixir"](https://pragprog.com/book/elixir/programming-elixir) by Dave Thomas * [Elixir Cheat Sheet](http://media.pragprog.com/titles/elixir/ElixirCheat.pdf) * ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) by Fred Hebert * ["Programming Erlang: Software for a Concurrent World"](https://pragprog.com/book/jaerlang2/programming-erlang) by Joe Armstrong ================================================ FILE: es/factor.md ================================================ --- contributors: - ["hyphz", "http://github.com/hyphz/"] translators: - ["Roberto R", "https://github.com/rrodriguze"] --- Factor es un lenguaje moderno basado en la pila, basado en Forth, creado por Slava Pestov. El código de este archivo puede escribirse en Factor, pero no importa directamente porque el encabezado del vocabulario de importación haria que el comienzo fuera totalmente confuso. ```factor ! Esto es un comentario ! Como Forth, toda la programación se realiza mediante la manipulación de la ! pila. ! La intruducción de un valor literal lo coloca en la pila 5 2 3 56 76 23 65 ! No hay salida pero la pila se imprime en modo interactivo ! Esos números se agregan a la pila de izquierda a derecha ! .s imprime la pila de forma no destructiva. .s ! 5 2 3 56 76 23 65 ! La aritmética funciona manipulando datos en la pila. 5 4 + ! Sem saída ! `.` muestra el resultado superior de la pila y lo imprime. . ! 9 ! Más ejemplos de aritmética: 6 7 * . ! 42 1360 23 - . ! 1337 12 12 / . ! 1 13 2 mod . ! 1 99 neg . ! -99 -99 abs . ! 99 52 23 max . ! 52 52 23 min . ! 23 ! Se proporcionan varias palabras para manipular la pila, conocidas colectivamente como palabras codificadas. 3 dup - ! duplica el primer item (1st ahora igual a 2nd): 3 - 3 2 5 swap / ! intercambia el primero con el segundo elemento: 5 / 2 4 0 drop 2 / ! elimina el primer item (no imprime en pantalla): 4 / 2 1 2 3 nip .s ! elimina el segundo item (semejante a drop): 1 3 1 2 clear .s ! acaba con toda la pila 1 2 3 4 over .s ! duplica el segundo item superior: 1 2 3 4 3 1 2 3 4 2 pick .s ! duplica el tercer item superior: 1 2 3 4 2 3 ! Creando Palabras ! La palabra `:` factoriza los conjuntos en modo de compilación hasta que vea la palabra`;`. : square ( n -- n ) dup * ; ! Sin salida 5 square . ! 25 ! Podemos ver lo que las palabra hacen también. ! \ suprime la evaluación de una palabra y coloca su identificador en la pila. \ square see ! : square ( n -- n ) dup * ; ! Después del nombre de la palabra para crear, la declaración entre paréntesis da efecto a la pila. ! Podemos usar los nombres que queramos dentro de la declaración: : weirdsquare ( camel -- llama ) dup * ; ! Mientras su recuento coincida con el efecto de pila de palabras: : doubledup ( a -- b ) dup dup ; ! Error: Stack effect declaration is wrong : doubledup ( a -- a a a ) dup dup ; ! Ok : weirddoubledup ( i -- am a fish ) dup dup ; ! Além disso Ok ! Donde Factor difiere de Forth es en el uso de las citaciones. ! Una citacion es un bloque de código que se coloca en la pila como un valor. ! [ inicia el modo de citación; ] termina. [ 2 + ] ! La cita que suma dos queda en la pila 4 swap call . ! 6 ! Y así, palabras de orden superior. TONOS de palabras de orden superior 2 3 [ 2 + ] dip .s ! Tomar valor de la parte superior de la pilar, cotizar, retroceder: 4 3 3 4 [ + ] keep .s ! Copiar el valor desde la parte superior de la pila, cotizar, enviar copia: 7 4 1 [ 2 + ] [ 3 + ] bi .s ! Ejecute cada cotización en el valor superior, empuje amabos resultados: 3 4 4 3 1 [ + ] [ + ] bi .s ! Las citas en un bi pueden extraer valores más profundos de la pila: 4 5 ( 1+3 1+4 ) 1 2 [ 2 + ] bi@ .s ! Citar en primer y segundo valor 2 [ + ] curry ! Inyecta el valor dado al comienzo de la pila: [ 2 + ] se deja en la pila ! Condicionales ! Cualquier valor es verdadero, excepto el valor interno f. ! no existe un valor interno, pero su uso no es esencial. ! Los condicionales son palabras de orden superior, como con los combinadores ! anteriores 5 [ "Five is true" . ] when ! Cinco es verdadero 0 [ "Zero is true" . ] when ! Cero es verdadero f [ "F is true" . ] when ! Sin salida f [ "F is false" . ] unless ! F es falso 2 [ "Two is true" . ] [ "Two is false" . ] if ! Two es verdadero ! Por defecto, los condicionales consumen el valor bajo prueba, pero las ! variantes con un ! asterisco se dejan solo si es verdad: 5 [ . ] when* ! 5 f [ . ] when* ! Sin salida, pila vacía, se consume porque f es falso ! Lazos ! Lo has adivinado... estas son palabras de orden superior también. 5 [ . ] each-integer ! 0 1 2 3 4 4 3 2 1 0 5 [ + . ] each-integer ! 0 2 4 6 8 5 [ "Hello" . ] times ! Hello Hello Hello Hello Hello ! Here's a list: { 2 4 6 8 } ! Goes on the stack as one item ! Aqui está uma lista: { 2 4 6 8 } [ 1 + . ] each ! Exibe 3 5 7 9 { 2 4 6 8 } [ 1 + ] map ! Salida { 3 5 7 9 } de la pila ! Reduzir laços ou criar listas: { 1 2 3 4 5 } [ 2 mod 0 = ] filter ! Solo mantenga miembros de la lista para los cuales la cita es verdadera: { 2 4 } { 2 4 6 8 } 0 [ + ] reduce . ! Como "fold" en lenguajes funcinales: exibe 20 (0+2+4+6+8) { 2 4 6 8 } 0 [ + ] accumulate . . ! Como reducir, pero mantiene los valores intermedios en una lista: { 0 2 6 12 } así que 20 1 5 [ 2 * dup ] replicate . ! Repite la cita 5 veces y recoge los resultados en una lista: { 2 4 8 16 32 } 1 [ dup 100 < ] [ 2 * dup ] produce ! Repite la segunda cita hasta que la primera devuelva falso y recopile los resultados: { 2 4 8 16 32 64 128 } ! Si todo lo demás falla, un propósito general a repetir. 1 [ dup 10 < ] [ "Hello" . 1 + ] while ! Escribe "Hello" 10 veces ! Sí, es dificil de leer ! Para eso están los bucles variantes ! Variables ! Normalmente, se espera que los programas de Factor mantengan todos los datos ! en la pila. ! El uso de variables con nombre hace que la refactorización sea más difícil ! (y se llama Factor por una razón) ! Variables globales, si las necesitas: SYMBOL: name ! Crea un nombre como palabra de identificación "Bob" name set-global ! Sin salída name get-global . ! "Bob" ! Las variables locales nombradas se consideran una extensión, pero están ! disponibles ! En una cita .. [| m n ! La cita captura los dos valores principales de la pila en m y n | m n + ] ! Leerlos ! Ou em uma palavra.. :: lword ( -- ) ! Tenga en cuenta los dos puntos dobles para invocar la extensión de variable léxica 2 :> c ! Declara la variable inmutable c para contener 2 c . ; ! Imprimirlo ! En una palabra declarada de esta manera, el lado de entrada de la declaración ! de la pila ! se vuelve significativo y proporciona los valores de las variables en las que ! se capturan los valores de pila :: double ( a -- result ) a 2 * ; ! Las variables se declaran mutables al terminar su nombre con su signo de ! exclamación :: mword2 ( a! -- x y ) ! Capture la parte superior de la pila en la variable mutable a a ! Empujar a a 2 * a! ! Multiplique por 2 y almacenar el resultado en a a ; ! Empujar el nuevo valor de a 5 mword2 ! Pila: 5 10 ! Listas y Secuencias ! Vimos arriba cómo empujar una lista a la pila 0 { 1 2 3 4 } nth ! Acceder a un miembro específico de una lista: 1 10 { 1 2 3 4 } nth ! Error: índice de secuencia fuera de los límites 1 { 1 2 3 4 } ?nth ! Lo mismo que nth si el índice está dentro de los límites: 2 10 { 1 2 3 4 } ?nth ! Sin errores si está fuera de los límites: f { "at" "the" "beginning" } "Append" prefix ! { "Append" "at" "the" "beginning" } { "Append" "at" "the" } "end" suffix ! { "Append" "at" "the" "end" } "in" 1 { "Insert" "the" "middle" } insert-nth ! { "Insert" "in" "the" "middle" } "Concat" "enate" append ! "Concatenate" - strings are sequences too "Concatenate" "Reverse " prepend ! "Reverse Concatenate" { "Concatenate " "seq " "of " "seqs" } concat ! "Concatenate seq of seqs" { "Connect" "subseqs" "with" "separators" } " " join ! "Connect subseqs with separators" ! Y si desea obtener meta, las citas son secuencias y se pueden desmontar 0 [ 2 + ] nth ! 2 1 [ 2 + ] nth ! + [ 2 + ] \ - suffix ! Quotation [ 2 + - ] ``` ## Listo para más? * [Documentación de Factor](http://docs.factorcode.org/content/article-help.home.html) ================================================ FILE: es/forth.md ================================================ --- contributors: - ["Horse M.D.", "http://github.com/HorseMD/"] translators: - ["Zach Larsen", "http://zachariahlarsen.com/"] --- Forth fue criado por Charles H. Moore en los 70s. Forth es un lenguaje imperativo, basado en pila y entorno de programación, siendo usado en proyectos como Open Firmware. También esta usado por NASA. Nota: Este articulo enfoca predominantemente en la Gforth implementación de Forth, pero casi todo de lo que esta escrito aquí debe funcionar en otro sitio. ```forth \ Este es un comentario ( Este es un comentario también pero solo esta usado cuando definiendo palabras. ) \ --------------------------------- Precursor ---------------------------------- \ Todo programación en Forth se hace manipulando el parámetro pila (mas \ común se refiere como "el pila"). 5 2 3 56 76 23 65 \ ok \ estos números se añadieron al pila desde izquierda a derecho. .s \ <7> 5 2 3 56 76 23 65 ok \ En Forth, todo es o una palabra o un numero. \ ------------------------------ Básico Aritmética ------------------------------ \ Aritmética (de hecho casi todas palabras que requieren datos) funciona manipulando datos \ en el pila. 5 4 + \ ok \ `.` saca lo alto resulto desde el pila: . \ 9 ok \ Mas ejemplos de aritmética: 6 7 * . \ 42 ok 1360 23 - . \ 1337 ok 12 12 / . \ 1 ok 13 2 mod . \ 1 ok 99 negate . \ -99 ok -99 abs . \ 99 ok 52 23 max . \ 52 ok 52 23 min . \ 23 ok \ ----------------------------- Pila Manipulación ----------------------------- \ Naturalmente, cuando trabajaremos con el pila, querremos algunos metidos útiles: 3 dup - \ duplicar el primero articulo (1ra ahora igual a 2da): 3 - 3 2 5 swap / \ intercambiar la primera con la segunda elemento: 5 / 2 6 4 5 rot .s \ rotar los tres primero elementos: 4 5 6 4 0 drop 2 / \ sacar el primero articulo (no imprima a la pantalla): 4 / 2 1 2 3 nip .s \ sacar el segundo articulo (similar a drop): 1 3 \ ---------------------- Mas Avanzado Pila Manipulación ---------------------- 1 2 3 4 tuck \ duplicar el primero articulo en el segundo hueco: 1 2 4 3 4 ok 1 2 3 4 over \ duplicar el segundo articulo a la primera del pila: 1 2 3 4 3 ok 1 2 3 4 2 roll \ *mover* el articulo en este posición a la primera del pila: 1 3 4 2 ok 1 2 3 4 2 pick \ *duplicar* el articulo en este posición a la primera del pila: 1 2 3 4 2 ok \ Cuando refiere a pila indices, ellos son basado en cero. \ ------------------------------ Creando Palabras -------------------------------- \ La `:` palabra hace que Forth entra modo de compilar hasta que se ve la `;` palabra. : cuadrado ( n -- n ) dup * ; \ ok 5 cuadrado . \ 25 ok \ Podemos ver lo que hace una palabra también.: see cuadrado \ : cuadrado dup * ; ok \ -------------------------------- Condicionales -------------------------------- \ -1 == cierto, 0 == falso. No obstante, valores que no son cero es usualmente tratado como \ siendo cierto: 42 42 = \ -1 ok 12 53 = \ 0 ok \ `if` es una palabra que solamente compila. `if` `then` . : ?>64 ( n -- n ) dup 64 > if ." Mas que 64!" then ; \ ok 100 ?>64 \ Mas que 64! ok \ Else: : ?>64 ( n -- n ) dup 64 > if ." Mas que 64!" else ." Menos que 64!" then ; 100 ?>64 \ Mas que 64! ok 20 ?>64 \ Menos que 64! ok \ ------------------------------------ Loops ----------------------------------- \ `do` también es una palabra que solamente compila. : miloop ( -- ) 5 0 do cr ." Hola!" loop ; \ ok miloop \ Hola! \ Hola! \ Hola! \ Hola! \ Hola! ok \ `do` espera dos números en el pila: el último numero y el primero numero. \ Podemos recibir el valor del indice mientras damos vuelta con `i`: : uno-a-12 ( -- ) 12 0 do i . loop ; \ ok uno-a-12 \ 0 1 2 3 4 5 6 7 8 9 10 11 12 ok \ `?do` funciona similarmente, pero salta el loop si el último y primero \ números son iguales. : cuadrados ( n -- ) 0 ?do i cuadrado . loop ; \ ok 10 cuadrado \ 0 1 4 9 16 25 36 49 64 81 ok \ cambiar el "paso" con `+loop`: : treces ( n n -- ) ?do i . 3 +loop ; \ ok 15 0 treces \ 0 3 6 9 12 ok \ Indefinido loops empiezan `begin` `until`: : death ( -- ) begin ." Ya hemos llegado?" 0 until ; \ ok \ ---------------------------- Variables y Memoria ---------------------------- \ Use `variable` declarar `edad` ser un variable. variable edad \ ok \ Ahora escribimos 21 a edad con la palabra `!`. 21 edad ! \ ok \ Por fin podemos imprimir nuestro variable usando la "leer" palabra `@`, que agregue el \ valor a la pila, or usa `?` que lee y imprime todo juntos. edad @ . \ 21 ok edad ? \ 21 ok \ Constantes son muy similar, pero no nos importa los direcciones de memoria: 100 constant PUNTA-QUE-AQUA-HIERVA \ ok PUNTA-QUE-AQUA-HIERVA . \ 100 ok \ ----------------------------------- Arrays ----------------------------------- \ Creando arrays es similar a variables, pero necesitamos alocar mas \ memoria a ellos. \ Puede usar `2 cells allot` para crear un array que es sea 3 cédulas de tamaño: variable minumeros 2 cells allot \ ok \ Inicializar todos los valores a 0 minumeros 3 cells erase \ ok \ Alternativamente podemos usar `fill`: minumeros 3 cells 0 fill \ o podemos saltar todo arriba y inicializar con valores específicos: create minumeros 64 , 9001 , 1337 , \ ok (el último `,` es importante!) \ ...que es equivalente a: \ Manualmente escribiendo valores a cada indice: 64 minumeros 0 cells + ! \ ok 9001 minumeros 1 cells + ! \ ok 1337 minumeros 2 cells + ! \ ok \ Leyendo valores en particular array indices: 0 cells minumeros + ? \ 64 ok 1 cells minumeros + ? \ 9001 ok \ Podemos simplificar un poco cuando hacemos una palabra que ayuda cuando manipulando arrays: : de-arr ( n n -- n ) cells + ; \ ok minumeros 2 de-arr ? \ 1337 ok \ Que podemos usar cuando escribimos también: 20 minumeros 1 de-arr ! \ ok minumeros 1 de-arr ? \ 20 ok \ ------------------------------ El Pila de Regreso ------------------------------ \ El pila de regreso se usa para retener punteros a cosas cuando palabras están \ ejecutando otras palabras como loops. \ Ya hemos visto un uso de esto: `i`, que duplica el primero del pila \ de regreso. `i` es equivalente a `r@`. : miloop ( -- ) 5 0 do r@ . loop ; \ ok \ También como leyendo, podemos agregar al pila de regreso y sacarlo: 5 6 4 >r swap r> .s \ 6 5 4 ok \ NOTA: Porque Forth usa el pila de regreso por punteros de palabras, `>r` debe \ siempre ser seguido por un `r>`. \ ------------------------- Flotante Punto Operaciones -------------------------- \ La mayoría Forths evitan el uso de flotante punto operaciones. 8.3e 0.8e f+ f. \ 9.1 ok \ Usualmente agregamos al frente palabras con 'f' cuando usando flotantes: variable miflotantevar \ ok 4.4e miflotantevar f! \ ok miflotantevar f@ f. \ 4.4 ok \ --------------------------------- Notas al Final -------------------------------- \ Usando una palabra que no existe vaciara el pila. No obstante, también hay una palabra \ específicamente por esto: clearstack \ vaciar la pantalla: page \ Cargando Forth archivos: \ s" archivodeforth.fs" included \ Puede listar cada palabra en el diccionario de Forth (pero es una lista gigante!): \ words \ Terminando Gforth: \ bye ``` ## Listo Para Mas? * [Starting Forth](http://www.forth.com/starting-forth/) * [Simple Forth](http://www.murphywong.net/hello/simple.htm) * [Thinking Forth](http://thinking-forth.sourceforge.net/) ================================================ FILE: es/fsharp.md ================================================ --- contributors: - ['Scott Wlaschin', 'http://fsharpforfunandprofit.com/'] translators: - ['Angel Arciniega', 'https://github.com/AngelsProjects'] --- F# es un lenguaje de programación funcional y orientado a objetos. Es gratis y su código fuente está abierto. Se ejecuta en Linux, Mac, Windows y más. Tiene un poderoso sistema de tipado que atrapa muchos errores de tiempo de compilación, pero usa inferencias de tipados que le permiten ser leídos como un lenguaje dinámico. La sintaxis de F# es diferente de los lenguajes que heredan de C. - Las llaves no se usan para delimitar bloques de código. En cambio, se usa sangría (como en Python). - Los espacios se usan para separar parámetros en lugar de comas. Si quiere probar el siguiente código, puede ir a [tryfsharp.org](http://www.tryfsharp.org/Create) y pegarlo en [REPL](https://es.wikipedia.org/wiki/REPL). ```fsharp // Los comentarios de una línea se escibren con una doble diagonal (* Los comentarios multilínea usan parentesis (* . . . *) -final del comentario multilínea- *) // ================================================ // Syntaxis básica // ================================================ // ------ "Variables" (pero no realmente) ------ // La palabra reservada "let" define un valor (inmutable) let miEntero = 5 let miFlotante = 3.14 let miCadena = "hola" // Tenga en cuenta que no es necesario ningún tipado // ------ Listas ------ let dosACinco = [2;3;4;5] // Los corchetes crean una lista con // punto y coma para delimitadores. let unoACinco = 1 :: dosACinco // :: Crea una lista con un nuevo elemento // El resultado es [1;2;3;4;5] let ceroACinco = [0;1] @ dosACinco // @ Concatena dos listas // IMPORTANTE: las comas no se usan para delimitar, // solo punto y coma ! // ------ Funciones ------ // La palabra reservada "let" también define el nombre de una función. let cuadrado x = x * x // Tenga en cuenta que no se usa paréntesis. cuadrado 3 // Ahora, ejecutemos la función. // De nuevo, sin paréntesis. let agregar x y = x + y // ¡No use add (x, y)! Eso significa // algo completamente diferente. agregar 2 3 // Ahora, ejecutemos la función. // Para definir una función en varias líneas, usemos la sangría. // Los puntos y coma no son necesarios. let pares lista = let esPar x = x%2 = 0 // Establece "esPar" como una función anidada List.filter esPar lista // List.filter es una función de la biblioteca // dos parámetros: una función que devuelve un // booleano y una lista en la que trabajar pares unoACinco // Ahora, ejecutemos la función. // Puedes usar paréntesis para aclarar. // En este ejemplo, "map" se ejecuta primero, con dos argumentos, // entonces "sum" se ejecuta en el resultado. // Sin los paréntesis, "List.map" se pasará como argumento a List.sum. let sumaDeCuadradosHasta100 = List.sum ( List.map cuadrado [1..100] ) // Puedes redirigir la salida de una función a otra con "|>" // Redirigir datos es muy común en F#, como con los pipes de UNIX. // Aquí está la misma función sumOfSquares escrita usando pipes let sumaDeCuadradosHasta100piped = [1..100] |> List.map cuadrado |> List.sum // "cuadrado" se declara antes // Puede definir lambdas (funciones anónimas) gracias a la palabra clave "fun" let sumaDeCuadradosHasta100ConFuncion = [1..100] |> List.map (fun x -> x*x) |> List.sum // En F#, no hay palabra clave "return". Una función siempre regresa // el valor de la última expresión utilizada. // ------ Coincidencia de patrones ------ // Match..with .. es una sobrecarga de la condición de case/ switch. let coincidenciaDePatronSimple = let x = "a" match x with | "a" -> printfn "x es a" | "b" -> printfn "x es b" | _ -> printfn "x es algo mas" // guion bajo corresponde con todos los demás // F# no permite valores nulos por defecto - debe usar el tipado de Option // y luego coincide con el patrón. // Some(..) y None son aproximadamente análogos a los envoltorios Nullable let valorValido = Some(99) let valorInvalido = None // En este ejemplo, match..with encuentra una coincidencia con "Some" y "None", // y muestra el valor de "Some" al mismo tiempo. let coincidenciaDePatronDeOpciones entrada = match entrada with | Some i -> printfn "la entrada es un int=%d" i | None -> printfn "entrada faltante" coincidenciaDePatronDeOpciones validValue coincidenciaDePatronDeOpciones invalidValue // ------ Viendo ------ // Las funciones printf/printfn son similares a las funciones // Console.Write/WriteLine de C#. printfn "Imprimiendo un int %i, a float %f, a bool %b" 1 2.0 true printfn "Un string %s, y algo generico %A" "hola" [1;2;3;4] // También hay funciones printf/sprintfn para formatear datos // en cadena. Es similar al String.Format de C#. // ================================================ // Mas sobre funciones // ================================================ // F# es un verdadero lenguaje funcional - las funciones son // entidades de primer nivel y se pueden combinar fácilmente // para crear construcciones poderosas // Los módulos se utilizan para agrupar funciones juntas. // Se requiere sangría para cada módulo anidado. module EjemploDeFuncion = // define una función de suma simple let agregar x y = x + y // uso básico de una función let a = agregar 1 2 printfn "1+2 = %i" a // aplicación parcial para "hornear en" los parámetros (?) let agregar42 = agregar 42 let b = agregar42 1 printfn "42+1 = %i" b // composición para combinar funciones let agregar1 = agregar 1 let agregar2 = agregar 2 let agregar3 = agregar1 >> agregar2 let c = agregar3 7 printfn "3+7 = %i" c // funciones de primer nivel [1..10] |> List.map agregar3 |> printfn "la nueva lista es %A" // listas de funciones y más let agregar6 = [agregar1; agregar2; agregar3] |> List.reduce (>>) let d = agregar6 7 printfn "1+2+3+7 = %i" d // ================================================ // Lista de colecciones // ================================================ // Il y a trois types de collection ordonnée : // * Les listes sont les collections immutables les plus basiques // * Les tableaux sont mutables et plus efficients // * Les séquences sont lazy et infinies (e.g. un enumerator) // // Des autres collections incluent des maps immutables et des sets // plus toutes les collections de .NET module EjemplosDeLista = // las listas utilizan corchetes let lista1 = ["a";"b"] let lista2 = "c" :: lista1 // :: para una adición al principio let lista3 = lista1 @ lista2 // @ para la concatenación // Lista de comprensión (alias generadores) let cuadrados = [for i in 1..10 do yield i*i] // Generador de números primos let rec tamiz = function | (p::xs) -> p :: tamiz [ for x in xs do if x % p > 0 then yield x ] | [] -> [] let primos = tamiz [2..50] printfn "%A" primos // coincidencia de patrones para listas let listaDeCoincidencias unaLista = match unaLista with | [] -> printfn "la lista esta vacia" | [primero] -> printfn "la lista tiene un elemento %A " primero | [primero; segundo] -> printfn "la lista es %A y %A" primero segundo | _ -> printfn "la lista tiene mas de dos elementos" listaDeCoincidencias [1;2;3;4] listaDeCoincidencias [1;2] listaDeCoincidencias [1] listaDeCoincidencias [] // Récursion en utilisant les listes let rec suma unaLista = match unaLista with | [] -> 0 | x::xs -> x + suma xs suma [1..10] // ----------------------------------------- // Funciones de la biblioteca estándar // ----------------------------------------- // mapeo let agregar3 x = x + 3 [1..10] |> List.map agregar3 // filtrado let par x = x % 2 = 0 [1..10] |> List.filter par // mucho más - consulte la documentación module EjemploDeArreglo = // los arreglos usan corchetes con barras. let arreglo1 = [| "a";"b" |] let primero = arreglo1.[0] // se accede al índice usando un punto // la coincidencia de patrones de los arreglos es la misma que la de las listas let coincidenciaDeArreglos una Lista = match unaLista with | [| |] -> printfn "la matriz esta vacia" | [| primero |] -> printfn "el arreglo tiene un elemento %A " primero | [| primero; second |] -> printfn "el arreglo es %A y %A" primero segundo | _ -> printfn "el arreglo tiene mas de dos elementos" coincidenciaDeArreglos [| 1;2;3;4 |] // La biblioteca estándar funciona como listas [| 1..10 |] |> Array.map (fun i -> i+3) |> Array.filter (fun i -> i%2 = 0) |> Array.iter (printfn "el valor es %i. ") module EjemploDeSecuencia = // Las secuencias usan llaves let secuencia1 = seq { yield "a"; yield "b" } // Las secuencias pueden usar yield y // puede contener subsecuencias let extranio = seq { // "yield" agrega un elemento yield 1; yield 2; // "yield!" agrega una subsecuencia completa yield! [5..10] yield! seq { for i in 1..10 do if i%2 = 0 then yield i }} // prueba extranio |> Seq.toList // Las secuencias se pueden crear usando "unfold" // Esta es la secuencia de fibonacci let fib = Seq.unfold (fun (fst,snd) -> Some(fst + snd, (snd, fst + snd))) (0,1) // prueba let fib10 = fib |> Seq.take 10 |> Seq.toList printf "Los primeros 10 fib son %A" fib10 // ================================================ // Tipos de datos // ================================================ module EejemploDeTipoDeDatos = // Todos los datos son inmutables por defecto // las tuplas son tipos anónimos simples y rápidos // - Usamos una coma para crear una tupla let dosTuplas = 1,2 let tresTuplas = "a",2,true // Combinación de patrones para desempaquetar let x,y = dosTuplas // asignado x=1 y=2 // ------------------------------------ // Los tipos de registro tienen campos con nombre // ------------------------------------ // Usamos "type" con llaves para definir un tipo de registro type Persona = {Nombre:string; Apellido:string} // Usamos "let" con llaves para crear un registro let persona1 = {Nombre="John"; Apellido="Doe"} // Combinación de patrones para desempaquetar let {Nombre=nombre} = persona1 // asignado nombre="john" // ------------------------------------ // Los tipos de unión (o variantes) tienen un conjunto de elección // Solo un caso puede ser válido a la vez. // ------------------------------------ // Usamos "type" con barra/pipe para definir una unión estándar type Temp = | GradosC of float | GradosF of float // Una de estas opciones se usa para crear una let temp1 = GradosF 98.6 let temp2 = GradosC 37.0 // Coincidencia de patrón en todos los casos para desempaquetar (?) let imprimirTemp = function | GradosC t -> printfn "%f gradC" t | GradosF t -> printfn "%f gradF" t imprimirTemp temp1 imprimirTemp temp2 // ------------------------------------ // Tipos recursivos // ------------------------------------ // Los tipos se pueden combinar recursivamente de formas complejas // sin tener que crear subclases type Empleado = | Trabajador of Persona | Gerente of Empleado lista let jdoe = {Nombre="John";Apellido="Doe"} let trabajador = Trabajador jdoe // ------------------------------------ // Modelado con tipados (?) // ------------------------------------ // Los tipos de unión son excelentes para modelar el estado sin usar banderas (?) type DireccionDeCorreo = | DireccionDeCorreoValido of string | DireccionDeCorreoInvalido of string let intentarEnviarCorreo correoElectronico = match correoElectronico with // uso de patrones de coincidencia | DireccionDeCorreoValido direccion -> () // enviar | DireccionDeCorreoInvalido direccion -> () // no enviar // Combinar juntos, los tipos de unión y tipos de registro // ofrece una base excelente para el diseño impulsado por el dominio. // Puedes crear cientos de pequeños tipos que reflejarán fielmente // el dominio. type ArticuloDelCarrito = { CodigoDelProducto: string; Cantidad: int } type Pago = Pago of float type DatosActivosDelCarrito = { ArticulosSinPagar: ArticuloDelCarrito lista } type DatosPagadosDelCarrito = { ArticulosPagados: ArticuloDelCarrito lista; Pago: Pago} type CarritoDeCompras = | CarritoVacio // sin datos | CarritoActivo of DatosActivosDelCarrito | CarritoPagado of DatosPagadosDelCarrito // ------------------------------------ // Comportamiento nativo de los tipos // ------------------------------------ // Los tipos nativos tienen el comportamiento más útil "listo para usar", sin ningún código para agregar. // * Inmutabilidad // * Bonita depuración de impresión // * Igualdad y comparación // * Serialización // La impresión bonita se usa con %A printfn "dosTuplas=%A,\nPersona=%A,\nTemp=%A,\nEmpleado=%A" dosTuplas persona1 temp1 trabajador // La igualdad y la comparación son innatas // Aquí hay un ejemplo con tarjetas. type JuegoDeCartas = Trebol | Diamante | Espada | Corazon type Rango = Dos | Tres | Cuatro | Cinco | Seis | Siete | Ocho | Nueve | Diez | Jack | Reina | Rey | As let mano = [ Trebol,As; Corazon,Tres; Corazon,As; Espada,Jack; Diamante,Dos; Diamante,As ] // orden List.sort mano |> printfn "la mano ordenada es (de menos a mayor) %A" List.max mano |> printfn "la carta más alta es%A" List.min mano |> printfn "la carta más baja es %A" // ================================================ // Patrones activos // ================================================ module EjemplosDePatronesActivos = // F# tiene un tipo particular de coincidencia de patrón llamado "patrones activos" // donde el patrón puede ser analizado o detectado dinámicamente. // "clips de banana" es la sintaxis de los patrones activos // por ejemplo, definimos un patrón "activo" para que coincida con los tipos de "caracteres" ... let (|Digito|Latra|EspacioEnBlanco|Otros|) ch = if System.Char.IsDigit(ch) then Digito else if System.Char.IsLetter(ch) then Letra else if System.Char.IsWhiteSpace(ch) then EspacioEnBlanco else Otros // ... y luego lo usamos para hacer que la lógica de análisis sea más clara let ImprimirCaracter ch = match ch with | Digito -> printfn "%c es un Digito" ch | Letra -> printfn "%c es una Letra" ch | Whitespace -> printfn "%c es un Espacio en blanco" ch | _ -> printfn "%c es algo mas" ch // ver una lista ['a';'b';'1';' ';'-';'c'] |> List.iter ImprimirCaracter // ----------------------------------------- // FizzBuzz usando patrones activos // ----------------------------------------- // Puede crear un patrón de coincidencia parcial también // Solo usamos un guión bajo en la definición y devolvemos Some si coincide. let (|MultDe3|_|) i = if i % 3 = 0 then Some MultDe3 else None let (|MultDe5|_|) i = if i % 5 = 0 then Some MultDe5 else None // la función principal let fizzBuzz i = match i with | MultDe3 & MultDe5 -> printf "FizzBuzz, " | MultDe3 -> printf "Fizz, " | MultDe5 -> printf "Buzz, " | _ -> printf "%i, " i // prueba [1..20] |> List.iter fizzBuzz // ================================================ // concisión // ================================================ module EjemploDeAlgoritmo = // F# tiene una alta relación señal / ruido, lo que permite leer el código // casi como un algoritmo real // ------ Ejemplo: definir una función sumaDeCuadrados ------ let sumaDeCuadrados n = [1..n] // 1) Tome todos los números del 1 al n |> List.map cuadrado // 2) Elevar cada uno de ellos al cuadrado |> List.sum // 3) Realiza su suma // prueba sumaDeCuadrados 100 |> printfn "Suma de cuadrados = %A" // ------ Ejemplo: definir una función de ordenación ------ let rec ordenar lista = match lista with // Si la lista está vacía | [] -> [] // devolvemos una lista vacía // si la lista no está vacía | primerElemento::otrosElementos -> // tomamos el primer elemento let elementosMasPequenios = // extraemos los elementos más pequeños otrosElementos // tomamos el resto |> List.filter (fun e -> e < primerElemento) |> ordenar // y los ordenamos let elementosMasGrandes = // extraemos el mas grande otrosElementos // de los que permanecen |> List.filter (fun e -> e >= primerElemento) |> ordenar // y los ordenamos // Combinamos las 3 piezas en una nueva lista que devolvemos List.concat [elementosMasPequenios; [primerElemento]; elementosMasGrandes] // prueba ordenar [1;5;23;18;9;1;3] |> printfn "Ordenado = %A" // ================================================ // Código asíncrono // ================================================ module AsyncExample = // F# incluye características para ayudar con el código asíncrono // sin conocer la "pirámide del destino" // // El siguiente ejemplo descarga una secuencia de página web en paralelo. open System.Net open System open System.IO open Microsoft.FSharp.Control.CommonExtensions // Recuperar el contenido de una URL de forma asincrónica let extraerUrlAsync url = async { // La palabra clave "async" y llaves // crear un objeto "asincrónico" let solicitud = WebRequest.Create(Uri(url)) use! respuesta = solicitud.AsyncGetResponse() // use! es una tarea asincrónica use flujoDeDatos = resp.GetResponseStream() // "use" dispara automáticamente la funcion close() // en los recursos al final de las llaves use lector = new IO.StreamReader(flujoDeDatos) let html = lector.ReadToEnd() printfn "terminó la descarga %s" url } // una lista de sitios para informar let sitios = ["http://www.bing.com"; "http://www.google.com"; "http://www.microsoft.com"; "http://www.amazon.com"; "http://www.yahoo.com"] // ¡Aqui vamos! sitios |> List.map extraerUrlAsync // crear una lista de tareas asíncrona |> Async.Parallel // decirle a las tareas que se desarrollan en paralelo |> Async.RunSynchronously // ¡Empieza! // ================================================ // Compatibilidad .NET // ================================================ module EjemploCompatibilidadNet = // F# puede hacer casi cualquier cosa que C# pueda hacer, y se ajusta // perfectamente con bibliotecas .NET o Mono. // ------- Trabaja con las funciones de las bibliotecas existentes ------- let (i1success,i1) = System.Int32.TryParse("123"); if i1success then printfn "convertido como %i" i1 else printfn "conversion fallida" // ------- Implementar interfaces sobre la marcha! ------- // Crea un nuevo objeto que implemente IDisposable let crearRecurso name = { new System.IDisposable with member this.Dispose() = printfn "%s creado" name } let utilizarYDisponerDeRecursos = use r1 = crearRecurso "primer recurso" printfn "usando primer recurso" for i in [1..3] do let nombreDelRecurso = sprintf "\tinner resource %d" i use temp = crearRecurso nombreDelRecurso printfn "\thacer algo con %s" nombreDelRecurso use r2 = crearRecurso "segundo recurso" printfn "usando segundo recurso" printfn "hecho." // ------- Código orientado a objetos ------- // F# es también un verdadero lenguaje OO. // Admite clases, herencia, métodos virtuales, etc. // interfaz de tipo genérico type IEnumerator<'a> = abstract member Actual : 'a abstract MoverSiguiente : unit -> bool // Clase base abstracta con métodos virtuales [] type Figura() = // propiedades de solo lectura abstract member Ancho : int with get abstract member Alto : int with get // método no virtual member this.AreaDelimitadora = this.Alto * this.Ancho // método virtual con implementación de la clase base abstract member Imprimir : unit -> unit default this.Imprimir () = printfn "Soy una Figura" // clase concreta que hereda de su clase base y sobrecarga type Rectangulo(x:int, y:int) = inherit Figura() override this.Ancho = x override this.Alto = y override this.Imprimir () = printfn "Soy un Rectangulo" // prueba let r = Rectangulo(2,3) printfn "La anchura es %i" r.Ancho printfn "El area es %i" r.AreaDelimitadora r.Imprimir() // ------- extensión de método ------- // Al igual que en C#, F# puede extender las clases existentes con extensiones de método. type System.String with member this.EmpiezaConA = this.EmpiezaCon "A" // prueba let s = "Alice" printfn "'%s' empieza con una 'A' = %A" s s.EmpiezaConA // ------- eventos ------- type MiBoton() = let eventoClick = new Event<_>() [] member this.AlHacerClick = eventoClick.Publish member this.PruebaEvento(arg) = eventoClick.Trigger(this, arg) // prueba let miBoton = new MiBoton() miBoton.AlHacerClick.Add(fun (sender, arg) -> printfn "Haga clic en el evento con arg=%O" arg) miBoton.PruebaEvento("Hola Mundo!") ``` ## Más información Para más demostraciones de F#, visite el sitio [Try F#](http://www.tryfsharp.org/Learn), o sigue la serie [why use F#](http://fsharpforfunandprofit.com/why-use-fsharp/). Aprenda más sobre F# en [fsharp.org](http://fsharp.org/). ================================================ FILE: es/git.md ================================================ --- contributors: - ["Jake Prather", "http://github.com/JakeHP"] translators: - ["Raúl Ascencio", "http://rscnt.github.io"] --- Git es un sistema de control de versiones distribuido diseñado para manejar cualquier tipo de proyecto, ya sea grande o pequeño, con velocidad y eficiencia. Git realiza esto haciendo "snapshots" del proyecto, con ello permite versionar y administrar nuestro código fuente. ## Versionamiento, conceptos. ### ¿Qué es el control de versiones? El control de versiones es un sistema que guarda todos los cambios realizados en uno o varios archivos, a lo largo del tiempo. ### Versionamiento centralizado vs versionamiento distribuido. + El versionamiento centralizado se enfoca en sincronizar, rastrear, y respaldar archivos. + El versionamiento distribuido se enfoca en compartir los cambios realizados. Cada cambio tiene un único identificador. + El versionamiento distribuido no tiene una estructura definida, incluso se puede mantener el estilo de los repositorios SVN con git. [Información adicional](https://git-scm.com/book/es/v2/Inicio---Sobre-el-Control-de-Versiones-Acerca-del-Control-de-Versiones) ### ¿Por qué usar Git? * Se puede trabajar sin conexión. * ¡Colaborar con otros es sencillo!. * Derivar, crear ramas del proyecto (aka: Branching) es fácil. * Combinar (aka: Merging) * Git es rápido. * Git es flexible. ## Arquitectura de Git. ### Repositorio Un repositorio es un conjunto de archivos, directorios, registros, cambios (aka: commits), y encabezados (aka: heads). Imagina que un repositorio es una clase, y que sus atributos otorgan acceso al historial del elemento, además de otras cosas. Un repositorio esta compuesto por la carpeta .git y un "árbol de trabajo". ### Directorio .git (componentes del repositorio) El directorio .git contiene todas las configuraciones, registros, branches, HEAD y mas. [Lista detallada.](https://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html) ### Directorio de trabajo (componentes del repositorio) Es básicamente los directorios y archivos dentro del repositorio. La mayoría de las veces se le llama "directorio de trabajo". ### Índice (componentes del directorio .git) El índice es el área de inicio en git. Es básicamente la capa que separa el directorio de trabajo del repositorio en git. Esto otorga a los desarrolladores más poder sobre lo que se envía y se recibe del repositorio. ### Commit (aka: cambios) Un commit es una captura de un conjunto de cambios, o modificaciones hechas en el directorio de trabajo. Por ejemplo, si se añaden 5 archivos, se eliminan 2, estos cambios se almacenarán en un commit (aka: captura). Este commit puede ser o no ser enviado (aka: "pusheado") hacia un repositorio. ### Branch (rama) Un "branch", es escencialmente un apuntador hacia el último commit (cambio registrado) que se ha realizado. A medida que se realizan más commits, este apuntador se actualizará automaticamente hacia el ultimo commit. ### "HEAD" y "head" (componentes del directorio .git) "HEAD" es un apuntador hacia la rama (branch) que se esta utilizando. Un repositorio solo puede tener un HEAD activo. En cambio "head", es un apuntador a cualquier commit realizado, un repositorio puede tener cualquier número de "heads". ## Comandos. ### init Crear un repositorio de git vacio. Las configuraciones, información almacenada y demás son almacenadas en el directorio ".git". ```bash $ git init ``` ### config Se utiliza para configurar las opciones ya sea globalmente, o solamente en el repositorio. ```bash # Imprime y guarda algunas variables de configuracion básicas. (Globalmente) $ git config --global user.email $ git config --global user.name $ git config --global user.email "corre@gmail.com" $ git config --global user.name "nombre" ``` [Más sobre git config.](https://git-scm.com/book/es/v2/Personalizaci%c3%b3n-de-Git-Configuraci%c3%b3n-de-Git) ### help Otorga un accceso rápido a una guía extremadamente detallada de cada comando en git. O puede ser usada simplemente como un recordatorio de estos. ```bash # Una vista rápida de los comandos disponibles. $ git help # Chequear todos los comandos disponibles $ git help -a # Obtener ayuda especifica de un comando - manual de usuario # git help $ git help add $ git help commit $ git help init ``` ### status Muestra las diferencias entre el archivo índice y el commit al cual apunta el HEAD actualmente. ```bash # Mostrará el "branch", archivos sin añadir al repo, cambios y otras # diferencias $ git status # Devuelve ayuda sobre el comando status. $ git help status ``` ### add Para añadir archivos al árbol (directorio, repositorio) de trabajo. Si no se utiliza `git add`, los nuevos archivos no se añadirán al arbol de trabajo, por lo que no se incluirán en los commits (cambios). ```bash # Añade un archivo en el directorio de trabajo actual. $ git add FooBar.java # Añade un archivo que se encuentra bajo un directorio. $ git add /directorio/del/archivo/Foo.c # Soporte para expresiones regulares! $ git add ./*.py ``` ### branch Administra las ramas del repositorio ("branches"). Puedes ver, editar, crear y borrar ramas ("branches"), usando este comando. ```bash # lista todas las ramas (remotas y locales) $ git branch -a # Añadir una nueva rama ("branch"). $ git branch branchNueva # Eliminar una rama. $ git branch -d branchFoo # Renombrar una rama. # git branch -m $ git branch -m youngling padawan # Editar la descripcion de la rama. $ git branch master --edit-description ``` ### checkout Actualiza todos los archivos en el directorio de trabajo para que sean igual que las versiones almacenadas en el índice, o en un árbol de trabajo especificado. ```bash # Despachar un repositorio. - Por defecto la master branch. (la rama principal llamada 'master') $ git checkout # Despacha una rama especifica. $ git checkout padawan # Crea una nueva rama y cambia hacia ella, es igual a utilizar: "git brach jedi; git checkout jedi" $ git checkout -b jdei ``` ### clone Clona, o copia, un repositorio existente en un nuevo directorio. También añade el seguimiento hacia las ramas existentes del repositorio que ha sido clonado, lo que permite subir (push) los archivos hacia una rama remota. ```bash # Clonar la repo de jquery. $ git clone https://github.com/jquery/jquery.git ``` ### commit Almacena el contenido actual del índice en un nuevo "commit". Este commit contiene los cambios hechos más un resumen proporcionado por el desarrollador. ```bash # realizar un commit y añadirle un mensaje. $ git commit -m "jedi anakin wil be - jedis.list" ``` ### diff Muestra las diferencias entre un archivo en el directorio de trabajo, el índice y los commits. ```bash # Muestra la diferencia entre un directorio de trabajo y el índice. $ git diff # Muestra la diferencia entre el índice y los commits más recientes. $ git diff --cached # Muestra la diferencia entre el directorio de trabajo y el commit más reciente. $ git diff HEAD ``` ### grep Permite realizar una busqueda rápida en un repositorio. Configuraciones opcionales: ```bash # Gracias a Travis Jeffery por compartir lo siguiente. # Permite mostrar numeros de lineas en la salida de grep. $ git config --global grep.lineNumber true # Realiza una búsqueda mas legible, incluyendo agrupación. $ git config --global alias.g "grep --break --heading --line-number" ``` ```bash # Busca por "unaVariable" en todos los archivos .java $ git grep 'unaVariable' -- '*.java' # Busca por una línea que contenga "nombreArreglo" y "agregar" o "remover" $ git grep -e 'nombreArreglo' --and \( -e agregar -e remover \) ``` Más ejemplos: - [Git Grep Ninja](https://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja) ### log Muestra los commits (cambios) registrados en el repositorio. ```bash # Muestra todos los commits. $ git log # Muestra un numero x de commits. $ git log -n 10 # Muestra solo los commits que se han combinado en el historial. $ git log --merges ``` ### merge Combina los cambios de commits realizados externamente dentro de la rama en la que se trabaja. ```bash # Combina la rama especificada en la rama actual. $ git merge jediMaster # Siempre genere un solo merge commit cuando se utiliza merge. $ git merge --no-ff jediMaster ``` ### mv Renombra o mueve un archivo ```bash # Renombrando un archivo. $ git mv HolaMundo.c AdiosMundo.c # Moviendo un archivo. $ git mv HolaOtraVezMundo.c ./nuevo/directorio/NuevoArchivo.c # Sustituye un archivo. $ git mv -f archivoA archivoB ``` ### pull Trae los cambios de un repositorio y los combina en otro en una rama diferente. ```bash # Actualiza el repositorio local, combinando los nuevos cambios # de las ramas remotas "origin" y "master". # git pull $ git pull origin master ``` ### push Envía y combina los cambios de un repositorio local a un repositorio y rama remotos. ```bash # Envía y combina cambios de un repositorio local hacia un repositorio remoto # llamados "origin" y "master", respectivamente. # git push # git push => por defecto es lo mismo que poner => git push origin master $ git push origin master ``` ### rebase Toma todos los cambios que fueron registrados en una rama, y los repite dentro de otra rama. *No reescribe los commits que se han empujado antes a un repositorio público.* ```bash # Integrar ramaExperimento dentro de la rama "master" # git rebase $ git rebase master experimentBranch ``` [Información adicional.](https://git-scm.com/book/es/v2/Ramificaciones-en-Git-Reorganizar-el-Trabajo-Realizado) ### reset (precaución) Reinicia el HEAD actual hacia un estado especificado. Esto permite deshacer combinaciones (merges), pulls, commits, adds y más. Es un comando útil, pero tambien peligroso si no se sabe lo que se hace. ```bash # Reinicia el área principal, con el último cambio registrado. (deja los # directorios sin cambios) $ git reset # Reinicia el área principal, con el último cambio registrado, y reescribe el # directorio de trabajo. $ git reset --hard # Mueve la rama actual hacia el commit especificado (no realiza cambios a los # directorios), todos los cambios aún existen el directorio. $ git reset 31f2bb1 # Mueve la rama actual devuelta a un commit especificado, así como el # directorio (borra todos los cambios que no fueron registrados y todos los # cambios realizados después del commit especificado). $ git reset --hard 31f2bb1 ``` ### rm Lo contrario de git add, git rm elimina los archivos del directorio de trabajo actual. ```bash # Elimina FooBar.c $ git rm FooBar.c # Elimina un archivo de un directorio. $ git rm /directorio/del/archivo/FooBar.c ``` ## Información Adicional * [Udemy tutorial de Git: Una guía completa](https://blog.udemy.com/git-tutorial-a-comprehensive-guide/) * [Inmersión Git - Una visita guiada caminando a través de los fundamentos de git](https://gitimmersion.com/) * [git-scm - Video-tutoriales](https://git-scm.com/videos) * [Atlassian Git - Tutoriales y Flujos de trabajo](https://www.atlassian.com/git/) * [git - la guía sencilla](https://rogerdudler.github.io/git-guide/index.es.html) * [Pro Git](https://git-scm.com/book/es/v2) * [Una introducción a Git y GitHub para principiantes (Tutorial)](https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners) * [Git para informáticos](https://eagain.net/articles/git-for-computer-scientists/) ================================================ FILE: es/go.md ================================================ --- contributors: - ["Sonia Keys", "https://github.com/soniakeys"] - ["Christopher Bess", "https://github.com/cbess"] - ["Jesse Johnson", "https://github.com/holocronweaver"] - ["Quint Guvernator", "https://github.com/qguv"] - ["Jose Donizetti", "https://github.com/josedonizetti"] - ["Alexej Friesen", "https://github.com/heyalexej"] translators: - ["Adrian Espinosa", "http://www.adrianespinosa.com"] - ["Jesse Johnson", "https://github.com/holocronweaver"] - ["Nacho Pacheco -- Feb/2015", "https://github.com/gitnacho"] --- Go fue creado por la necesidad de hacer el trabajo rápidamente. No es la última tendencia en informática, pero es la forma nueva y más rápida de resolver problemas reales. Tiene conceptos familiares de lenguajes imperativos con tipado estático. Es rápido compilando y rápido al ejecutar, añade una concurrencia fácil de entender para las CPUs de varios núcleos de hoy día, y tiene características que ayudan con la programación a gran escala. Go viene con una biblioteca estándar muy buena y una comunidad entusiasta. ```go // Comentario de una sola línea /* Comentario multilínea */ // La cláusula `package` aparece al comienzo de cada fichero fuente. // `main` es un nombre especial que declara un ejecutable en vez de una // biblioteca. package main // La instrucción `import` declara los paquetes de bibliotecas referidos // en este fichero. import ( "fmt" // Un paquete en la biblioteca estándar de Go. "io/ioutil" // Implementa algunas útiles funciones de E/S. m "math" // Biblioteca de matemáticas con alias local m. "net/http" // Sí, ¡un servidor web! "strconv" // Conversiones de cadenas. ) // Definición de una función. `main` es especial. Es el punto de entrada // para el ejecutable. Te guste o no, Go utiliza llaves. func main() { // Println imprime una línea a stdout. // Llámalo con el nombre del paquete, fmt. fmt.Println("¡Hola mundo!") // Llama a otra función de este paquete. másAlláDelHola() } // Las funciones llevan parámetros entre paréntesis. // Si no hay parámetros, los paréntesis siguen siendo obligatorios. func másAlláDelHola() { var x int // Declaración de una variable. // Las variables se deben declarar antes de utilizarlas. x = 3 // Asignación de variable. // Declaración "corta" con := para inferir el tipo, declarar y asignar. y := 4 suma, producto := aprendeMúltiple(x, y) // La función devuelve dos // valores. fmt.Println("suma:", suma, "producto:", producto) // Simple salida. aprendeTipos() // < y minutos, ¡aprende más! } // Las funciones pueden tener parámetros y (¡múltiples!) valores de // retorno. func aprendeMúltiple(x, y int) (suma, producto int) { return x + y, x * y // Devuelve dos valores. } // Algunos tipos incorporados y literales. func aprendeTipos() { // La declaración corta suele darte lo que quieres. s := "¡Aprende Go!" // tipo cadena. s2 := `Un tipo cadena "puro" puede incluir saltos de línea.` // mismo tipo cadena // Literal no ASCII. Los ficheros fuente de Go son UTF-8. g := 'Σ' // Tipo rune, un alias de int32, alberga un carácter unicode. f := 3.14159 // float64, el estándar IEEE-754 de coma flotante 64-bit. c := 3 + 4i // complex128, representado internamente por dos float64. // Sintaxis var con iniciadores. var u uint = 7 // Sin signo, pero la implementación depende del tamaño // como en int. var pi float32 = 22. / 7 // Sintaxis de conversión con una declaración corta. n := byte('\n') // byte es un alias para uint8. // Los Arreglos tienen un tamaño fijo a la hora de compilar. var a4 [4]int // Un arreglo de 4 ints, iniciados a 0. a3 := [...]int{3, 1, 5} // Un arreglo iniciado con un tamaño fijo de tres // elementos, con valores 3, 1 y 5. // Los Sectores tienen tamaño dinámico. Los arreglos y sectores tienen // sus ventajas y desventajas pero los casos de uso para los sectores // son más comunes. s3 := []int{4, 5, 9} // Comparar con a3. No hay puntos suspensivos. s4 := make([]int, 4) // Asigna sectores de 4 ints, iniciados a 0. var d2 [][]float64 // Solo declaración, sin asignación. bs := []byte("a sector") // Sintaxis de conversión de tipo. // Debido a que son dinámicos, los sectores pueden crecer bajo demanda. // Para añadir elementos a un sector, se utiliza la función incorporada // append(). // El primer argumento es el sector al que se está anexando. Comúnmente, // la variable del arreglo se actualiza en su lugar, como en el // siguiente ejemplo. sec := []int{1, 2 , 3} // El resultado es un sector de longitud 3. sec = append(sec, 4, 5, 6) // Añade 3 elementos. El sector ahora tiene una // longitud de 6. fmt.Println(sec) // El sector actualizado ahora es [1 2 3 4 5 6] // Para anexar otro sector, en lugar de la lista de elementos atómicos // podemos pasar una referencia a un sector o un sector literal como // este, con elipsis al final, lo que significa tomar un sector y // desempacar sus elementos, añadiéndolos al sector sec. sec = append(sec, []int{7, 8, 9} ...) // El segundo argumento es un // sector literal. fmt.Println(sec) // El sector actualizado ahora es [1 2 3 4 5 6 7 8 9] p, q := aprendeMemoria() // Declara p, q para ser un tipo puntero a // int. fmt.Println(*p, *q) // * sigue un puntero. Esto imprime dos ints. // Los Mapas son arreglos asociativos dinámicos, como los hash o // diccionarios de otros lenguajes. m := map[string]int{"tres": 3, "cuatro": 4} m["uno"] = 1 // Las variables no utilizadas en Go producen error. // El guión bajo permite "utilizar" una variable, pero descartar su // valor. _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs // Esto cuenta como utilización de variables. fmt.Println(s, c, a4, s3, d2, m) aprendeControlDeFlujo() // Vuelta al flujo. } // Es posible, a diferencia de muchos otros lenguajes tener valores de // retorno con nombre en las funciones. // Asignar un nombre al tipo que se devuelve en la línea de declaración de // la función nos permite volver fácilmente desde múltiples puntos en una // función, así como sólo utilizar la palabra clave `return`, sin nada // más. func aprendeRetornosNombrados(x, y int) (z int) { z = x * y return // aquí z es implícito, porque lo nombramos antes. } // Go posee recolector de basura. Tiene punteros pero no aritmética de // punteros. Puedes cometer errores con un puntero nil, pero no // incrementando un puntero. func aprendeMemoria() (p, q *int) { // Los valores de retorno nombrados q y p tienen un tipo puntero // a int. p = new(int) // Función incorporada que reserva memoria. // La asignación de int se inicia a 0, p ya no es nil. s := make([]int, 20) // Reserva 20 ints en un solo bloque de memoria. s[3] = 7 // Asigna uno de ellos. r := -2 // Declara otra variable local. return &s[3], &r // & toma la dirección de un objeto. } func cálculoCaro() float64 { return m.Exp(10) } func aprendeControlDeFlujo() { // La declaración If requiere llaves, pero no paréntesis. if true { fmt.Println("ya relatado") } // El formato está estandarizado por la orden "go fmt." if false { // Abadejo. } else { // Relamido. } // Utiliza switch preferentemente para if encadenados. x := 42.0 switch x { case 0: case 1: case 42: // Los cases no se mezclan, no requieren de "break". case 43: // No llega. } // Como if, for no utiliza paréntesis tampoco. // Variables declaradas en for e if son locales a su ámbito. for x := 0; x < 3; x++ { // ++ es una instrucción. fmt.Println("iteración", x) } // aquí x == 42. // For es la única instrucción de bucle en Go, pero tiene formas // alternativas. for { // Bucle infinito. break // ¡Solo bromeaba! continue // No llega. } // Puedes usar `range` para iterar en un arreglo, un sector, una // cadena, un mapa o un canal. // `range` devuelve o bien, un canal o de uno a dos valores (arreglo, // sector, cadena y mapa). for clave, valor := range map[string]int{"uno": 1, "dos": 2, "tres": 3} { // por cada par en el mapa, imprime la clave y el valor fmt.Printf("clave=%s, valor=%d\n", clave, valor) } // Como en for, := en una instrucción if significa declarar y asignar // primero, luego comprobar y > x. if y := cálculoCaro(); y > x { x = y } // Las funciones literales son "cierres". granX := func() bool { return x > 100 // Referencia a x declarada encima de la instrucción // switch. } fmt.Println("granX:", granX()) // cierto (la última vez asignamos // 1e6 a x). x /= 1.3e3 // Esto hace a x == 1300 fmt.Println("granX:", granX()) // Ahora es falso. // Es más las funciones literales se pueden definir y llamar en línea, // actuando como un argumento para la función, siempre y cuando: // a) la función literal sea llamada inmediatamente (), // b) el tipo del resultado sea del tipo esperado del argumento fmt.Println("Suma dos números + doble: ", func(a, b int) int { return (a + b) * 2 }(10, 2)) // Llamada con argumentos 10 y 2 // => Suma dos números + doble: 24 // Cuando lo necesites, te encantará. goto encanto encanto: aprendeFunciónFábrica() // func devolviendo func es divertido(3)(3) aprendeADiferir() // Un rápido desvío a una importante palabra clave. aprendeInterfaces() // ¡Buen material dentro de poco! } func aprendeFunciónFábrica() { // Las dos siguientes son equivalentes, la segunda es más práctica fmt.Println(instrucciónFábrica("día")("Un bello", "de verano")) d := instrucciónFábrica("atardecer") fmt.Println(d("Un hermoso", "de verano")) fmt.Println(d("Un maravilloso", "de verano")) } // Los decoradores son comunes en otros lenguajes. Lo mismo se puede hacer // en Go con funciónes literales que aceptan argumentos. func instrucciónFábrica(micadena string) func(antes, después string) string { return func(antes, después string) string { return fmt.Sprintf("¡%s %s %s!", antes, micadena, después) // nueva cadena } } func aprendeADiferir() (ok bool) { // las instrucciones diferidas se ejecutan justo antes de que la // función regrese. defer fmt.Println("las instrucciones diferidas se ejecutan en orden inverso (PEPS).") defer fmt.Println("\nEsta línea se imprime primero debido a que") // Defer se usa comunmente para cerrar un fichero, por lo que la // función que cierra el fichero se mantiene cerca de la función que lo // abrió. return true } // Define Stringer como un tipo interfaz con un método, String. type Stringer interface { String() string } // Define par como una estructura con dos campos int, x e y. type par struct { x, y int } // Define un método en el tipo par. Par ahora implementa a Stringer. func (p par) String() string { // p se conoce como el "receptor" // Sprintf es otra función pública del paquete fmt. // La sintaxis con punto se refiere a los campos de p. return fmt.Sprintf("(%d, %d)", p.x, p.y) } func aprendeInterfaces() { // La sintaxis de llaves es una "estructura literal". Evalúa a una // estructura iniciada. La sintaxis := declara e inicia p a esta // estructura. p := par{3, 4} fmt.Println(p.String()) // Llama al método String de p, de tipo par. var i Stringer // Declara i como interfaz de tipo Stringer. i = p // Válido porque par implementa Stringer. // Llama al metodo String de i, de tipo Stringer. Misma salida que // arriba. fmt.Println(i.String()) // Las funciones en el paquete fmt llaman al método String para // consultar un objeto por una representación imprimible de si // mismo. fmt.Println(p) // Salida igual que arriba. Println llama al método // String. fmt.Println(i) // Salida igual que arriba. aprendeNúmeroVariableDeParámetros("¡gran", "aprendizaje", "aquí!") } // Las funciones pueden tener número variable de argumentos. func aprendeNúmeroVariableDeParámetros(misCadenas ...interface{}) { // Itera en cada valor de los argumentos variables. // El espacio en blanco aquí omite el índice del argumento arreglo. for _, parámetro := range misCadenas { fmt.Println("parámetro:", parámetro) } // Pasa el valor de múltiples variables como parámetro variadic. fmt.Println("parámetros:", fmt.Sprintln(misCadenas...)) aprendeManejoDeError() } func aprendeManejoDeError() { // ", ok" forma utilizada para saber si algo funcionó o no. m := map[int]string{3: "tres", 4: "cuatro"} if x, ok := m[1]; !ok { // ok será falso porque 1 no está en el mapa. fmt.Println("nada allí") } else { fmt.Print(x) // x sería el valor, si estuviera en el mapa. } // Un valor de error comunica más información sobre el problema aparte // de "ok". if _, err := strconv.Atoi("no-int"); err != nil { // _ descarta el // valor // Imprime "strconv.ParseInt: parsing "no-int": invalid syntax". fmt.Println(err) } // Revisaremos las interfaces más adelante. Mientras tanto... aprendeConcurrencia() } // c es un canal, un objeto de comunicación concurrente seguro. func inc(i int, c chan int) { c <- i + 1 // <- es el operador "enviar" cuando aparece un canal a la // izquierda. } // Utilizaremos inc para incrementar algunos números concurrentemente. func aprendeConcurrencia() { // Misma función make utilizada antes para crear un sector. Make asigna // e inicia sectores, mapas y canales. c := make(chan int) // Inicia tres rutinasgo concurrentes. Los números serán incrementados // concurrentemente, quizás en paralelo si la máquina es capaz y está // correctamente configurada. Las tres envían al mismo canal. go inc(0, c) // go es una instrucción que inicia una nueva rutinago. go inc(10, c) go inc(-805, c) // Lee los tres resultados del canal y los imprime. // ¡No se puede saber en que orden llegarán los resultados! fmt.Println(<-c, <-c, <-c) // Canal a la derecha, <- es el operador // "recibe". cs := make(chan string) // Otro canal, este gestiona cadenas. ccs := make(chan chan string) // Un canal de canales cadena. go func() { c <- 84 }() // Inicia una nueva rutinago solo para // enviar un valor. go func() { cs <- "verboso" }() // Otra vez, para cs en esta ocasión. // Select tiene una sintaxis parecida a la instrucción switch pero cada // caso involucra una operación con un canal. Selecciona un caso de // forma aleatoria de los casos que están listos para comunicarse. select { case i := <-c: // El valor recibido se puede asignar a una variable, fmt.Printf("es un %T", i) case <-cs: // o el valor se puede descartar. fmt.Println("es una cadena") case <-ccs: // Canal vacío, no está listo para la comunicación. fmt.Println("no sucedió.") } // En este punto un valor fue devuelto de c o cs. Una de las dos // rutinasgo que se iniciaron se ha completado, la otrá permancerá // bloqueada. aprendeProgramaciónWeb() // Go lo hace. Tú también quieres hacerlo. } // Una simple función del paquete http inicia un servidor web. func aprendeProgramaciónWeb() { // El primer parámetro es la direccinón TCP a la que escuchar. // El segundo parámetro es una interfaz, concretamente http.Handler. go func() { err := http.ListenAndServe(":8080", par{}) fmt.Println(err) // no ignora errores }() consultaAlServidor() } // Hace un http.Handler de par implementando su único método, ServeHTTP. func (p par) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Sirve datos con un método de http.ResponseWriter. w.Write([]byte("¡Aprendiste Go en Y minutos!")) } func consultaAlServidor() { resp, err := http.Get("http://localhost:8080") fmt.Println(err) defer resp.Body.Close() cuerpo, err := ioutil.ReadAll(resp.Body) fmt.Printf("\nEl servidor web dijo: `%s`\n", string(cuerpo)) } ``` ## Más información La raíz de todas las cosas sobre Go es el [sitio web oficial de Go](https://go.dev/). Allí puedes seguir el tutorial, jugar interactivamente y leer mucho más. Aparte del recorrido, [la documentación](https://golang.org/doc/) tiene información sobre cómo escribir código efectivo y limpio en Go, documentación de paquetes y comandos, y el historial de versiones. La [definición del lenguaje](https://golang.org/ref/spec) es altamente recomendada. Es fácil de leer y sorprendentemente corta (relativo a las definiciones de lenguajes en estos días). Puedes jugar con el código en el [parque de diversiones Go](https://go.dev/play/p/ncRC2Zevag). ¡Trata de cambiarlo y ejecutarlo desde tu navegador! Ten en cuenta que puedes utilizar [https://go.dev/play/](https://go.dev/play/) como un [REPL](https://es.wikipedia.org/wiki/REPL) para probar cosas y el código en el navegador, sin tener que instalar Go. En la lista de lecturas para estudiantes de Go está el [código fuente de la biblioteca estándar](https://go.dev/src/). Ampliamente documentado, demuestra lo mejor del legible y comprensible Go, con su característico estilo y modismos. ¡O puedes hacer clic en un nombre de función en [la documentación](https://pkg.go.dev/std) y aparecerá el código fuente! Go Mobile provee soporte para plataformas móbiles (Android y iOS). Puedes escribir aplicaciones móbiles completamente en Go o escribir una biblioteca con bindings de un paquete de Go, que pueden invocarse en Java (en Android) y Objective-C (en iOS). Visita la [página de Go Mobile](https://go.dev/wiki/Mobile) para más información. ================================================ FILE: es/groovy.md ================================================ --- contributors: - ["Roberto Pérez Alcolea", "http://github.com/rpalcolea"] translators: - ["Jhoon Saravia", "https://github.com/jhoon"] filename: groovy.groovy --- Groovy - Un lenguaje dinámico para la plataforma Java. [Leer más aquí](http://www.groovy-lang.org/). ```groovy /* Hora de configurar: 1) Instala GVM - http://gvmtool.net/ 2) Instala Groovy: gvm install groovy 3) Inicia la consola de groovy escribiendo: groovyConsole */ // Los comentarios de una sola línea inician con dos barras inclinadas /* Los comentarios multilínea se ven así. */ // Hola Mundo println "Hola mundo!" /* Variables: Puedes asignar valores a variables para usarlas después */ def x = 1 println x x = new java.util.Date() println x x = -3.1499392 println x x = false println x x = "Groovy!" println x /* Mapas y Colecciones */ // Creando una lista vacía def technologies = [] /*** Agregando elementos a la lista ***/ // Como si fuera Java technologies.add("Grails") // Doble símbolo de menor agrega un elemento y, además, retorna la lista technologies << "Groovy" // Agregando múltiples elementos technologies.addAll(["Gradle","Griffon"]) /*** Quitando elementos de la lista ***/ // Como si fuera Java technologies.remove("Griffon") // La resta también funciona technologies = technologies - 'Grails' /*** Iterando Listas ***/ // Para iterar sobre los elementos de una Lista technologies.each { println "Technology: $it"} technologies.eachWithIndex { it, i -> println "$i: $it"} /*** Revisando los contenidos de una Lista ***/ // Evaluar si la lista contiene elemento(s) (boolean) contained = technologies.contains( 'Groovy' ) // O contained = 'Groovy' in technologies // Evaluar por múltiples contenidos technologies.containsAll(['Groovy','Grails']) /*** Ordenando Listas ***/ // Para ordenar una Lista (modifica la lista original) technologies.sort() // Para ordenarla sin modificar la original, se puede hacer: sortedTechnologies = technologies.sort( false ) /*** Manipulando Listas ***/ // Reemplazar todos los elementos en la lista Collections.replaceAll(technologies, 'Gradle', 'gradle') // Mezclar una lista Collections.shuffle(technologies, new Random()) // Limpiar una lista technologies.clear() // Creando un mapa vacío def devMap = [:] // Agregando valores devMap = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] devMap.put('lastName','Perez') // Iterar sobre los elementos del mapa devMap.each { println "$it.key: $it.value" } devMap.eachWithIndex { it, i -> println "$i: $it"} // Evaluar si el mapa contiene una llave assert devMap.containsKey('name') // Evaluar si el mapa contiene un valor assert devMap.containsValue('Roberto') // Para obtener las llaves del mapa println devMap.keySet() // Para obtener los valores del mapa println devMap.values() /* Groovy Beans GroovyBeans son JavaBeans pero usando una sintaxis mucho más simple Cuando Groovy es compilado a código de bytes, las siguientes reglas son usadas: * Si el nombre es declarado con un modificador de acceso (public, private o protected), entonces se genera un campo. * Un nombre declarado sin modificador de acceso genera un campo privado con un getter y un setter públicos (ej: una propiedad) * Si una propiedad es declarada como final, entonces el campo privado es creado como final y no se genera un setter. * Puedes declarar una propiedad y también sus propios getter y setter. * Puedes declarar una propiedad y un campo del mismo nombre, en ese caso, la propiedad usará ese campo. * Si quieres una propiedad private o proteceted, tienes que proveer tus propios getter y setter, los cuales deben ser declarados private o protected. * Si accedes a una propiedad desde dentro de la clase, la propiedad es definida en tiempo de compilación con this implícito o explícito (por ejemplo, this.foo o simplemente foo), Groovy accederá al campo directamente en vez de usar el getter y setter. * Si accedes a una propiedad que no existe usando foo explícito o implícito, entonces Groovy accederá a la propiedad a través de la clase meta, que puede fallar en tiempo de ejecución. */ class Foo { // propiedad de solo lectura final String name = "Roberto" // propiedad de solo lectura, con getter público y setter como protected String language protected void setLanguage(String language) { this.language = language } // propiedad de tipo dinámico def lastName } /* Derivación Lógica e Iteraciones */ // Groovy soporta la clásica sintaxis de if - else def x = 3 if(x==1) { println "One" } else if(x==2) { println "Two" } else { println "X greater than Two" } // Groovy también soporta el uso del operador ternario: def y = 10 def x = (y > 1) ? "worked" : "failed" assert x == "worked" // ¡Groovy también soporta 'El Operador Elvis'! // En lugar de usar el operador ternario: displayName = user.name ? user.name : 'Anonymous' // Podemos escribirlo así: displayName = user.name ?: 'Anonymous' // Iteración con For // Iterando en un rango numérico def x = 0 for (i in 0 .. 30) { x += i } // Iterando sobre una lista x = 0 for( i in [5,3,2,1] ) { x += i } // Iterando sobre un arreglo array = (0..20).toArray() x = 0 for (i in array) { x += i } // Iterando sobre un mapa def map = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] x = "" for ( e in map ) { x += e.value x += " " } assert x.equals("Roberto Grails Groovy ") /* Operadores Para la lista de los operadores que Groovy soporta, visita: http://www.groovy-lang.org/operators.html#Operator-Overloading Operadores Groovy útiles */ // Operador de propagación: invocar una acción en todos los elementos de un objeto agregado. def technologies = ['Groovy','Grails','Gradle'] technologies*.toUpperCase() // equivale a: technologies.collect { it?.toUpperCase() } // Operador de navegación segura: usado para evitar un NullPointerException. def user = User.get(1) def username = user?.username /* Closures Un Closure en Groovy es como un "bloque de código" o un puntero a un método. Es una porci´øn de código que es definida y ejecutada en un punto futuro en el tiempo. Más información en: http://www.groovy-lang.org/closures.html */ // Ejemplo: def clos = { println "Hello World!" } println "Executing the Closure:" clos() // Pasando parámetros a un closure def sum = { a, b -> println a+b } sum(2,4) // Los Closures pueden referir a variables no listadas en sus listas de parámetros def x = 5 def multiplyBy = { num -> num * x } println multiplyBy(10) // Si tienes un Closure que toma un solo argumento, puedes omitir la // definición del parámetro en el Closure def clos = { print it } clos( "hi" ) /* Groovy puede memorizar los resultados de un Closure */ def cl = {a, b -> sleep(3000) // simula algún proceso que consume tiempo a + b } mem = cl.memoize() def callClosure(a, b) { def start = System.currentTimeMillis() mem(a, b) println "Inputs(a = $a, b = $b) - took ${System.currentTimeMillis() - start} msecs." } callClosure(1, 2) callClosure(1, 2) callClosure(2, 3) callClosure(2, 3) callClosure(3, 4) callClosure(3, 4) callClosure(1, 2) callClosure(2, 3) callClosure(3, 4) /* Expando La clase Expando es un bean dinámico para que podamos agregar propiedades y closures como métodos a una instancia de esta clase http://mrhaki.blogspot.mx/2009/10/groovy-goodness-expando-as-dynamic-bean.html */ def user = new Expando(name:"Roberto") assert 'Roberto' == user.name user.lastName = 'Pérez' assert 'Pérez' == user.lastName user.showInfo = { out -> out << "Name: $name" out << ", Last name: $lastName" } def sw = new StringWriter() println user.showInfo(sw) /* Metaprogramación (MOP) */ // Usando ExpandoMetaClass para agregar comportamiento String.metaClass.testAdd = { println "we added this" } String x = "test" x?.testAdd() // Interceptando llamadas a métodos class Test implements GroovyInterceptable { def sum(Integer x, Integer y) { x + y } def invokeMethod(String name, args) { System.out.println "Invoke method $name with args: $args" } } def test = new Test() test?.sum(2,3) test?.multiply(2,3) // Groovy soporta propertyMissing para lidiar con intentos de resolución de propiedades. class Foo { def propertyMissing(String name) { name } } def f = new Foo() assertEquals "boo", f.boo /* TypeChecked y CompileStatic Groovy, por naturaleza, es y siempre será un lenguaje dinámico pero soporta typechecked y compilestatic Más información: http://www.infoq.com/articles/new-groovy-20 */ // TypeChecked import groovy.transform.TypeChecked void testMethod() {} @TypeChecked void test() { testMeethod() def name = "Roberto" println naameee } // Otro ejemplo: import groovy.transform.TypeChecked @TypeChecked Integer test() { Integer num = "1" Integer[] numbers = [1,2,3,4] Date date = numbers[1] return "Test" } // ejemplo de CompileStatic: import groovy.transform.CompileStatic @CompileStatic int sum(int x, int y) { x + y } assert sum(2,5) == 7 ``` ## Más recursos [Documentación de Groovy](http://www.groovy-lang.org/documentation.html) [Consola Web de Groovy](http://groovyconsole.appspot.com/) Únete a un [Groovy user group](http://www.groovy-lang.org/usergroups.html) ## Libros * [Groovy Goodness](https://leanpub.com/groovy-goodness-notebook) * [Groovy in Action](http://manning.com/koenig2/) * [Programming Groovy 2: Dynamic Productivity for the Java Developer](http://shop.oreilly.com/product/9781937785307.do) ================================================ FILE: es/hack.md ================================================ --- contributors: - ["Stephen Holdaway", "https://github.com/stecman"] - ["David Lima", "https://github.com/davelima"] translators: - ["César Suárez", "https://github.com/csuarez"] --- Hack es un superconjunto de PHP que se ejecuta en una máquina virtual llamada HHVM. Hack es casi totalmente compatible con código PHP ya existente y añade varias características típicas de los lenguajes de programación estáticamente tipados. En este artículo sólo se cubren las características específicas de Hack. Los detalles sobre la sintaxis de PHP están en el [artículo sobre PHP](../php/) de esta misma web. ```php id = $id; } } // Funciones anónimas concisas (lambdas) $multiplier = 5; array_map($y ==> $y * $multiplier, [1, 2, 3]); // Genéricos class Box { protected T $data; public function __construct(T $data) { $this->data = $data; } public function getData(): T { return $this->data; } } function openBox(Box $box) : int { return $box->getData(); } // Shapes // // Hack añade el concepto de shape para definir estructuras similares a // vectores, pero con un conjunto de claves garantizado y tipado type Point2D = shape('x' => int, 'y' => int); function distance(Point2D $a, Point2D $b) : float { return sqrt(pow($b['x'] - $a['x'], 2) + pow($b['y'] - $a['y'], 2)); } distance( shape('x' => -1, 'y' => 5), shape('x' => 2, 'y' => 50) ); // Alias de tipos // // Hack permite crear alias para hacer que los tipos complejos sean más legibles newtype VectorArray = array>; // Una tupla que contiene dos enteros newtype Point = (int, int); function addPoints(Point $p1, Point $p2) : Point { return tuple($p1[0] + $p2[0], $p1[1] + $p2[1]); } addPoints( tuple(1, 2), tuple(5, 6) ); // Enumerados de primera clase enum RoadType : int { Road = 0; Street = 1; Avenue = 2; Boulevard = 3; } function getRoadType() : RoadType { return RoadType::Avenue; } // Promoción de argumentos en constructores // // Para evitar repetir una y otra vez la definición de constructores que // sólo asignan propiedades, Hack añade una sintaxis concisa para definir // propiedades junto al constructor. class ArgumentPromotion { public function __construct(public string $name, protected int $age, private bool $isAwesome) {} } class WithoutArgumentPromotion { public string $name; protected int $age; private bool $isAwesome; public function __construct(string $name, int $age, bool $isAwesome) { $this->name = $name; $this->age = $age; $this->isAwesome = $isAwesome; } } // Multitarea cooperativa // // "async" y "await" son dos palabras claves nuevas para realizar multi-tarea. // Esto no implica que se usen hilos, sólo permiten transferir el control de la // ejecución. { for ($i = $start; $i <= $end; $i++) { echo "$i "; // Da a otras tareas la oportunidad de hacer algo await RescheduleWaitHandle::create(RescheduleWaitHandle::QUEUE_DEFAULT, 0); } } // Esto imprime "1 4 7 2 5 8 3 6 9" AwaitAllWaitHandle::fromArray([ cooperativePrint(1, 3), cooperativePrint(4, 6), cooperativePrint(7, 9) ])->getWaitHandle()->join(); // Atributos // // Los atributos son una especie de metadatos para funciones. Hack implementa // algunos atributos especiales para introducir esta característica. // El atributo especial __Memoize hace que el resultado de la función se cacheé. <<__Memoize>> function doExpensiveTask() : ?string { return file_get_contents('http://example.com'); } // Esta función se va a ejecutar sólo una vez: doExpensiveTask(); doExpensiveTask(); // El atributo __ConsistentConstruct indica al comprobador de tipos de Hack que // asegure que la signatura de __construct sea la misma para todas las // subclases. <<__ConsistentConstruct>> class ConsistentFoo { public function __construct(int $x, float $y) { // ... } public function someMethod() { // ... } } class ConsistentBar extends ConsistentFoo { public function __construct(int $x, float $y) { // El comprobador de tipos de Hack fuerza que los constructores de // los padres sean llamados. parent::__construct($x, $y); // ... } // La anotación __Override es un atributo opcional para que el comprobador // de tipos fuerce que ese método esté sobrecargando un método de un padre // o de un trait. Sino, fallará. <<__Override>> public function someMethod() { // ... } } class InvalidFooSubclass extends ConsistentFoo { // Este constructor no coincide con el padre y causará el siguiente error: // // "This object is of type ConsistentBaz. It is incompatible with this // object of type ConsistentFoo because some of their methods are // incompatible" public function __construct(float $x) { // ... } // Usando la anotación __Override en un método que no sobrecarga nada se // producirá el siguiente error: // // "InvalidFooSubclass::otherMethod() is marked as override; no non-private // parent definition found or overridden parent is defined in non-> public function otherMethod() { // ... } } // Los traits pueden implementar interfaces (PHP no soporta esto). interface KittenInterface { public function play() : void; } trait CatTrait implements KittenInterface { public function play() : void { // ... } } class Samuel { use CatTrait; } $cat = new Samuel(); $cat instanceof KittenInterface === true; // True ``` ## Más información Para obtener una explicación más detallada de las características que añade Hack a PHP visita la página de [referencia de Hack](http://docs.hhvm.com/manual/en/hacklangref.php) o la [página oficial de Hack](http://hacklang.org/) para información de caracter más general. Visita la [página oficial de HHVM](http://hhvm.com/) para ver las instrucciones de su instalación. También puedes visitar la [sección de características de PHP no soportadas por Hack](http://docs.hhvm.com/manual/en/hack.unsupported.php) para más detalles sobre la retrocompatibilidad entre Hack y PHP. ================================================ FILE: es/haml.md ================================================ --- contributors: - ["Simon Neveu", "https://github.com/sneveu"] translators: - ["Camilo Garrido", "http://www.twitter.com/hirohope"] --- Haml es un lenguage de marcas principalmente usado con Ruby, que de forma simple y limpia describe el HTML de cualquier documento web sin el uso de código en linea. Es una alternativa popular respecto a usar el lenguage de plantilla de Rails (.erb) y te permite embeber código Ruby en tus anotaciones. Apunta a reducir la repetición en tus anotaciones cerrando los tags por ti, basándose en la estructura de identación de tu código. El resultado es una anotación bien estructurada, que no se repite, lógica y fácil de leer. También puedes usar Haml en un proyecto independiente de Ruby, instalando la gema Haml en tu máquina y usando la línea de comandos para convertirlo en html. $ haml archivo_entrada.haml archivo_salida.html ```haml / ------------------------------------------- / Identación / ------------------------------------------- / Por la importancia que la identación tiene en cómo tu código es traducido, la identación debe ser consistente a través de todo el documento. Cualquier diferencia en la identación lanzará un error. Es una práctica común usar dos espacios, pero realmente depende de tí, mientras sea consistente. / ------------------------------------------- / Comentarios / ------------------------------------------- / Así es como un comentario se ve en Haml. / Para escribir un comentario multilínea, identa tu código a comentar de tal forma que sea envuelto por por una barra. -# Este es un comentario silencioso, significa que no será traducido al código en absoluto / ------------------------------------------- / Elementos Html / ------------------------------------------- / Para escribir tus tags, usa el signo de porcentaje seguido por el nombre del tag %body %header %nav / Nota que no hay tags de cierre. El código anterior se traduciría como

/ El tag div es un elemento por defecto, por lo que pueden ser escritos simplemente así .foo / Para añadir contenido a un tag, añade el texto directamente después de la declaración %h1 Headline copy / Para escribir contenido multilínea, anídalo. %p Esto es mucho contenido que podríamos dividirlo en dos líneas separadas. / Puedes escapar html usando el signo ampersand y el signo igual ( &= ). Esto convierte carácteres sensibles en html a su equivalente codificado en html. Por ejemplo %p &= "Sí & si" / se traduciría en 'Sí & si' / Puedes desescapar html usando un signo de exclamación e igual ( != ) %p != "Así es como se escribe un tag párrafo

" / se traduciría como 'Así es como se escribe un tag párrafo

' / Clases CSS puedes ser añadidas a tus tags, ya sea encadenando .nombres-de-clases al tag %div.foo.bar / o como parte de un hash Ruby %div{:class => 'foo bar'} / Atributos para cualquier tag pueden ser añadidos en el hash %a{:href => '#', :class => 'bar', :title => 'Bar'} / Para atributos booleanos asigna el valor verdadero 'true' %input{:selected => true} / Para escribir atributos de datos, usa la llave :dato con su valor como otro hash %div{:data => {:attribute => 'foo'}} / ------------------------------------------- / Insertando Ruby / ------------------------------------------- / Para producir un valor Ruby como contenido de un tag, usa un signo igual seguido por código Ruby %h1= libro.nombre %p = libro.autor = libro.editor / Para correr un poco de código Ruby sin traducirlo en html, usa un guión - libros = ['libro 1', 'libro 2', 'libro 3'] / Esto te permite hacer todo tipo de cosas asombrosas, como bloques de Ruby - libros.shuffle.each_with_index do |libro, indice| %h1= libro if libro do %p Esto es un libro / Nuevamente, no hay necesidad de añadir los tags de cerrado en el código, ni siquiera para Ruby La identación se encargará de ello por tí. / ------------------------------------------- / Ruby en linea / Interpolación de Ruby / ------------------------------------------- / Incluye una variable Ruby en una línea de texto plano usando #{} %p Tu juego con puntaje más alto es #{mejor_juego} / ------------------------------------------- / Filtros / ------------------------------------------- / Usa un signo dos puntos para definir filtros Haml, un ejemplo de filtro que puedes usar es :javascript, el cual puede ser usado para escribir JavaScript en línea. :javascript console.log('Este es un / There are many types of filters (:markdown, :javascript, :coffee, :css, :ruby and so on) Also you can define your own filters using Haml::Filters ``` ## Additional resources - [What is HAML?](http://haml.info/) - A good introduction that does a much better job of explaining the benefits of using HAML. - [Official Docs](http://haml.info/docs/yardoc/file.REFERENCE.html) - If you'd like to go a little deeper. ================================================ FILE: haskell.md ================================================ --- name: Haskell filename: learnhaskell.hs contributors: - ["Adit Bhargava", "http://adit.io"] - ["Stanislav Modrak", "https://stanislav.gq"] --- Haskell was designed as a practical, purely functional programming language. It's famous for its monads and its type system, but I keep coming back to it because of its elegance. Haskell makes coding a real joy for me. ```haskell -- Single line comments start with two dashes. {- Multiline comments can be enclosed in a block like this. -} ---------------------------------------------------- -- 1. Primitive Datatypes and Operators ---------------------------------------------------- -- You have numbers 3 -- 3 -- Math is what you would expect 1 + 1 -- 2 8 - 1 -- 7 10 * 2 -- 20 35 / 5 -- 7.0 -- Division is not integer division by default 35 / 4 -- 8.75 -- integer division 35 `div` 4 -- 8 -- Boolean values are primitives True False -- Boolean operations not True -- False not False -- True True && False -- False True || False -- True 1 == 1 -- True 1 /= 1 -- False 1 < 10 -- True -- In the above examples, `not` is a function that takes one value. -- Haskell doesn't need parentheses for function calls...all the arguments -- are just listed after the function. So the general pattern is: -- func arg1 arg2 arg3... -- See the section on functions for information on how to write your own. -- Strings and characters "This is a string." 'a' -- character 'You cant use single quotes for strings.' -- error! -- Strings can be concatenated "Hello " ++ "world!" -- "Hello world!" -- A string is a list of characters ['H', 'e', 'l', 'l', 'o'] -- "Hello" -- Lists can be indexed with the `!!` operator followed by an index -- but this is an O(n) operation because lists are linked lists "This is a string" !! 0 -- 'T' ---------------------------------------------------- -- 2. Lists and Tuples ---------------------------------------------------- -- Every element in a list must have the same type. -- These two lists are equal: [1, 2, 3, 4, 5] [1..5] -- Ranges are versatile. ['A'..'F'] -- "ABCDEF" -- You can create a step in a range. [0,2..10] -- [0, 2, 4, 6, 8, 10] [5..1] -- [] (Haskell defaults to incrementing) [5,4..1] -- [5, 4, 3, 2, 1] -- indexing into a list [1..10] !! 3 -- 4 (zero-based indexing) -- You can also have infinite lists in Haskell! [1..] -- a list of all the natural numbers -- Infinite lists work because Haskell has "lazy evaluation". This means -- that Haskell only evaluates things when it needs to. So you can ask for -- the 1000th element of your list and Haskell will give it to you: [1..] !! 999 -- 1000 -- And now Haskell has evaluated elements 1 - 1000 of this list...but the -- rest of the elements of this "infinite" list don't exist yet! Haskell won't -- actually evaluate them until it needs to. -- joining two lists [1..5] ++ [6..10] -- adding to the head of a list 0:[1..5] -- [0, 1, 2, 3, 4, 5] -- more list operations head [1..5] -- 1 tail [1..5] -- [2, 3, 4, 5] init [1..5] -- [1, 2, 3, 4] last [1..5] -- 5 -- list comprehensions [x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10] -- with a conditional [x*2 | x <- [1..5], x*2 > 4] -- [6, 8, 10] -- Every element in a tuple can be a different type, but a tuple has a -- fixed length. -- A tuple: ("haskell", 1) -- accessing elements of a pair (i.e. a tuple of length 2) fst ("haskell", 1) -- "haskell" snd ("haskell", 1) -- 1 -- pair element accessing does not work on n-tuples (i.e. triple, quadruple, etc) snd ("snd", "can't touch this", "da na na na") -- error! see function below ---------------------------------------------------- -- 3. Functions ---------------------------------------------------- -- A simple function that takes two variables add a b = a + b -- Using the function add 1 2 -- 3 -- You can also put the function name between the two arguments -- with backticks: 1 `add` 2 -- 3 -- You can also define functions that have no letters! This lets -- you define your own operators! Here's an operator that does -- integer division (//) a b = a `div` b 35 // 4 -- 8 -- Guards: an easy way to do branching in functions fib x | x < 2 = 1 | otherwise = fib (x - 1) + fib (x - 2) -- Pattern matching is similar. Here we have given three different -- equations that define fib. Haskell will automatically use the first -- equation whose left hand side pattern matches the value. fib 1 = 1 fib 2 = 2 fib x = fib (x - 1) + fib (x - 2) -- Pattern matching on tuples sndOfTriple (_, y, _) = y -- use a wild card (_) to bypass naming unused value -- Pattern matching on lists. Here `x` is the first element -- in the list, and `xs` is the rest of the list. We can write -- our own map function: myMap func [] = [] myMap func (x:xs) = func x:(myMap func xs) -- Anonymous functions are created with a backslash followed by -- all the arguments. myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7] -- using fold (called `inject` in some languages) with an anonymous -- function. foldl1 means fold left, and use the first value in the -- list as the initial value for the accumulator. foldl1 (\acc x -> acc + x) [1..5] -- 15 ---------------------------------------------------- -- 4. More functions ---------------------------------------------------- -- partial application: if you don't pass in all the arguments to a function, -- it gets "partially applied". That means it returns a function that takes the -- rest of the arguments. add a b = a + b foo = add 10 -- foo is now a function that takes a number and adds 10 to it foo 5 -- 15 -- Another way to write the same thing foo = (10+) foo 5 -- 15 -- function composition -- the operator `.` chains functions together. -- For example, here foo is a function that takes a value. It adds 10 to it, -- multiplies the result of that by 4, and then returns the final value. foo = (4*) . (10+) -- 4*(10+5) = 60 foo 5 -- 60 -- fixing precedence -- Haskell has an operator called `$`. This operator applies a function -- to a given parameter. In contrast to standard function application, which -- has highest possible priority of 10 and is left-associative, the `$` operator -- has priority of 0 and is right-associative. Such a low priority means that -- the expression on its right is applied as a parameter to the function on its left. -- before even (fib 7) -- false -- equivalently even $ fib 7 -- false -- composing functions even . fib $ 7 -- false ---------------------------------------------------- -- 5. Type signatures ---------------------------------------------------- -- Haskell has a very strong type system, and every valid expression has a type. -- Some basic types: 5 :: Integer "hello" :: String True :: Bool -- Functions have types too. -- `not` takes a boolean and returns a boolean: -- not :: Bool -> Bool -- Here's a function that takes two arguments: -- add :: Integer -> Integer -> Integer -- When you define a value, it's good practice to write its type above it: double :: Integer -> Integer double x = x * 2 ---------------------------------------------------- -- 6. Control Flow and If Expressions ---------------------------------------------------- -- if-expressions haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome" -- if-expressions can be on multiple lines too, indentation is important haskell = if 1 == 1 then "awesome" else "awful" -- case expressions: Here's how you could parse command line arguments case args of "help" -> printHelp "start" -> startProgram _ -> putStrLn "bad args" -- Haskell doesn't have loops; it uses recursion instead. -- map applies a function over every element in a list map (*2) [1..5] -- [2, 4, 6, 8, 10] -- you can make a for function using map for list func = map func list -- and then use it for [0..5] $ \i -> show i -- we could've written that like this too: for [0..5] show -- filter keeps only the elements in a list that satisfy a condition filter even [1..10] -- [2, 4, 8, 10] -- You can use foldl or foldr to reduce a list -- foldl foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43 -- This is the same as (2 * (2 * (2 * 4 + 1) + 2) + 3) -- foldl is left-handed, foldr is right-handed foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16 -- This is now the same as (2 * 1 + (2 * 2 + (2 * 3 + 4))) ---------------------------------------------------- -- 7. Data Types ---------------------------------------------------- -- A data type is declared with a 'type constructor' on the left -- and one or more 'data constructors' on the right, separated by -- the pipe | symbol. This is a sum/union type. Each data constructor -- is a (possibly nullary) function that creates an object of the type -- named by the type constructor. -- This is essentially an enum data Color = Red | Blue | Green -- Now you can use it in a function: say :: Color -> String say Red = "You are Red!" say Blue = "You are Blue!" say Green = "You are Green!" -- Note that the type constructor is used in the type signature -- and the data constructors are used in the body of the function -- Data constructors are primarily pattern-matched against -- This next one is a traditional container type holding two fields -- In a type declaration, data constructors take types as parameters -- Data constructors can have the same name as type constructors -- This is common where the type only has a single data constructor data Point = Point Float Float -- This can be used in a function like: distance :: Point -> Point -> Float distance (Point x y) (Point x' y') = sqrt $ dx + dy where dx = (x - x') ** 2 dy = (y - y') ** 2 -- Types can have multiple data constructors with arguments, too data Name = Mononym String | FirstLastName String String | FullName String String String -- To make things clearer we can use record syntax data Point2D = CartesianPoint2D { x :: Float, y :: Float } | PolarPoint2D { r :: Float, theta :: Float } myPoint = CartesianPoint2D { x = 7.0, y = 10.0 } -- Using record syntax automatically creates accessor functions -- (the name of the field) xOfMyPoint = x myPoint -- xOfMyPoint is equal to 7.0 -- Record syntax also allows a simple form of update myPoint' = myPoint { x = 9.0 } -- myPoint' is CartesianPoint2D { x = 9.0, y = 10.0 } -- Even if a type is defined with record syntax, it can be declared like -- a simple data constructor. This is fine: myPoint'2 = CartesianPoint2D 3.3 4.0 -- It's also useful to pattern match data constructors in `case` expressions distanceFromOrigin x = case x of (CartesianPoint2D x y) -> sqrt $ x ** 2 + y ** 2 (PolarPoint2D r _) -> r -- Your data types can have type parameters too: data Maybe a = Nothing | Just a -- These are all of type Maybe Just "hello" -- of type `Maybe String` Just 1 -- of type `Maybe Int` Nothing -- of type `Maybe a` for any `a` -- For convenience we can also create type synonyms with the 'type' keyword type String = [Char] -- Unlike `data` types, type synonyms need no constructor, and can be used -- anywhere a synonymous data type could be used. Say we have the -- following type synonyms and items with the following type signatures type Weight = Float type Height = Float type Point = (Float, Float) getMyHeightAndWeight :: Person -> (Height, Weight) findCenter :: Circle -> Point somePerson :: Person someCircle :: Circle distance :: Point -> Point -> Float -- The following would compile and run without issue, -- even though it does not make sense semantically, -- because the type synonyms reduce to the same base types distance (getMyHeightAndWeight somePerson) (findCenter someCircle) ---------------------------------------------------- -- 8. Typeclasses ---------------------------------------------------- -- Typeclasses are one way Haskell does polymorphism -- They are similar to interfaces in other languages -- A typeclass defines a set of functions that must -- work on any type that is in that typeclass. -- The Eq typeclass is for types whose instances can -- be tested for equality with one another. class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y) -- This defines a typeclass that requires two functions, (==) and (/=) -- It also declares that one function can be declared in terms of another -- So it is enough that *either* the (==) function or the (/=) is defined -- And the other will be 'filled in' based on the typeclass definition -- To make a type a member of a type class, the instance keyword is used instance Eq TrafficLight where Red == Red = True Green == Green = True Yellow == Yellow = True _ == _ = False -- Now we can use (==) and (/=) with TrafficLight objects canProceedThrough :: TrafficLight -> Bool canProceedThrough t = t /= Red -- You can NOT create an instance definition for a type synonym -- Functions can be written to take typeclasses with type parameters, -- rather than types, assuming that the function only relies on -- features of the typeclass isEqual :: (Eq a) => a -> a -> Bool isEqual x y = x == y -- Note that x and y MUST be the same type, as they are both defined -- as being of type parameter 'a'. -- A typeclass does not state that different types in the typeclass can -- be mixed together. -- So `isEqual Red 2` is invalid, even though 2 is an Int which is an -- instance of Eq, and Red is a TrafficLight which is also an instance of Eq -- Other common typeclasses are: -- Ord for types that can be ordered, allowing you to use >, <=, etc. -- Read for types that can be created from a string representation -- Show for types that can be converted to a string for display -- Num, Real, Integral, Fractional for types that can do math -- Enum for types that can be stepped through -- Bounded for types with a maximum and minimum -- Haskell can automatically make types part of Eq, Ord, Read, Show, Enum, -- and Bounded with the `deriving` keyword at the end of the type declaration data Point = Point Float Float deriving (Eq, Read, Show) -- In this case it is NOT necessary to create an 'instance' definition ---------------------------------------------------- -- 9. Haskell IO ---------------------------------------------------- -- While IO can't be explained fully without explaining monads, -- it is not hard to explain enough to get going. -- When a Haskell program is executed, `main` is -- called. It must return a value of type `IO a` for some type `a`. For example: main :: IO () main = putStrLn $ "Hello, sky! " ++ (say Blue) -- putStrLn has type String -> IO () -- It is easiest to do IO if you can implement your program as -- a function from String to String. The function -- interact :: (String -> String) -> IO () -- inputs some text, runs a function on it, and prints out the -- output. countLines :: String -> String countLines = show . length . lines main' = interact countLines -- You can think of a value of type `IO ()` as representing a -- sequence of actions for the computer to do, much like a -- computer program written in an imperative language. We can use -- the `do` notation to chain actions together. For example: sayHello :: IO () sayHello = do putStrLn "What is your name?" name <- getLine -- this gets a line and gives it the name "name" putStrLn $ "Hello, " ++ name -- Exercise: write your own version of `interact` that only reads -- one line of input. -- The code in `sayHello` will never be executed, however. The only -- action that ever gets executed is the value of `main`. -- To run `sayHello` comment out the above definition of `main` -- and replace it with: -- main = sayHello -- Let's understand better how the function `getLine` we just -- used works. Its type is: -- getLine :: IO String -- You can think of a value of type `IO a` as representing a -- computer program that will generate a value of type `a` -- when executed (in addition to anything else it does). We can -- name and reuse this value using `<-`. We can also -- make our own action of type `IO String`: action :: IO String action = do putStrLn "This is a line. Duh" input1 <- getLine input2 <- getLine -- The type of the `do` statement is that of its last line. -- `return` is not a keyword, but merely a function return (input1 ++ "\n" ++ input2) -- return :: String -> IO String -- We can use this just like we used `getLine`: main'' = do putStrLn "I will echo two lines!" result <- action putStrLn result putStrLn "This was all, folks!" -- The type `IO` is an example of a "monad". The way Haskell uses a monad to -- do IO allows it to be a purely functional language. Any function that -- interacts with the outside world (i.e. does IO) gets marked as `IO` in its -- type signature. This lets us reason about which functions are "pure" (don't -- interact with the outside world or modify state) and which functions aren't. -- This is a powerful feature, because it's easy to run pure functions -- concurrently; so, concurrency in Haskell is very easy. ---------------------------------------------------- -- 10. The Haskell REPL ---------------------------------------------------- -- Start the repl by typing `ghci`. -- Now you can type in Haskell code. > foo = 5 > foo 5 -- You can see the type of any value or expression with `:t`: > :t foo foo :: Num a => a -- Option `+d` shows default types: > :t +d foo foo :: Integer -- Operators, such as `+`, `:` and `$`, are functions. -- Their type can be inspected by putting the operator in parentheses: > :t (:) (:) :: a -> [a] -> [a] -- You can get additional information on any `name` using `:i`: > :i (+) class Num a where (+) :: a -> a -> a ... -- Defined in ‘GHC.Num’ infixl 6 + -- Type `:?` to get a list of all available commands. -- You can also run any action of type `IO ()` > sayHello What is your name? Friend! Hello, Friend! ``` There's a lot more to Haskell, including typeclasses and monads. These are the big ideas that make Haskell such fun to code in. I'll leave you with one final Haskell example: an implementation of a quicksort variant in Haskell: ```haskell qsort [] = [] qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater where lesser = filter (< p) xs greater = filter (>= p) xs ``` There are two popular ways to install Haskell: The traditional [Cabal-based installation](http://www.haskell.org/platform/), and the newer [Stack-based process](https://www.stackage.org/install). You can find a much gentler introduction from the excellent [Learn you a Haskell](http://learnyouahaskell.com/) (or [up-to-date community version](https://learnyouahaskell.github.io/)), [Happy Learn Haskell Tutorial](http://www.happylearnhaskelltutorial.com/) or [Real World Haskell](http://book.realworldhaskell.org/). ================================================ FILE: haxe.md ================================================ --- name: Haxe filename: LearnHaxe3.hx contributors: - ["Justin Donaldson", "https://github.com/jdonaldson/"] - ["Dan Korostelev", "https://github.com/nadako/"] --- [Haxe](https://haxe.org/) is a general-purpose language that provides platform support for C++, C#, Swf/ActionScript, JavaScript, Java, PHP, Python, Lua, HashLink, and Neko bytecode (the latter two being also written by the Haxe author). Note that this guide is for Haxe version 3. Some of the guide may be applicable to older versions, but it is recommended to use other references. ```haxe /* Welcome to Learn Haxe 3 in 15 minutes. http://www.haxe.org This is an executable tutorial. You can compile and run it using the haxe compiler, while in the same directory as LearnHaxe.hx: $ haxe -main LearnHaxe3 --interp Look for the slash-star marks surrounding these paragraphs. We are inside a "Multiline comment". We can leave some notes here that will get ignored by the compiler. Multiline comments are also used to generate javadoc-style documentation for haxedoc. They will be used for haxedoc if they immediately precede a class, class function, or class variable. */ // Double slashes like this will give a single-line comment. /* This is your first actual haxe code coming up, it's declaring an empty package. A package isn't necessary, but it's useful if you want to create a namespace for your code (e.g. org.yourapp.ClassName). Omitting package declaration is the same as declaring an empty package. */ package; // empty package, no namespace. /* Packages are directories that contain modules. Each module is a .hx file that contains types defined in a package. Package names (e.g. org.yourapp) must be lower case while module names are capitalized. A module contain one or more types whose names are also capitalized. E.g, the class "org.yourapp.Foo" should have the folder structure org/module/Foo.hx, as accessible from the compiler's working directory or class path. If you import code from other files, it must be declared before the rest of the code. Haxe provides a lot of common default classes to get you started: */ import haxe.ds.ArraySort; // you can import many classes/modules at once with "*" import haxe.ds.*; // you can import static fields import Lambda.array; // you can also use "*" to import all static fields import Math.*; // You can also import classes in a special way, enabling them to extend the // functionality of other classes like a "mixin". More on 'using' later. using StringTools; // Typedefs are like variables... for types. They must be declared before any // code. More on this later. typedef FooString = String; // Typedefs can also reference "structural" types, more on that later as well. typedef FooObject = { foo: String }; // Here's the class definition. It's the main class for the file, since it has // the same name (LearnHaxe3). class LearnHaxe3 { /* If you want certain code to run automatically, you need to put it in a static main function, and specify the class in the compiler arguments. In this case, we've specified the "LearnHaxe3" class in the compiler arguments above. */ static function main() { /* Trace is the default method of printing haxe expressions to the screen. Different targets will have different methods of accomplishing this. E.g., java, c++, c#, etc. will print to std out. JavaScript will print to console.log, and flash will print to an embedded TextField. All traces come with a default newline. Finally, It's possible to prevent traces from showing by using the "--no-traces" argument on the compiler. */ trace("Hello World, with trace()!"); // Trace can handle any type of value or object. It will try to print // a representation of the expression as best it can. You can also // concatenate strings with the "+" operator: trace("Integer: " + 10 + " Float: " + 3.14 + " Boolean: " + true); // In Haxe, it's required to separate expressions in the same block with // semicolons. But, you can put two expressions on one line: trace('two expressions..'); trace('one line'); ////////////////////////////////////////////////////////////////// // Types & Variables ////////////////////////////////////////////////////////////////// trace("***Types & Variables***"); // You can save values and references to data structures using the // "var" keyword: var an_integer:Int = 1; trace(an_integer + " is the value for an_integer"); /* Haxe is statically typed, so "an_integer" is declared to have an "Int" type, and the rest of the expression assigns the value "1" to it. It's not necessary to declare the type in many cases. Here, the haxe compiler is inferring that the type of another_integer should be "Int". */ var another_integer = 2; trace(another_integer + " is the value for another_integer"); // The $type() method prints the type that the compiler assigns: $type(another_integer); // You can also represent integers with hexadecimal: var hex_integer = 0xffffff; /* Haxe uses platform precision for Int and Float sizes. It also uses the platform behavior for overflow. (Other numeric types and behavior are possible using special libraries.) In addition to simple values like Integers, Floats, and Booleans, Haxe provides standard library implementations for common data structures like strings, arrays, lists, and maps: */ // Strings can have double or single quotes. var a_string = "some" + 'string'; trace(a_string + " is the value for a_string"); // Strings can be "interpolated" by inserting variables into specific // positions. The string must be single quoted, and the variable must // be preceded with "$". Expressions can be enclosed in ${...}. var x = 1; var an_interpolated_string = 'the value of x is $x'; var another_interpolated_string = 'the value of x + 1 is ${x + 1}'; // Strings are immutable, instance methods will return a copy of // parts or all of the string. (See also the StringBuf class). var a_sub_string = a_string.substr(0,4); trace(a_sub_string + " is the value for a_sub_string"); // Regexes are also supported, but there's not enough space here to go // into much detail. var re = ~/foobar/; trace(re.match('foo') + " is the value for (~/foobar/.match('foo')))"); // Arrays are zero-indexed, dynamic, and mutable. Missing values are // defined as null. var a = new Array(); // an array that contains Strings a[0] = 'foo'; trace(a.length + " is the value for a.length"); a[9] = 'bar'; trace(a.length + " is the value for a.length (after modification)"); trace(a[3] + " is the value for a[3]"); //null // Arrays are *generic*, so you can indicate which values they contain // with a type parameter: var a2 = new Array(); // an array of Ints var a3 = new Array>(); // an Array of Arrays (of Strings). // Maps are simple key/value data structures. The key and the value // can be of any type. // Here, the keys are strings, and the values are Ints: var m = new Map(); m.set('foo', 4); // You can also use array notation: m['bar'] = 5; trace(m.exists('bar') + " is the value for m.exists('bar')"); trace(m.get('bar') + " is the value for m.get('bar')"); trace(m['bar'] + " is the value for m['bar']"); var m2 = ['foo' => 4, 'baz' => 6]; // Alternative map syntax trace(m2 + " is the value for m2"); // Remember, you can use type inference. The Haxe compiler will // decide the type of the variable the first time you pass an // argument that sets a type parameter. var m3 = new Map(); m3.set(6, 'baz'); // m3 is now a Map trace(m3 + " is the value for m3"); // Haxe has some more common datastructures in the haxe.ds module, such // as List, Stack, and BalancedTree. ////////////////////////////////////////////////////////////////// // Operators ////////////////////////////////////////////////////////////////// trace("***OPERATORS***"); // basic arithmetic trace((4 + 3) + " is the value for (4 + 3)"); trace((5 - 1) + " is the value for (5 - 1)"); trace((2 * 4) + " is the value for (2 * 4)"); // Division always produces Floats. trace((8 / 3) + " is the value for (8 / 3) (a Float)"); trace((12 % 4) + " is the value for (12 % 4)"); // basic comparison trace((3 == 2) + " is the value for 3 == 2"); trace((3 != 2) + " is the value for 3 != 2"); trace((3 > 2) + " is the value for 3 > 2"); trace((3 < 2) + " is the value for 3 < 2"); trace((3 >= 2) + " is the value for 3 >= 2"); trace((3 <= 2) + " is the value for 3 <= 2"); // standard bitwise operators /* ~ Unary bitwise complement << Signed left shift >> Signed right shift >>> Unsigned right shift & Bitwise AND ^ Bitwise exclusive OR | Bitwise inclusive OR */ var i = 0; trace("Pre-/Post- Increments and Decrements"); trace(i++); // i = 1. Post-Increment trace(++i); // i = 2. Pre-Increment trace(i--); // i = 1. Post-Decrement trace(--i); // i = 0. Pre-Decrement ////////////////////////////////////////////////////////////////// // Control Structures ////////////////////////////////////////////////////////////////// trace("***CONTROL STRUCTURES***"); // if statements var j = 10; if (j == 10) { trace("this is printed"); } else if (j > 10) { trace("not greater than 10, so not printed"); } else { trace("also not printed."); } // there is also a "ternary" if: (j == 10) ? trace("equals 10") : trace("not equals 10"); // Finally, there is another form of control structure that operates // at compile time: conditional compilation. #if neko trace('hello from neko'); #elseif js trace('hello from js'); #else trace('hello from another platform!'); #end // The compiled code will change depending on the platform target. // Since we're compiling for neko (-x or -neko), we only get the neko // greeting. trace("Looping and Iteration"); // while loop var k = 0; while (k < 100) { // trace(counter); // will print out numbers 0-99 k++; } // do-while loop var l = 0; do { trace("do statement always runs at least once"); } while (l > 0); // for loop // There is no c-style for loop in Haxe, because they are prone // to error, and not necessary. Instead, Haxe has a much simpler // and safer version that uses Iterators (more on those later). var m = [1, 2, 3]; for (val in m) { trace(val + " is the value for val in the m array"); } // Note that you can iterate on an index using a range // (more on ranges later as well) var n = ['foo', 'bar', 'baz']; for (val in 0...n.length) { trace(val + " is the value for val (an index for n)"); } trace("Array Comprehensions"); // Array comprehensions give you the ability to iterate over arrays // while also creating filters and modifications. var filtered_n = [for (val in n) if (val != "foo") val]; trace(filtered_n + " is the value for filtered_n"); var modified_n = [for (val in n) val += '!']; trace(modified_n + " is the value for modified_n"); var filtered_and_modified_n = [for (val in n) if (val != "foo") val += "!"]; trace(filtered_and_modified_n + " is the value for filtered_and_modified_n"); ////////////////////////////////////////////////////////////////// // Switch Statements (Value Type) ////////////////////////////////////////////////////////////////// trace("***SWITCH STATEMENTS (VALUE TYPES)***"); /* Switch statements in Haxe are very powerful. In addition to working on basic values like strings and ints, they can also work on the generalized algebraic data types in enums (more on enums later). Here are some basic value examples for now: */ var my_dog_name = "fido"; var favorite_thing = ""; switch (my_dog_name) { case "fido" : favorite_thing = "bone"; case "rex" : favorite_thing = "shoe"; case "spot" : favorite_thing = "tennis ball"; default : favorite_thing = "some unknown treat"; // same as default: // case _ : favorite_thing = "some unknown treat"; } // The "_" case above is a "wildcard" value that will match anything. trace("My dog's name is " + my_dog_name + ", and his favorite thing is a: " + favorite_thing); ////////////////////////////////////////////////////////////////// // Expression Statements ////////////////////////////////////////////////////////////////// trace("***EXPRESSION STATEMENTS***"); // Haxe control statements are very powerful because every statement // is also an expression, consider: // if statements var k = if (true) 10 else 20; trace("k equals ", k); // outputs 10 var other_favorite_thing = switch (my_dog_name) { case "fido" : "teddy"; case "rex" : "stick"; case "spot" : "football"; default : "some unknown treat"; } trace("My dog's name is " + my_dog_name + ", and his other favorite thing is a: " + other_favorite_thing); ////////////////////////////////////////////////////////////////// // Converting Value Types ////////////////////////////////////////////////////////////////// trace("***CONVERTING VALUE TYPES***"); // You can convert strings to ints fairly easily. // string to integer Std.parseInt("0"); // returns 0 Std.parseFloat("0.4"); // returns 0.4 // integer to string Std.string(0); // returns "0" // concatenation with strings will auto-convert to string. 0 + ""; // returns "0" true + ""; // returns "true" // See documentation for parsing in Std for more details. ////////////////////////////////////////////////////////////////// // Dealing with Types ////////////////////////////////////////////////////////////////// /* As mentioned before, Haxe is a statically typed language. All in all, static typing is a wonderful thing. It enables precise autocompletions, and can be used to thoroughly check the correctness of a program. Plus, the Haxe compiler is super fast. *HOWEVER*, there are times when you just wish the compiler would let something slide, and not throw a type error in a given case. To do this, Haxe has two separate keywords. The first is the "Dynamic" type: */ var dyn: Dynamic = "any type of variable, such as this string"; /* All that you know for certain with a Dynamic variable is that the compiler will no longer worry about what type it is. It is like a wildcard variable: You can pass it instead of any variable type, and you can assign any variable type you want. The other more extreme option is the "untyped" keyword: */ untyped { var x:Int = 'foo'; // This can't be right! var y:String = 4; // Madness! } /* The untyped keyword operates on entire *blocks* of code, skipping any type checks that might be otherwise required. This keyword should be used very sparingly, such as in limited conditionally-compiled situations where type checking is a hindrance. In general, skipping type checks is *not* recommended. Use the enum, inheritance, or structural type models in order to help ensure the correctness of your program. Only when you're certain that none of the type models work should you resort to "Dynamic" or "untyped". */ ////////////////////////////////////////////////////////////////// // Basic Object Oriented Programming ////////////////////////////////////////////////////////////////// trace("***BASIC OBJECT ORIENTED PROGRAMMING***"); // Create an instance of FooClass. The classes for this are at the // end of the file. var foo_instance = new FooClass(3); // read the public variable normally trace(foo_instance.public_any + " is the value for foo_instance.public_any"); // we can read this variable trace(foo_instance.public_read + " is the value for foo_instance.public_read"); // but not write it; this will throw an error if uncommented: // foo_instance.public_read = 4; // trace(foo_instance.public_write); // as will this. // Calls the toString method: trace(foo_instance + " is the value for foo_instance"); // same thing: trace(foo_instance.toString() + " is the value for foo_instance.toString()"); // The foo_instance has the "FooClass" type, while acceptBarInstance // has the BarClass type. However, since FooClass extends BarClass, it // is accepted. BarClass.acceptBarInstance(foo_instance); // The classes below have some more advanced examples, the "example()" // method will just run them here. SimpleEnumTest.example(); ComplexEnumTest.example(); TypedefsAndStructuralTypes.example(); UsingExample.example(); } } // This is the "child class" of the main LearnHaxe3 Class. class FooClass extends BarClass implements BarInterface { public var public_any:Int; // public variables are accessible anywhere public var public_read (default, null): Int; // enable only public read public var public_write (null, default): Int; // or only public write // Use this style to enable getters/setters: public var property (get, set): Int; // private variables are not available outside the class. // see @:allow for ways around this. var _private:Int; // variables are private if they are not marked public // a public constructor public function new(arg:Int) { // call the constructor of the parent object, since we extended BarClass: super(); this.public_any = 0; this._private = arg; } // getter for _private function get_property() : Int { return _private; } // setter for _private function set_property(val:Int) : Int { _private = val; return val; } // Special function that is called whenever an instance is cast to a string. public function toString() { return _private + " with toString() method!"; } // this class needs to have this function defined, since it implements // the BarInterface interface. public function baseFunction(x: Int) : String { // convert the int to string automatically return x + " was passed into baseFunction!"; } } // A simple class to extend. class BarClass { var base_variable:Int; public function new() { base_variable = 4; } public static function acceptBarInstance(b:BarClass) {} } // A simple interface to implement interface BarInterface { public function baseFunction(x:Int):String; } ////////////////////////////////////////////////////////////////// // Enums and Switch Statements ////////////////////////////////////////////////////////////////// // Enums in Haxe are very powerful. In their simplest form, enums // are a type with a limited number of states: enum SimpleEnum { Foo; Bar; Baz; } // Here's a class that uses it: class SimpleEnumTest { public static function example() { // You can specify the "full" name, var e_explicit:SimpleEnum = SimpleEnum.Foo; var e = Foo; // but inference will work as well. switch (e) { case Foo: trace("e was Foo"); case Bar: trace("e was Bar"); case Baz: trace("e was Baz"); // comment this line to throw an error. } /* This doesn't seem so different from simple value switches on strings. However, if we don't include *all* of the states, the compiler will complain. You can try it by commenting out a line above. You can also specify a default for enum switches as well: */ switch (e) { case Foo: trace("e was Foo again"); default : trace("default works here too"); } } } // Enums go much further than simple states, we can also enumerate // *constructors*, but we'll need a more complex enum example. enum ComplexEnum { IntEnum(i:Int); MultiEnum(i:Int, j:String, k:Float); SimpleEnumEnum(s:SimpleEnum); ComplexEnumEnum(c:ComplexEnum); } // Note: The enum above can include *other* enums as well, including itself! // Note: This is what's called *Algebraic data type* in some other languages. class ComplexEnumTest { public static function example() { var e1:ComplexEnum = IntEnum(4); // specifying the enum parameter // Now we can switch on the enum, as well as extract any parameters // it might have had. switch (e1) { case IntEnum(x) : trace('$x was the parameter passed to e1'); default: trace("Shouldn't be printed"); } // another parameter here that is itself an enum... an enum enum? var e2 = SimpleEnumEnum(Foo); switch (e2){ case SimpleEnumEnum(s): trace('$s was the parameter passed to e2'); default: trace("Shouldn't be printed"); } // enums all the way down var e3 = ComplexEnumEnum(ComplexEnumEnum(MultiEnum(4, 'hi', 4.3))); switch (e3) { // You can look for certain nested enums by specifying them // explicitly: case ComplexEnumEnum(ComplexEnumEnum(MultiEnum(i,j,k))) : { trace('$i, $j, and $k were passed into this nested monster'); } default: trace("Shouldn't be printed"); } // Check out "generalized algebraic data types" (GADT) for more details // on why these are so great. } } class TypedefsAndStructuralTypes { public static function example() { // Here we're going to use typedef types, instead of base types. // At the top we've declared the type "FooString" to mean a "String" type. var t1:FooString = "some string"; // We can use typedefs for "structural types" as well. These types are // defined by their field structure, not by class inheritance. Here's // an anonymous object with a String field named "foo": var anon_obj = { foo: 'hi' }; /* The anon_obj variable doesn't have a type declared, and is an anonymous object according to the compiler. However, remember back at the top where we declared the FooObj typedef? Since anon_obj matches that structure, we can use it anywhere that a "FooObject" type is expected. */ var f = function(fo:FooObject) { trace('$fo was passed in to this function'); } f(anon_obj); // call the FooObject signature function with anon_obj. /* Note that typedefs can have optional fields as well, marked with "?" typedef OptionalFooObj = { ?optionalString: String, requiredInt: Int } Typedefs work well with conditional compilation. For instance, we could have included this at the top of the file: #if( js ) typedef Surface = js.html.CanvasRenderingContext2D; #elseif( nme ) typedef Surface = nme.display.Graphics; #elseif( !flash9 ) typedef Surface = flash8.MovieClip; #elseif( java ) typedef Surface = java.awt.geom.GeneralPath; #end That would give us a single "Surface" type to work with across all of those platforms. */ } } class UsingExample { public static function example() { /* The "using" import keyword is a special type of class import that alters the behavior of any static methods in the class. In this file, we've applied "using" to "StringTools", which contains a number of static methods for dealing with String types. */ trace(StringTools.endsWith("foobar", "bar") + " should be true!"); /* With a "using" import, the first argument type is extended with the method. What does that mean? Well, since "endsWith" has a first argument type of "String", that means all String types now have the "endsWith" method: */ trace("foobar".endsWith("bar") + " should be true!"); /* This technique enables a good deal of expression for certain types, while limiting the scope of modifications to a single file. Note that the String instance is *not* modified in the run time. The newly attached method is not really part of the attached instance, and the compiler still generates code equivalent to a static method. */ } } ``` We're still only scratching the surface here of what Haxe can do. For a formal overview of all Haxe features, see the [manual](https://haxe.org/manual) and the [API docs](https://api.haxe.org/). For a comprehensive directory of available third-party Haxe libraries, see [Haxelib](https://lib.haxe.org/). For more advanced topics, consider checking out: * [Abstract types](https://haxe.org/manual/types-abstract.html) * [Macros](https://haxe.org/manual/macro.html) * [Compiler Features](https://haxe.org/manual/cr-features.html) Finally, please join us on [the Haxe forum](https://community.haxe.org/), on IRC [#haxe on freenode](http://webchat.freenode.net/), or on the [Haxe Gitter chat](https://gitter.im/HaxeFoundation/haxe). ================================================ FILE: hcl.md ================================================ --- category: tool name: HCL contributors: - ["Romans Malinovskis" , "http://github.com/romaninsh"] filename: terraform.txt --- ## Introduction HCL (Hashicorp Configuration Language) is a high-level configuration language used in tools from Hashicorp (such as Terraform). HCL/Terraform is widely used in provisioning cloud infrastructure and configuring platforms/services through APIs. This document focuses on HCL 0.13 syntax. HCL is a declarative language and Terraform will consume all `*.tf` files in the current folder, so code placement and sequence has no significance. Sub-folders can be consumed through modules. This guide is focused on HCL specifics, you should already be familiar with what Terraform is. ```terraform // Top-level HCL file will interactively ask user values for the variables // which do not have a default value variable "ready" { description = "Ready to learn?" type = bool // default = true } // Module block consults a specified folder for *.tf files, would // effectively prefix all resources IDs with "module.learn-basics." module "learn-basics" { source = "./learn-basics" ready_to_learn = var.ready } output "knowledge" { value = module.learn-basics.knowledge } ``` ## learn-basics ```terraform // Variables are not automatically passed into modules // and can be typeless. variable "ready" { } // It is good practice to define a type though. There are 3 primitive types - // 3 collection types and 2 structural types. Structural types define // types recursively variable "structural-types" { type = object({ object: object({ can-be-nested: bool }), tuple: tuple([int, string]) }) default = { object = { can-be-nested: true } tuple = [3, "cm"] } } // Collection types may specify a type, but can also be "any". variable "list" { type: list(string) default = ["red", "green", "blue"] } variable "map" { type: map(any) default = { red = "#FF0000" "green" = "#00FF00" } } variable "favourites" { type: set default = ["red", "blue"] } // When the type is not specified or is a mix of scalars // they will be converted to strings. // Use modern IDEs for type completion features. It does not matter // in which file and in which order you define a variable, it becomes // accessible from anywhere. // Default values for variables may not use expressions, but you can // use locals for that. You don't specify types for locals. With locals // you can create intermediate products from other variables, modules, // and functions. locals { ready = var.ready ? "yes": "no" yaml = yamldecode(file("${path.module}/file-in-current-folder.yaml")) } // 'locals' blocks can be defined multiple times, but all variables, // resources and local names should be unique locals { set = toset(var.map) } module "more-resources" { source = "../more-learning" yaml-data = local.yaml } // Modules can declare outputs, that can be optionally referenced // (see above), typically outputs appear at the bottom of the file or // in "outputs.tf". output "knowledge" { value = "types so far, more to come" } ``` Terraform exists for managing cloud "resources". A resource could be anything as long as it can be created and destroyed through an API call. (compute instance, distribution, DNS record, S3 bucket, SSL certificate or permission grant). Terraform relies on "providers" for implementing specific vendor APIs. For example the "aws" provider enables use of resources for managing AWS cloud resources. When `terraform` is invoked (`terraform apply`) it will validate code, create all resources in memory, load their existing state from a file (state file), refresh against the current cloud APIs and then calculate the differences. Based on the differences, Terraform proposes a "plan" - series of create, modify or delete actions to bring your infrastructrue in alignment with an HCL definition. Terraform will also automatically calculate dependencies between resources and will maintain the correct create / destroy order. Failure during execution allows you to retry the entire process, which will usually pick off where things finished. ## more-learning Time to introduce resources. ```terraform variable "yaml-data" { // config is sourced from a .yaml file, so technically it is a // map(any), but we can narrow down type like this: type = map(string) } // You do not need to explicitly define providers, they all have reasonable // defaults with environment variables. Using a resource that relies on a // provider will also transparently initialize it (when you invoke terraform init) resource "aws_s3_bucket" "bucket" { bucket = "abc" } // You can also create provider aliases provider "aws" { alias = "as-role" assume_role { role_arn = ".." } } // then use them to create resources resource "aws_s3_bucket_object" "test-file" { // all resources have attributes that can be referenced. Some of those // will be available right away (like bucket) and others may only // become available after the plan begins executing. The test-file resource // will be created only after aws_s3_bucket.bucket finishes being created // depends_on = aws_s3_bucket.bucket bucket = aws_s3_bucket.bucket.bucket key = "index.html" content = file("${path.module}/index.html") // you can also manually specify provider alias provider = aws.as-role } // Each resource will receive an ID in state, like "aws_s3_bucket.bucket". // When resources are created inside a module, their state ID is prepended // with module. module "learn-each" { source = "../learn-each" } // Nesting modules like this may not be the best practice, and it's only // used here for illustration purposes ``` ## learn-each Terraform offers some great features for creating series of objects: ```terraform locals { list = ["red", "green", "blue"] } resource "aws_s3_bucket" "badly-coloured-bucket" { count = count(local.list) bucket_prefix = "${local.list[count.index]}-" } // will create 3 buckets, prefixed with "red-", etc. and followed by // a unique identifier. Some resources will automatically generate // a random name if not specified. The actual name of the resource // (or bucket in this example) can be referenced as attributes output "red-bucket-name" { value = aws_s3_bucket.badly-coloured-bucket[0].bucket } // note that bucket resource ID will be "aws_s3_bucket.badly-coloured-bucket[0]" // through to 2, because they are list index elements. If you remove "red" from // the list, however, it will re-create all the buckets as they would now // have new IDs. A better way is to use for_each resource "aws_s3_bucket" "coloured-bucket" { // for_each only supports maps and sets for_each = toset(local.list) bucket_prefix = "${each.value}-" } // the name for this resource would be aws_s3_bucket.coloured-bucket[red] output "red-bucket-name2" { value = aws_s3_bucket.badly-coloured-bucket["red"].bucket } output "all-bucket-names" { // returns a list containing bucket names - using a "splat expression" value = aws_s3_bucket.coloured-bucket[*].bucket } // there are other splat expressions: output "all-bucket-names2" { value = [for b in aws_s3_bucket.coloured-bucket: b.bucket] } // can also include a filter output "filtered-bucket-names" { value = [for b in aws_s3_bucket.coloured-bucket: b.bucket if length(b.bucket) < 10 ] } // here are some ways to generate maps {red: "red-123123.."} output "bucket-map" { value = { for b in aws_s3_bucket.coloured-bucket: trimsuffix(b.bucket_prefix, '-') => b.bucket } } // as of Terraform 0.13 it is now also possible to use count/each for modules variable "learn-functions" { type = bool default = true } module "learn-functions" { count = var.learn-functions ? 1: 0 source = "../learn-functions" } ``` This is now popular syntax that works in Terraform 0.13 that allows including modules conditionally. ## learn-functions Terraform does not allow you to define your own functions, but there's an extensive list of built-in functions ```terraform locals { list = ["one", "two", "three"] upper_list = [for x in local.list : upper(x) ] // "ONE", "TWO", "THREE" map = {for x in local.list : x => upper(x) } // "one":"ONE", "two":"TWO", "three":"THREE" filtered_list = [for k, v in local.map : substr(v, 0, 2) if k != "two" ] // "ON", "TH" prefixed_list = [for v in local.filtered_list : "pre-${v}" ] // "pre-ON", "pre-TH" joined_list = join(local.upper_list,local. filtered_list) // "ONE", "TWO", "THREE", "pre-ON", "pre-TH" // Set is very similar to List, but element order is irrelevant joined_set = toset(local.joined_list) // "ONE", "TWO", "THREE", "pre-ON", "pre-TH" map_again = map(slice(local.joined_list, 0, 4)) // "ONE":"TWO", "THREE":"pre-ON" } // Usually list manipulation can be useful either for a resource with for_each or // to specify a dynamic block for a resource. This creates a bucket with some tags: resource "aws_s3_bucket" "bucket" { name = "test-bucket" tags = local.map_again } // this is identical to: // resource "aws_s3_bucket" "bucket" { // name = "test-bucket" // tags = { // ONE = "TWO" // THREE = "pre-ON" // } // } // Some resources also contain dynamic blocks. The next example uses a "data" block // to look up 3 buckets (red, green and blue), then creates a policy that contains // read-only access to the red and green buckets and full access to the blue bucket. locals { buckets = { red = "read-only" green = "read-only" blue = "full" } // we could load buckets from a file: // bucket = file('bucket.json') actions = { "read-only" = ["s3:GetObject", "s3:GetObjectVersion"], "full" = ["s3:GetObject", "s3:GetObjectVersion", "s3:PutObject", "s3:PutObjectVersion"] } // we will look up actions, so that we don't have to repeat actions } // use a function to convert map keys into set data "aws_s3_bucket" "bucket" { for_each = toset(keys(local.buckets)) bucket = each.value } // create json for our policy data "aws_iam_policy_document" "role_policy" { statement { effect = "Allow" actions = [ "ec2:*", ] resources = ["*"] } dynamic "statement" { for_each = local.buckets content { effect = "Allow" actions = lookup(local.actions, statement.value, null) resources = [data.aws_s3_bucket.bucket[statement.key]] } } } // and this actually creates the AWS policy with permissions to all buckets resource "aws_iam_policy" "policy" { policy = data.aws_iam_policy_document.role_policy.json } ``` ## Additional Resources - [Terraform tips & tricks](https://blog.gruntwork.io/terraform-tips-tricks-loops-if-statements-and-gotchas-f739bbae55f9) - [Building Dynamic Outputs with Terraform Expressions and Functions](https://www.thegreatcodeadventure.com/building-dynamic-outputs-with-terraform-for_each-for-and-zipmap/) ================================================ FILE: hdl.md ================================================ --- name: HDL filename: learnhdl.hdl contributors: - ["Jack Smith", "https://github.com/JSmithTech2019"] --- HDL (hardware description language) is a specialized language used to describe the structure/behavior of real world circuits. It is used by circuit designers to simulate circuits and logic prior to wiring and fabricating a hardware circuit. HDL allows circuit designers to simulate circuits at a high level without being connected to specific components. ## Basic building blocks & introduction to the language--- This programming language is built by simulating hardware chips and wiring. Normal programming functions are replaced with specialized chips that are added to the current wiring design. Every base chip must be written as it's own file and imported to be used in the current chip, though they may be reused as often as desired. ```verilog // Single line comments start with two forward slashes. /* * Multiline comments can be written using '/*' and 'star/'. * These are often used as comments. * * Note that they cannot be nested and will end at the first 'star/'. */ //////////////////////////////////////////////////// // 1. Chips & Components //////////////////////////////////////////////////// /* * Unlike other languages HDL creates an individual chip (function) per file * These are defined with a name, input arguments, output arguments * and finally the parts/logic of that specific chip. */ // Note CHIP is capitalized, the chip name does not need to be. CHIP Ex { IN a, // Single bit (0 or 1) variable. c[16]; // 16 bit variable bus of single bit values. OUT out[16], // 16 bit variable bus output. carry; // Single bit output variable PARTS: // The functional components of the chip. } // Lines are ended with semicolons but can be continued using commas. The // whitespace is ignored. //////////////////////////////////////////////////// // 2. Inputs, Outputs, & Variables //////////////////////////////////////////////////// /* * Variables and IO are treated as pins/wires and can carry a single bit * of data (0 or 1). */ // Hardware works on low level 0's and 1's, in order to use a constant // high or low we use the terms true and false. a=false; // This is a 0 value. b=true; // This is a 1 value. // Inputs and outputs can be defined as single bits IN a, b; // Creates two single bit inputs // They can also be defined as busses act as arrays where each // index can contain a single bit value. OUT c[16]; // Creates a 16 bit output array. // Bussed values can be accessed using brackets a[0] // The first indexed value in the bus a. a[0..3] // The first 4 values in the a bus. // Values can also be passed in entirety. For example if the function // foo() takes an 8 bit input bus and outputs a 2 bit bus: foo(in=a[0..7], out=c); // C is now a 2 bit internal bus // Note that internally defined busses cannot be subbussed! // To access these elements, output or input them separately: foo(in[0]=false, in[1..7]=a[0..6], out[0]=out1, out[1]=out2); // out1 and out2 can then be passed into other circuits within the design. //////////////////////////////////////////////////// // Combining Subsystems //////////////////////////////////////////////////// /* * HDL relies heavily on using smaller "building block" chips to then be * added into larger and more complex designs. Creating the smaller components * and then adding them to the larger circuit allows for fewer lines of code * as well as reduction in total rewriting of code. */ // We are writing the function AND that checks if inputs I and K are both one. // To implement this chip we will use the built in NAND gate as well as design // a custom NOT gate to invert a single input. // First we construct the Negation (not) chip. We will use the logically // complete gate NAND that is built in for this task. CHIP Not { IN i; // Not gates only take one single bit input. OUT o; // The negated value of a. PARTS: // Add the input to the built in chip, which then sends output to the NOT // output. This effectively negates the given value. Nand(a=i, b=i, out=o); } // By using the built in NAND gate we were able to construct a NOT gate // that works like a real world hardware logic chip. Now we must construct // the AND gate using these two gate primitives. // We define a two input, single output AND gate: CHIP And { IN i, k; // Two single bit inputs. OUT o; // One single bit output. PARTS: // Insert I and K into the nand gate and store the output in an internal // wire called notOut. Nand(a=i,b=k,out=notOut); // Use the not gate we constructed to invert notOut and send to the AND // output. Not(in=notOut,out=o); } // Easy! Now we can use Nand, And, and Not gates in higher level circuits. // Many of these low level components are built in to HDL but any chip can // be written as a submodule and used in larger designs. ``` ## Test Files When working with the nand2tetris hardware simulator chips written using HDL will then be processed against test and comparison files to test functionality of the simulated chip versus the expected output. To do this a test file will be loaded into the hardware simulator and run against the simulated hardware. ```verilog // First the chip the test file is written for is loaded load .hdl // We set the output file for the simulated chip output as well as the comparison // file that it will be tested against. We also specify what the output is // expected to look like. In this case there will be two output columns, each // will be buffered by a single space on either side and 4 binary values in // the center of each column. output-file .out, compare-to .cmp, output-list in%B1.4.1 out%B1.4.1; // Then we set initial values for inputs to the chip. For example set enable1 1, // set input enable1 to 1 set enable2 0, // set input enable2 to 0 // The clock is also controlled in the test file using tick and tock. Tick is a // positive pulse and tock takes the clock back to 0. Clock cycles can be run // multiple times in a row with no other changes to inputs or outputs. tick, tock, // Finally we output the first expected value (from the test file) which is then // compared with the first line of real output from our HDL circuit. This output // can be viewed in the .out file. output; // An example of , a chip that takes in a 4 bit value as input and // adds 1 to that value could have the following as test code: // Set the input value to 0000, clock pulse, compare output from cmp file to actual out. set in %B0000, tick, tock, output; // Set the input value to 0110, clock pulse, compare output from cmp file to actual out. set in %B0110, tick, tock, output; // The expected output for case 1 should be 0001 and case 2 expects 0111, lets // learn a little more about comparison files before finalizing our lesson. ``` ## Comparison Files Now lets take a look at comparison files, the files that hold what the test file compares with the actual output of an HDL chip in the hardware simulator! ```verilog // Like the example above, the structure of the comparison file // would look something like this | in | out | | 0000 | 0001 | | 0110 | 0111 | // Notice how the input values specified in the test case are equivalent to the // `in` column of the comparison file, and that the space buffer is 1 on either side. // If the output from the HDL code we not this, such as the output below, then the // test will fail and the user will know that the simulated chip is not correctly designed. | in | out | | 0000 | 0001 | | 0110 | 0110 | // Error! The chip did not add 1 here, something went wrong. ``` This is incredibly useful as it allows designers to simulate chip logic prior to fabricating real life hardware and identify problems in their designs. Be warned that errors in the test or comparison files can lead to both false positives and also the more damaging false negatives so ensure that the logic is sound behind the test creation. Good luck and happy coding! ## Resources * [From Nand To Tetris](https://www.nand2tetris.org) ## Further Reading * [Hardware Description Language](https://en.wikipedia.org/wiki/Hardware_description_language) * [HDL Programming Fundamentals](https://www.electronicdesign.com/products/hdl-programming-fundamentals) ================================================ FILE: he/html.md ================================================ --- contributors: - ['Christophe THOMAS', 'https://github.com/WinChris'] translators: - ['Menachem Zeivald', 'https://github.com/MenachemZeivald'] --- HTML קיצור של Hypertext Markup Language כלומר זוהי שפה שמשתמשת בתגיות. זוהי שפה המאפשרת לנו לכתוב אתרי אינטרנט. זוהי שפת תגיות והיא מאפשרת לנו לכתוב דפי אינטרנט באמצעות קוד כדי לתת הוראות לדפדפן כיצד יש להציג טקסט ונתונים. למעשה, קובצי HTML הם קבצי טקסט פשוטים. מהם התגיות? זוהי שיטה לארגון מידע על ידי הקפתו בתגיות פתיחה וסגירה. התגית משמשת כדי לתת משמעות לטקסט שהיא מקיפה. ל-HTML יש גרסאות רבות. כאן נדבר על HTML5. **הערה:** אתה יכול לבדוק את התגים והאלמנטים השונים תוך כדי קריאת המדריך באתר כמו [codepen](http://codepen.io/pen/) כדי לראות את ההשפעות שלהם, להבין איך הם עובדים ולהכיר את השפה. מאמר זה עוסק בעיקר בתחביר של HTML וכמה עצות שימושיות. ```html האתר שלי

שלום עולם!

בואו נבדוק את הקישור הזה

זוהי פסקה.

זו עוד פסקה.

  • זה פריט ברשימה לא ממוספרת
  • זהו פריט נוסף
  • וזה הפריט האחרון ברשימה
האתר שלי

שלום עולם

בואו נבדוק את הקישור הזה

זוהי פסקה.

זו עוד פסקה.

  • זה פריט ברשימה לא ממוספרת
  • זהו פריט נוסף
  • וזה הפריט האחרון ברשימה
כותרת ראשונה כותרת שנייה
שורה ראשונה, עמודה ראשונה שורה ראשונה, עמודה שנייה
שורה שנייה, עמודה ראשונה שורה שנייה, עמודה שנייה
``` ## לקריאה נוספת - [Wikipedia](https://he.wikipedia.org/wiki/HTML) - [HTML Tutorial (EN)](https://developer.mozilla.org/en-US/docs/Web/HTML) - [W3Schools (EN)](http://www.w3schools.com/html/html_intro.asp) ================================================ FILE: he/uxntal.md ================================================ --- contributors: - ["Devine Lu Linvega", "https://wiki.xxiivv.com"] translators: - ["Maja Abramski-Kronenberg", "https://me.digitalwords.net"] ---

אוקסנטל (Uxntal) היא שפת סף מבוססת מחסנית שמִּתרגמת לשפת מכונה של מכונה ווירטואלית בשם אוקסן (Uxn).

תכנות של מכונת מחסנית עלול להראות מוזר בגלל השימוש בכתיב סופי, כלומר כתיב שבו הסמנים של פעולות (אופרטורים) תמיד ממוקמים בסוף הפעולה. לדוגמה, נכתוב 3 4 + במקום הכתיב הרגיל 3 + 4.

את הביטוי שנכתב בכתיב הרגיל (5 + 10) * 3 נוכל לכתוב 5 10 + 3 * בכתיב הסופי, שנקרא גם „כתיב פולני הפוך”.

```tal ( זו הערה ) ( התכנות באוקסנטל נעשה כולו בעזרת שינוי המחסנית ) #12 ( דחוף בית (8 סיביות) ) #3456 ( דחוף צמד בתים (16 סיביות) ) ( באוקסן 32 הוראות, ולכל הוראה שלושה מצבים אפשריים ) POP ( שלוף בית ) POP2 ( שלוף צמד בתים ) ( המצבים הם:‏ [2] (מצב צמד בתים) עבוד עם צמד בתים במחסנית (מצב ברירת המחדל הוא עבודה עם בתים) [k] (מצב הותרה) הפריטים עליהם מבוצעת ההוראה נשארים במחסנית [r] (מצב חזרה) ההוראה מבוצעת על מחסנית החזרה ) #12 #34 ADD ( 46 ) #12 #34 ADDk ( 12 34 46 ) ( ניתן לשלב בין המצבים השונים ) #1234 #5678 ADD2k ( 12 34 56 78 68 ac ) ( ההוראות החשבוניות וההוראות על סיביות הן:‏ ADD SUB MUL DIV AND ORA EOR SFT ) ( ניתן ליצור הוראות חדשות בעזרת מקרואים ) %MOD2 { DIV2k MUL2 SUB2 } #1234 #0421 MOD2 ( 01 b0 ) ( ---------------------------------------------------------------------------- ) ( צמד בתים הוא פשוט שני בתים צמודים; ניתן גם לפעול על כל בית בנפרד ) #1234 SWP ( 34 12 ) #1234 #5678 SWP2 ( 56 78 12 34 ) #1234 #5678 SWP ( 12 34 78 56 ) ( ניתן להסיר מהמחסנית כל אחד מהבתים שמרכיבים צמד בתים ) #1234 POP ( 12 ) #1234 NIP ( 34 ) ( ההוראות על המחסנית עצמה הן:‏ POP DUP NIP SWP OVR ROT ) ( ---------------------------------------------------------------------------- ) ( ניתן להשוות בין ערכים במחסנית ) #12 #34 EQU ( 00 ) #12 #12 EQU ( 01 ) ( הוראות לוגיות דוחפות למחסנית דגל עם ערך 00 או 01 לפי התוצאה ) #12 #34 LTH #78 #56 GTH #0101 EQU2 ( 01 ) ( ההוראות הלוגיות הן:‏ EQU NEQ GTH LTH ) ( ---------------------------------------------------------------------------- ) ( הזכרון הזמין לאוקסן:‏ ‏256 בתים במחסנית העבודה ‏256 בתים במחסנית החזרה ‏65536 בתים בזכרון ‏256 בתים בזכרון הקלט והפלט ) ( 0000-ffff כתובות הזכרון הזמינות הן בטווח ) #12 #0200 STA ( אחסן 12 בכתובת 0200 בזכרון ) #3456 #0201 STA2 ( אחסן 3456 בכתובת 0201 בזכרון ) #0200 LDA2 ( 12 34 ) ( הכתובות בדף האפס הן בנות בית יחיד ) #1234 #80 STZ2 ( אחסן 12 ב־0080, ו־34 ב־0081 ) #80 LDZ2 ( 12 34 ) ( התקנים חיצוניים הם הדרך של אוקסן לתקשר עם העולם החיצון.‏ ניתן לחבר עד 16 התקנים בעת ובעונה אחת.‏ .10-1f הבתים של ההתקנים נקראים „פורטים”. לדוגמה, התקן הקונסולה משתמש בפורטים /write הפורט לכתיבה לקונסולה, שמספרו 18, נקרא בשם ) %EMIT { #18 DEO } #31 EMIT ( הדפס "1" בקונסולה ) ( תווית היא שוות ערך למיקום מסויים בתוכנית ) @parent ( parent הגדר תווית בשם ) &child ( parent/child הגדר תת־תווית ) ( ניתן לדחוף מיקומים למחסנית ) ;parent ( דחוף מיקום מוחלט, באורך 2 בתים ) ,parent ( דחוף מיקום יחסי, באורך בית אחד ) .parent ( דחוף מיקום בדף האפס, באורך בית אחד ) ( ההוראות על הזכרון הן:‏ LDZ STZ LDR STR LDA STA DEI DEO ) ( ---------------------------------------------------------------------------- ) ( הוראות לוגיות מאפשרות ליצור תנאים ) #12 #34 NEQ ,skip JCN #31 EMIT @skip ( for ניתן גם ליצור בעזרתן לולאות ) #3a #30 @loop DUP EMIT ( כשהתוכנית תסיים יודפס "0123456789" בקונסולה ) INC GTHk ,loop JCN POP2 ( while בדומה, ניתן ליצור גם לולאות ) ;word @while LDAk EMIT INC2 LDAk ,while JCN POP2 BRK @word "vermillion $1 ( JMP2r ולחזור בעזרת ,JSR ניתן לקפוץ אל תת־שגרות בעזרת ) ;word ,print-word JSR BRK @print-word ( word* -- ) @while LDAk EMIT INC2 LDAk ,while JCN POP2 JMP2r @word "cerulean ( ההוראות לקפיצה הן:‏ JMP JCN JSR ) ```

רוצה עוד?

================================================ FILE: hi/amd.md ================================================ --- contributors: - ["Frederik Ring", "https://github.com/m90"] --- ## एएमडी के साथ प्रारंभ करना एपीआई को परिभाषित करने के लिए एक तंत्र को निर्दिष्ट ** ** अतुल्यकालिक मॉड्यूल परिभाषा जावास्क्रिप्ट मॉड्यूल ऐसे मॉड्यूल और इसकी अतुल्यकालिक निर्भरता से भरा हुआ है। यह ब्राउज़र पर्यावरण जहां के लिए विशेष रूप से अच्छी तरह से अनुकूल है, और प्रदर्शन , प्रयोज्य, डीबगिंग, और क्रॉस-डोमेन जैसे मॉड्यूल्स को जल्दी सिंक्रनाइज़ लोडिंग करता hai। ### मूल अवधारणा ```javascript // बुनियादी एएमडी एपीआई दो तरीकों लेकिन कुछ भी नहीं होते : `define` और `require` // और सभी मॉड्यूल परिभाषा और खपत के बारे में है : // `define` एक मॉड्यूल को परिभाषित करता है // `require` निर्भरता का एक सेट का आयात करता है और // पारित कर दिया कॉलबैक में उन्हें सेवन करती है // एक नया नाम देकर हम मॉड्यूल को परिभाषित करने का उपयोग करके शुरू करते हैं // जिसकी कोई निर्भरता है । हम एक नाम से गुजर रहा है ऐसा करेंगे // और एक कारखाने समारोह को परिभाषित करने के लिए : define('awesomeAMD', function(){ var isAMDAwesome = function(){ return true; }; // एक मॉड्यूल के कारखाने समारोह की मान है // जब प्राप्त होगा क्या अन्य मॉड्यूल या आवश्यकता कॉल // हमारे `awesomeAMD` मॉड्यूल की आवश्यकता होती है । // निर्यात मूल्य कुछ भी हो सकता है, (निर्माता ) काम करता है, // वस्तुओं, पुरातन, (जो कि बहुत ज्यादा मदद नहीं करेगा , हालांकि) भी अपरिभाषित । return isAMDAwesome; }); // अब, हमारे `awesomeAMD` मॉड्यूल पर निर्भर करता है कि किसी अन्य मॉड्यूल परिभाषित करते हैं। // हमारे परिभाषित करने के लिए एक अतिरिक्त तर्क है कि नोटिस अब // मॉड्यूल की निर्भरता : define('loudmouth', ['awesomeAMD'], function(awesomeAMD){ // निर्भरता कारखाने के तर्कों को पारित हो जाएगा // क्रम में वे निर्दिष्ट कर रहे हैं var tellEveryone = function(){ if (awesomeAMD()){ alert('This is sOoOo rad!'); } else { alert('Pretty dull, isn\'t it?'); } }; return tellEveryone; }); // हम अब परिभाषित का उपयोग करने के लिए कैसे जानते हैं के रूप में, के लिए `require` का उपयोग करते हैं // हमारे कार्यक्रम बंद किक । `require` के हस्ताक्षर है :(arrayOfDependencies, callback)`. require(['loudmouth'], function(loudmouth){ loudmouth(); }); // इस ट्यूटोरियल रन कोड बनाने के लिए है, चलो एक बहुत ही बुनियादी लागू करते हैं // (गैर अतुल्यकालिक ) की मौके पर यहीं एएमडी के संस्करण: function define(name, deps, factory){ // निर्भरता के बिना मॉड्यूल नियंत्रित किया जाता है कैसे नोटिस define[name] = require(factory ? deps : [], factory || deps); } function require(deps, callback){ var args = []; // पहले की जरूरत है सभी निर्भरता पुनः प्राप्त करते हैं // आवश्यकता कॉल द्वारा for (var i = 0; i < deps.length; i++){ args[i] = define[deps[i]]; } // सभी कॉलबैक की निर्भरता को संतुष्ट return callback.apply(null, args); } // आप यहाँ कार्रवाई में इस कोड को देख सकते हैं: http://jsfiddle.net/qap949pd/ ``` ### Require.js के साथ वास्तविक दुनिया के उपयोग परिचयात्मक उदाहरण के विपरीत, `require.js` (सबसे लोकप्रिय एएमडी पुस्तकालय ) वास्तव में लागू करता है **Amd** में **A** , आप XHR के माध्यम से मॉड्यूल और उनकी निर्भरता लोड करने के लिए सक्षम करने के लिए : ```javascript /* file: app/main.js */ require(['modules/someClass'], function(SomeClass){ // निर्भरता लोड होने तक कॉलबैक टाल दिया गया है var thing = new SomeClass(); }); console.log('So here we are, waiting!'); // this will run first ``` परंपरा के अनुसार , आप आमतौर पर एक फाइल में एक मॉड्यूल में ही रखते है । `require.js` फ़ाइल पथ पर आधारित मॉड्यूल नाम को हल कर सकते हैं , तो आप अपने मॉड्यूल के नाम करने की जरूरत नहीं है , लेकिन बस उनके स्थान का उपयोग कर उन्हें संदर्भित कर सकते हैं । उदाहरण के `में someClass` आपके विन्यास की `baseUrl` के सापेक्ष `modules` फ़ोल्डर में माना गया है : * app/ * main.js * modules/ * someClass.js * someHelpers.js * ... * daos/ * things.js * ... इसका मतलब यह है कि हम एक मॉड्यूल आईडी निर्दिष्ट किए बिना `someClass` परिभाषित कर सकते हैं : ```javascript /* file: app/modules/someClass.js */ define(['daos/things', 'modules/someHelpers'], function(thingsDao, helpers){ // module definition, of course, will also happen asynchronously function SomeClass(){ this.method = function(){/**/}; // ... } return SomeClass; }); ``` अपने `main.js` में डिफ़ॉल्ट पथ मानचित्रण व्यवहार का उपयोग `requirejs.config ( configObj )` में परिवर्तन करने के लिए: ```javascript /* file: main.js */ requirejs.config({ baseUrl : 'app', paths : { // आप भी अन्य स्थानों से मॉड्यूल लोड कर सकते हैं jquery : '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min', coolLibFromBower : '../bower_components/cool-lib/coollib' } }); require(['jquery', 'coolLibFromBower', 'modules/someHelpers'], function($, coolLib, helpers){ //एक `main` फ़ाइल में कम से कम एक बार की आवश्यकता को फोन करने की जरूरत है, // अन्यथा कोई कोड कभी चलेंगे coolLib.doFancyStuffWith(helpers.transform($('#foo'))); }); ``` `require.js` आधारित क्षुधा आमतौर पर एक डाटा विशेषता के रूप में `require.js` स्क्रिप्ट टैग को पारित कर दिया है कि एक एकल प्रवेश बिंदु ( `main.js` ) होगा। यह स्वचालित रूप से भरी हुई है और pageload पर क्रियान्वित किया जाएगा : ```html A hundred script tags? Never again! ``` ### R.js का उपयोग कर एक पूरी परियोजना का अनुकूलन कई लोगों को विकास के दौरान समझदार कोड संगठन के लिए एएमडी का उपयोग कर पसंद करते हैं, लेकिन अभी भी पेज लोड पर XHRs के सैकड़ों करने के बजाय उत्पादन में एक भी स्क्रिप्ट फ़ाइल जहाज करने के लिए चाहते हैं। (राइनो भी समर्थन किया है, तो आप शायद Node.js में चलेगा ) `require.js` ( अपनी परियोजना की निर्भरता ग्राफ का विश्लेषण , और अपने सभी मॉड्यूल युक्त एक एकल फाइल निर्माण कर सकते हैं कि `r.js` नामक एक स्क्रिप्ट के साथ आता है ठीक से minified और उपभोग के लिए तैयार है, ) नाम दिया है। Install it using `npm`: ```shell $ npm install requirejs -g ``` अब आप एक विन्यास फाइल के साथ फ़ीड कर सकते हैं: ```shell $ r.js -o app.build.js ``` हमारे ऊपर के उदाहरण के लिए विन्यास की तरह लग सकता है: ```javascript /* file : app.build.js */ ({ name : 'main', // प्रवेश बिंदु के नाम out : 'main-built.js', // फ़ाइल का नाम करने के लिए उत्पादन में लिखने के लिए baseUrl : 'app', paths : { // ` empty :` का उपयोग कर , यह अभी भी समन्वय से लोड किया जाना चाहिए कि r.js बताता है // main.js में निर्दिष्ट स्थान jquery : 'empty:', coolLibFromBower : '../bower_components/cool-lib/coollib' } }) ``` उत्पादन में बनाया फ़ाइल का उपयोग करने के लिए, बस `Data-main` स्वैप: ```html ``` एक अविश्वसनीय रूप से विस्तृत [निर्माण विकल्पों में से अवलोकन](https://github.com/jrburke/r.js/blob/master/build/example.build.js) GitHub रेपो में उपलब्ध है। ### विषय इस ट्यूटोरियल में शामिल नहीं * [लोडर प्लगइन्स / रूपांतरण](http://requirejs.org/docs/plugins.html) * [CommonJS शैली लोड हो रहा है और निर्यात](http://requirejs.org/docs/commonjs.html) * [उन्नत विन्यास](http://requirejs.org/docs/api.html#config) * [शिम विन्यास (गैर एएमडी मॉड्यूल लोडिंग)](http://requirejs.org/docs/api.html#config-shim) * [सीएसएस लदान और require.js साथ अनुकूलन](http://requirejs.org/docs/optimization.html#onecss) * [बनाता है के लिए almond.js का प्रयोग](https://github.com/jrburke/almond) ### अग्रिम पठन: * [सरकारी कल्पना](https://github.com/amdjs/amdjs-api/wiki/AMD) * [क्यों एएमडी?](http://requirejs.org/docs/whyamd.html) * [यूनिवर्सल मॉड्यूल परिभाषा](https://github.com/umdjs/umd) ### कार्यान्वयन: * [Require.js](http://requirejs.org) * [डोजो टूलकिट](http://dojotoolkit.org/documentation/tutorials/1.9/modules/) * [Cujo.js](http://cujojs.com/) * [Curl.js](https://github.com/cujojs/curl) * [Lsjs](https://github.com/zazl/lsjs) * [एमडी](https://github.com/alexlawrence/mmd) ================================================ FILE: hi/c++.md ================================================ --- contributors: - ["Steven Basart", "https://github.com/xksteven"] - ["Matt Kline", "https://github.com/mrkline"] - ["Geoff Liu", "http://geoffliu.me"] - ["Connor Waters", "https://github.com/connorwaters"] - ["Ankush Goyal", "https://github.com/ankushg07"] - ["Jatin Dhankhar", "https://github.com/jatindhankhar"] translators: - ["Jishan Shaikh", "https://github.com/jishanshaikh4"] --- C++ एक सिस्टम प्रोग्रामिंग लैंग्वेज है जो, [इसके आविष्कारक बजेर्न स्ट्राउस्ट्रप के अनुसार](https://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote), के लिए डिजाइन किया गया था * एक "बेहतर सी" बनें * डेटा एब्स्ट्रैक्शन का समर्थन करें * ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग का समर्थन करें * सामान्य प्रोग्रामिंग का समर्थन करें हालांकि इसका सिंटैक्स नई भाषाओं की तुलना में अधिक कठिन या जटिल हो सकता है, इसका व्यापक रूप से उपयोग किया जाता है क्योंकि यह मूल निर्देशों को संकलित करता है जो हो सकते हैं सीधे प्रोसेसर द्वारा चलाया जाता है और हार्डवेयर पर कड़ा नियंत्रण प्रदान करता है (जैसे सी) जेनेरिक, अपवाद और कक्षाओं जैसी उच्च-स्तरीय सुविधाओं की पेशकश करते हुए। गति और कार्यक्षमता का यह संयोजन C++ बनाता है | सबसे व्यापक रूप से उपयोग की जाने वाली प्रोग्रामिंग भाषाओं में से एक। ```c++ ////////////////// // सी . से तुलना ////////////////// // C++ _लगभग_C का सुपरसेट है और इसके लिए अपना मूल सिंटैक्स साझा करता है // परिवर्तनीय घोषणाएं, आदिम प्रकार, और कार्य। // सी की तरह ही, आपके प्रोग्राम का एंट्री पॉइंट एक फंक्शन है, जिसे कहा जाता है // मुख्य एक पूर्णांक वापसी प्रकार के साथ। // यह मान प्रोग्राम की निकास स्थिति के रूप में कार्य करता है। // अधिक जानकारी के लिए https://en.wikipedia.org/wiki/Exit_status देखें। int main(int argc, char** argv) { // कमांड लाइन तर्क उसी तरह argc और argv द्वारा पारित किए जाते हैं // वे सी में हैं। // argc तर्कों की संख्या को इंगित करता है, // और argv सी-स्टाइल स्ट्रिंग्स (चार *) की एक सरणी है // तर्कों का प्रतिनिधित्व करते हैं। // पहला तर्क वह नाम है जिसके द्वारा प्रोग्राम को बुलाया गया था। // यदि आप तर्कों की परवाह नहीं करते हैं तो argc और argv को छोड़ा जा सकता है, // int main का फंक्शन सिग्नेचर देना () // 0 की निकास स्थिति सफलता को इंगित करती है। return 0; } // हालाँकि, C++ निम्नलिखित में से कुछ तरीकों से भिन्न होता है: // सी ++ में, वर्ण अक्षर वर्ण हैं sizeof('c') == sizeof(char) == 1 // सी में, चरित्र अक्षर ints . हैं sizeof('c') == sizeof(int) // सी ++ में सख्त प्रोटोटाइप है void func(); // फ़ंक्शन जो कोई तर्क स्वीकार नहीं करता है // सी में void func(); // फ़ंक्शन जो किसी भी संख्या में तर्कों को स्वीकार कर सकता है // C++ में NULL के बजाय nullptr का प्रयोग करें int* ip = nullptr; // सी मानक हेडर सी ++ में उपलब्ध हैं। // सी हेडर .h में समाप्त होते हैं, जबकि // सी ++ हेडर "सी" के साथ उपसर्ग कर रहे हैं और कोई ".एच" प्रत्यय नहीं है। // सी ++ मानक संस्करण: #include // सी मानक संस्करण: #include int main() { printf("Hello, world!\n"); return 0; } /////////////////////// // फंक्शन ओवरलोडिंग /////////////////////// // सी ++ फ़ंक्शन ओवरलोडिंग का समर्थन करता है // बशर्ते प्रत्येक फ़ंक्शन अलग-अलग पैरामीटर लेता है। void print(char const* myString) { printf("String %s\n", myString); } void print(int myInt) { printf("My int is %d", myInt); } int main() { print("Hello"); // Resolves to void print(const char*) print(15); // Resolves to void print(int) } ///////////////////////////// // डिफ़ॉल्ट फ़ंक्शन तर्क ///////////////////////////// // आप किसी फ़ंक्शन के लिए डिफ़ॉल्ट तर्क प्रदान कर सकते हैं // अगर वे कॉलर द्वारा प्रदान नहीं किए जाते हैं। void doSomethingWithInts(int a = 1, int b = 4) { // यहां इनट्स के साथ कुछ करें } int main() { doSomethingWithInts(); // a = 1, b = 4 doSomethingWithInts(20); // a = 20, b = 4 doSomethingWithInts(20, 5); // a = 20, b = 5 } // डिफ़ॉल्ट तर्क तर्क सूची के अंत में होना चाहिए। void invalidDeclaration(int a = 1, int b) // Error! { } ///////////// // नेमस्पेस ///////////// // नेमस्पेस वैरिएबल, फंक्शन के लिए अलग-अलग स्कोप प्रदान करते हैं, // और अन्य घोषणाएं। // नेमस्पेस को नेस्ट किया जा सकता है। namespace First { namespace Nested { void foo() { printf("This is First::Nested::foo\n"); } } // अंत नामस्थान नेस्टेड } // अंतिम नाम स्थान पहले namespace Second { void foo() { printf("This is Second::foo\n"); } } void foo() { printf("This is global foo\n"); } int main() { // नेमस्पेस सेकेंड से वर्तमान दायरे में सभी प्रतीकों को शामिल करता है। ध्यान दें // वह बस foo() अब काम नहीं करता है, क्योंकि यह अब अस्पष्ट है कि क्या // हम फू को नेमस्पेस सेकेंड या टॉप लेवल में कॉल कर रहे हैं। using namespace Second; Second::foo(); // प्रिंट "यह दूसरा है :: फू" First::Nested::foo(); // प्रिंट "यह पहला है :: नेस्टेड :: फू" ::foo(); // प्रिंट करता है "यह वैश्विक फू है" } /////////////// // इनपुट आउटपुट /////////////// // सी ++ इनपुट और आउटपुट स्ट्रीम का उपयोग करता है // cin, cout, और cerr stdin, stdout और stderr का प्रतिनिधित्व करते हैं। // << इंसर्शन ऑपरेटर है और >> एक्सट्रैक्शन ऑपरेटर है। #include // I/O स्ट्रीम के लिए शामिल करें using namespace std; // स्ट्रीम एसटीडी नेमस्पेस (मानक पुस्तकालय) में हैं int main() { int myInt; // स्टडआउट (या टर्मिनल / स्क्रीन) पर प्रिंट करता है cout << "Enter your favorite number:\n"; // इनपुट लेता है cin >> myInt; // cout को भी स्वरूपित किया जा सकता है cout << "Your favorite number is " << myInt << '\n'; // प्रिंट करता है "आपका पसंदीदा नंबर " है cerr << "Used for error messages"; } ////////// // स्ट्रिंग्स ////////// // सी ++ में स्ट्रिंग्स ऑब्जेक्ट हैं और इसमें कई सदस्य कार्य हैं #include using namespace std; // स्ट्रिंग्स नेमस्पेस एसटीडी (मानक पुस्तकालय) में भी हैं string myString = "Hello"; string myOtherString = " World"; // + का उपयोग संयोजन के लिए किया जाता है। cout << myString + myOtherString; // "Hello World" cout << myString + " You"; // "Hello You" // सी ++ स्ट्रिंग्स म्यूटेबल हैं। myString.append(" Dog"); cout << myString; // "Hello Dog" ///////////// // संदर्भ ///////////// // सी में वाले जैसे पॉइंटर्स के अलावा, // सी ++ में _references_ हैं। // ये पॉइंटर प्रकार हैं जिन्हें एक बार सेट करने के बाद पुन: असाइन नहीं किया जा सकता है // और शून्य नहीं हो सकता। // उनके पास वैरिएबल के समान सिंटैक्स भी है: // नहीं * dereferencing के लिए आवश्यक है और // और (का पता) असाइनमेंट के लिए उपयोग नहीं किया जाता है। using namespace std; string foo = "I am foo"; string bar = "I am bar"; string& fooRef = foo; // यह foo का संदर्भ बनाता है। fooRef += ". Hi!"; // संदर्भ के माध्यम से फू को संशोधित करें cout << fooRef; // प्रिंट "I am foo. Hi!" // "fooRef" को पुन: असाइन नहीं करता है। यह "फू = बार" जैसा ही है, और // फू == "मैं बार हूँ" // इस लाइन के बाद। cout << &fooRef << endl; // फू का पता प्रिंट करता है fooRef = bar; cout << &fooRef << endl; // अभी भी फू का पता प्रिंट करता है cout << fooRef; // प्रिंट "I am bar" // fooRef का पता वही रहता है, यानी यह अभी भी foo की बात कर रहा है। const string& barRef = bar; // बार के लिए एक कॉन्स्टेबल संदर्भ बनाएं। // सी की तरह, कॉन्स्ट वैल्यू (और पॉइंटर्स और रेफरेंस) को संशोधित नहीं किया जा सकता है। barRef += ". Hi!"; // त्रुटि, कॉन्स्ट संदर्भों को संशोधित नहीं किया जा सकता है। // साइडट्रैक: इससे पहले कि हम संदर्भों के बारे में अधिक बात करें, हमें एक अवधारणा पेश करनी चाहिए // एक अस्थायी वस्तु कहा जाता है। मान लीजिए हमारे पास निम्नलिखित कोड है: string tempObjectFun() { ... } string retVal = tempObjectFun(); // दूसरी पंक्ति में वास्तव में क्या होता है: // - एक स्ट्रिंग ऑब्जेक्ट tempObjectFun से लौटाया जाता है // - तर्क के रूप में लौटाई गई वस्तु के साथ एक नई स्ट्रिंग का निर्माण किया जाता है // कंस्ट्रक्टर // - लौटाई गई वस्तु नष्ट हो जाती है // लौटाई गई वस्तु को अस्थायी वस्तु कहा जाता है। अस्थायी वस्तुएं हैं // जब भी कोई फ़ंक्शन किसी ऑब्जेक्ट को लौटाता है, तब बनाया जाता है, और वे नष्ट हो जाते हैं // संलग्न अभिव्यक्ति के मूल्यांकन का अंत (ठीक है, यह वही है // मानक कहता है, लेकिन संकलक को इस व्यवहार को बदलने की अनुमति है। ऊपर देखो // "वापसी मूल्य अनुकूलन" यदि आप इस तरह के विवरण में हैं)। तो इसमें // कोड: foo(bar(tempObjectFun())) // यह मानते हुए कि फू और बार मौजूद हैं, tempObjectFun से लौटाई गई वस्तु है // बार को पास किया गया, और फू को कॉल करने से पहले इसे नष्ट कर दिया गया। // अब वापस संदर्भों पर। "संलग्नक के अंत में" का अपवाद // अभिव्यक्ति" नियम यह है कि यदि एक अस्थायी वस्तु एक कॉन्स्ट संदर्भ के लिए बाध्य है, तो // किस मामले में इसका जीवन वर्तमान दायरे तक बढ़ जाता है: void constReferenceTempObjectFun() { // constRef अस्थायी वस्तु प्राप्त करता है, और यह इस के अंत तक मान्य है // समारोह। const string& constRef = tempObjectFun(); ... } // सी ++ 11 में पेश किया गया एक अन्य प्रकार का संदर्भ विशेष रूप से अस्थायी के लिए है // ऑब्जेक्ट्स। आपके पास इसके प्रकार का एक चर नहीं हो सकता है, लेकिन इसमें पूर्वता होती है // अधिभार संकल्प: void someFun(string& s) { ... } // नियमित संदर्भ void someFun(string&& s) { ... } // अस्थायी वस्तु का संदर्भ string foo; someFun(foo); // नियमित संदर्भ के साथ संस्करण को कॉल करें someFun(tempObjectFun()); // अस्थायी संदर्भ के साथ संस्करण को कॉल करें // उदाहरण के लिए, आप कंस्ट्रक्टर के इन दो संस्करणों को देखेंगे // std::basic_string: basic_string(const basic_string& other); basic_string(basic_string&& other); // विचार यह है कि अगर हम एक अस्थायी वस्तु से एक नई स्ट्रिंग का निर्माण कर रहे हैं (जो // वैसे भी जल्द ही नष्ट होने जा रहा है), हम अधिक कुशल हो सकते हैं // कंस्ट्रक्टर जो उस अस्थायी स्ट्रिंग के कुछ हिस्सों को "बचाता" है। आप इसे देखेंगे // अवधारणा को "मूव सेमेन्टिक्स" के रूप में जाना जाता है। ///////////////////// // Enums ///////////////////// // Enums सबसे अधिक उपयोग किए जाने वाले स्थिरांक को मान निर्दिष्ट करने का एक तरीका है // आसान विज़ुअलाइज़ेशन और कोड को पढ़ना enum ECarTypes { Sedan, Hatchback, SUV, Wagon }; ECarTypes GetPreferredCarType() { return ECarTypes::Hatchback; } // सी ++ 11 के रूप में एनम को एक प्रकार असाइन करने का एक आसान तरीका है जो हो सकता है // डेटा के क्रमांकन में उपयोगी और एनम को आगे-पीछे परिवर्तित करना // वांछित प्रकार और उनके संबंधित स्थिरांक enum ECarTypes : uint8_t { Sedan, // 0 Hatchback, // 1 SUV = 254, // 254 Hybrid // 255 }; void WriteByteToFile(uint8_t InputValue) { // किसी फ़ाइल में इनपुटवैल्यू को क्रमबद्ध करें } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { // एनम को इसके घोषित एनम प्रकार के कारण uint8_t में परिवर्तित कर दिया गया है WriteByteToFile(InputCarType); } // दूसरी ओर, हो सकता है कि आप नहीं चाहते कि गलती से एनम को एक पूर्णांक में डाला जाए // टाइप करें या अन्य एनम के लिए ताकि इसके बजाय एक एनम क्लास बनाना संभव हो जो // परोक्ष रूप से परिवर्तित नहीं किया जाएगा enum class ECarTypes : uint8_t { Sedan, // 0 Hatchback, // 1 SUV = 254, // 254 Hybrid // 255 }; void WriteByteToFile(uint8_t InputValue) { // किसी फ़ाइल में इनपुटवैल्यू को क्रमबद्ध करें } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { // संकलित नहीं होगा, भले ही ECarTypes एक uint8_t एनम के कारण है // "एनम क्लास" के रूप में घोषित किया जा रहा है! WriteByteToFile(InputCarType); } ////////////////////////////////////////// // कक्षाएं और वस्तु-उन्मुख प्रोग्रामिंग ////////////////////////////////////////// // कक्षाओं का पहला उदाहरण #include // एक वर्ग घोषित करें। // कक्षाएं आमतौर पर हेडर (.h या .hpp) फाइलों में घोषित की जाती हैं। class Dog { // सदस्य चर और कार्य डिफ़ॉल्ट रूप से निजी हैं। std::string name; int weight; // इसका अनुसरण करने वाले सभी सदस्य सार्वजनिक हैं // जब तक "निजी:" या "संरक्षित:" नहीं मिलता है। public: // Default constructor Dog(); // सदस्य फ़ंक्शन घोषणाएं (कार्यान्वयन का पालन करें) // ध्यान दें कि हम यहां रखने के बजाय std::string का उपयोग करते हैं // नेमस्पेस एसटीडी का उपयोग करना; // ऊपर। // हेडर में कभी भी "नेमस्पेस का उपयोग करके" स्टेटमेंट न डालें। void setName(const std::string& dogsName); void setWeight(int dogsWeight); // ऐसे कार्य जो वस्तु की स्थिति को संशोधित नहीं करते हैं // को कॉन्स्ट के रूप में चिह्नित किया जाना चाहिए। // यह आपको ऑब्जेक्ट के संदर्भ में दिए जाने पर उन्हें कॉल करने की अनुमति देता है। // यह भी ध्यान दें कि कार्यों को स्पष्ट रूप से _virtual_ के रूप में घोषित किया जाना चाहिए // व्युत्पन्न कक्षाओं में ओवरराइड करने के लिए। // कार्य प्रदर्शन कारणों से डिफ़ॉल्ट रूप से आभासी नहीं हैं। virtual void print() const; // फंक्शन को क्लास बॉडी के अंदर भी परिभाषित किया जा सकता है। // इस तरह परिभाषित कार्य स्वचालित रूप से रेखांकित होते हैं। void bark() const { std::cout << name << " barks!\n"; } // कंस्ट्रक्टर्स के साथ, C++ डिस्ट्रक्टर्स प्रदान करता है। // इन्हें तब कहा जाता है जब कोई वस्तु हटा दी जाती है या दायरे से बाहर हो जाती है। // यह RAII जैसे शक्तिशाली प्रतिमानों को सक्षम बनाता है // (निचे देखो) // विध्वंसक आभासी होना चाहिए यदि एक वर्ग से प्राप्त किया जाना है; // यदि यह आभासी नहीं है, तो व्युत्पन्न वर्ग 'विनाशक होगा' // यदि ऑब्जेक्ट बेस-क्लास संदर्भ के माध्यम से नष्ट हो जाता है तो कॉल नहीं किया जाएगा // या सूचक। virtual ~Dog(); }; // अर्धविराम को वर्ग परिभाषा का पालन करना चाहिए। // क्लास सदस्य फ़ंक्शन आमतौर पर .cpp फ़ाइलों में कार्यान्वित किए जाते हैं। Dog::Dog() { std::cout << "A dog has been constructed\n"; } // वस्तुओं (जैसे तार) को संदर्भ द्वारा पारित किया जाना चाहिए // यदि आप उन्हें संशोधित कर रहे हैं या यदि आप नहीं हैं तो संदर्भ संदर्भ। void Dog::setName(const std::string& dogsName) { name = dogsName; } void Dog::setWeight(int dogsWeight) { weight = dogsWeight; } // ध्यान दें कि "आभासी" केवल घोषणा में आवश्यक है, परिभाषा नहीं। void Dog::print() const { std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; } Dog::~Dog() { std::cout << "Goodbye " << name << '\n'; } int main() { Dog myDog; // prints "A dog has been constructed" myDog.setName("Barkley"); myDog.setWeight(10); myDog.print(); // prints "Dog is Barkley and weighs 10 kg" return 0; } // prints "Goodbye Barkley" // विरासत: // इस वर्ग को सब कुछ विरासत में मिला है और डॉग क्लास से संरक्षित है // साथ ही निजी लेकिन सीधे निजी सदस्यों / विधियों तक नहीं पहुंच सकता है // ऐसा करने के लिए सार्वजनिक या संरक्षित विधि के बिना class OwnedDog : public Dog { public: void setOwner(const std::string& dogsOwner); // सभी स्वामित्व वाले कुत्तों के लिए प्रिंट फ़ंक्शन के व्यवहार को ओवरराइड करें। ले देख // https://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping // अधिक सामान्य परिचय के लिए यदि आप अपरिचित हैं // उपप्रकार बहुरूपता। // ओवरराइड कीवर्ड वैकल्पिक है लेकिन सुनिश्चित करता है कि आप वास्तव में हैं // बेस क्लास में विधि को ओवरराइड करना। private: std::string owner; }; // इस बीच, संबंधित .cpp फ़ाइल में: void OwnedDog::setOwner(const std::string& dogsOwner) { owner = dogsOwner; } void OwnedDog::print() const { Dog::print(); // बेस डॉग क्लास में प्रिंट फ़ंक्शन को कॉल करें class std::cout << "Dog is owned by " << owner << '\n'; // प्रिंट करता है "कुत्ता <नाम> है और वजन <वजन>" है // "कुत्ता <मालिक> के स्वामित्व में है" } ////////////////////////////////////////// // आरंभीकरण और ऑपरेटर ओवरलोडिंग ////////////////////////////////////////// // सी ++ में आप ऑपरेटरों के व्यवहार को ओवरलोड कर सकते हैं जैसे +, -, *, /, आदि। // यह एक फ़ंक्शन को परिभाषित करके किया जाता है जिसे कहा जाता है // जब भी ऑपरेटर का उपयोग किया जाता है। #include using namespace std; class Point { public: // सदस्य चर को इस तरह से डिफ़ॉल्ट मान दिया जा सकता है। double x = 0; double y = 0; // एक डिफ़ॉल्ट कंस्ट्रक्टर को परिभाषित करें जो कुछ भी नहीं करता है // लेकिन बिंदु को डिफ़ॉल्ट मान (0, 0) पर प्रारंभ करें Point() { }; // The following syntax is known as an initialization list // and is the proper way to initialize class member values Point (double a, double b) : x(a), y(b) { /* मानों को इनिशियलाइज़ करने के अलावा कुछ न करें */ } // + ऑपरेटर को ओवरलोड करें। Point operator+(const Point& rhs) const; // + = ऑपरेटर को अधिभारित करें Point& operator+=(const Point& rhs); // - और - = ऑपरेटरों को जोड़ना भी समझ में आता है, // लेकिन हम उन्हें संक्षिप्तता के लिए छोड़ देंगे। }; Point Point::operator+(const Point& rhs) const { // एक नया बिंदु बनाएं जो इस एक और rhs का योग हो।. return Point(x + rhs.x, y + rhs.y); } // के सबसे बाएं चर के संदर्भ को वापस करने के लिए यह अच्छा अभ्यास है // सौंपा गया कार्य। `(a += b) == c` इस तरह से काम करेगा। Point& Point::operator+=(const Point& rhs) { x += rhs.x; y += rhs.y; // `this` उस वस्तु का सूचक है, जिस पर एक विधि कहलाती है। return *this; } int main () { Point up (0,1); Point right (1,0); // यह प्वाइंट + ऑपरेटर को कॉल करता है // पॉइंट अप + (फ़ंक्शन) को इसके पैरामीटर के रूप में दाईं ओर कॉल करता है Point result = up + right; // Prints "Result is upright (1,1)" cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; return 0; } ///////////////////// // टेम्पलेट्स ///////////////////// // C++ में टेम्प्लेट ज्यादातर सामान्य प्रोग्रामिंग के लिए उपयोग किए जाते हैं, हालांकि वे हैं // अन्य भाषाओं में सामान्य निर्माणों की तुलना में बहुत अधिक शक्तिशाली। वे भी // स्पष्ट और आंशिक विशेषज्ञता और कार्यात्मक-शैली प्रकार का समर्थन करें // कक्षाएं; वास्तव में, वे एक ट्यूरिंग-पूर्ण कार्यात्मक भाषा एम्बेडेड हैं // सी ++ में! // हम उस तरह की सामान्य प्रोग्रामिंग से शुरू करते हैं जिससे आप परिचित हो सकते हैं। सेवा // एक वर्ग या फ़ंक्शन को परिभाषित करें जो एक प्रकार का पैरामीटर लेता है: template class Box { public: // इस वर्ग में, टी का उपयोग किसी अन्य प्रकार के रूप में किया जा सकता है। void insert(const T&) { ... } }; // संकलन के दौरान, कंपाइलर वास्तव में प्रत्येक टेम्पलेट की प्रतियां बनाता है // प्रतिस्थापित मापदंडों के साथ, इसलिए वर्ग की पूरी परिभाषा होनी चाहिए // प्रत्येक आह्वान पर उपस्थित। यही कारण है कि आप टेम्पलेट वर्ग परिभाषित देखेंगे // पूरी तरह से हेडर फाइलों में। // स्टैक पर टेम्प्लेट क्लास को इंस्टेंट करने के लिए: Box intBox; // और आप इसका उपयोग कर सकते हैं जैसा कि आप उम्मीद करेंगे: intBox.insert(123); // आप निश्चित रूप से, नेस्ट टेम्प्लेट कर सकते हैं: Box > boxOfBox; boxOfBox.insert(intBox); // C++11 तक, आपको दो '>' के बीच एक जगह रखनी थी, अन्यथा '>>' // सही शिफ्ट ऑपरेटर के रूप में पार्स किया जाएगा। // आप कभी-कभी देखेंगे // टेम्पलेट<टाइपनाम टी> // बजाय। 'वर्ग' कीवर्ड और 'टाइपनाम' कीवर्ड _अधिकतर_ हैं // इस मामले में विनिमेय। पूरी व्याख्या के लिए देखें // https://en.wikipedia.org/wiki/Typename // (हाँ, उस कीवर्ड का अपना विकिपीडिया पेज है)। // इसी तरह, एक टेम्पलेट फ़ंक्शन: template void barkThreeTimes(const T& input) { input.bark(); input.bark(); input.bark(); } // ध्यान दें कि यहां प्रकार के मापदंडों के बारे में कुछ भी निर्दिष्ट नहीं है। संकलक // उत्पन्न करेगा और फिर टेम्पलेट के प्रत्येक आमंत्रण को टाइप-चेक करेगा, इसलिए // उपरोक्त फ़ंक्शन किसी भी प्रकार 'T' के साथ काम करता है जिसमें एक कॉन्स 'bark' विधि होती है! Dog fluffy; fluffy.setName("Fluffy") barkThreeTimes(fluffy); // Prints "Fluffy barks" three times. // टेम्प्लेट मापदंडों का वर्ग होना जरूरी नहीं है: template void printMessage() { cout << "Learn C++ in " << Y << " minutes!" << endl; } // और आप स्पष्ट रूप से अधिक कुशल कोड के लिए टेम्पलेट्स को विशेषज्ञ बना सकते हैं। का // बेशक, विशेषज्ञता के अधिकांश वास्तविक दुनिया के उपयोग इस तरह के रूप में तुच्छ नहीं हैं। // ध्यान दें कि आपको अभी भी फ़ंक्शन (या वर्ग) को टेम्पलेट के रूप में घोषित करने की आवश्यकता है // भले ही आपने सभी मापदंडों को स्पष्ट रूप से निर्दिष्ट किया हो। template<> void printMessage<10>() { cout << "Learn C++ faster in only 10 minutes!" << endl; } printMessage<20>(); // Prints "Learn C++ in 20 minutes!" printMessage<10>(); // Prints "Learn C++ faster in only 10 minutes!" ///////////////////// // संचालन अपवाद ///////////////////// // मानक पुस्तकालय कुछ अपवाद प्रकार प्रदान करता है // (देखें https://en.cppreference.com/w/cpp/error/exception) // लेकिन किसी भी प्रकार को अपवाद के रूप में फेंका जा सकता है #include #include // _try_ ब्लॉक के अंदर फेंके गए सभी अपवादों को बाद में पकड़ा जा सकता है // _कैच_ हैंडलर। try { // _new_ का उपयोग करके ढेर पर अपवाद आवंटित न करें। throw std::runtime_error("A problem occurred"); } // कॉन्स्ट संदर्भ द्वारा अपवादों को पकड़ें यदि वे ऑब्जेक्ट हैं catch (const std::exception& ex) { std::cout << ex.what(); } // पिछले _catch_ ब्लॉक द्वारा नहीं पकड़े गए किसी भी अपवाद को पकड़ता है catch (...) { std::cout << "Unknown exception caught"; throw; // Re-throws the exception } /////// // आरएआईआई /////// // RAII का अर्थ "संसाधन अधिग्रहण आरंभीकरण है"। // इसे अक्सर C++ में सबसे शक्तिशाली प्रतिमान माना जाता है // और सरल अवधारणा है कि एक वस्तु के लिए एक निर्माता // उस वस्तु के संसाधनों को प्राप्त करता है और विनाशक उन्हें जारी करता है। // यह समझने के लिए कि यह कैसे उपयोगी है, // एक फ़ंक्शन पर विचार करें जो C फ़ाइल हैंडल का उपयोग करता है: void doSomethingWithAFile(const char* filename) { // शुरू करने के लिए, मान लें कि कुछ भी विफल नहीं हो सकता है। FILE* fh = fopen(filename, "r"); // Open the file in read mode. doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); fclose(fh); // Close the file handle. } // दुर्भाग्य से, त्रुटि प्रबंधन से चीजें जल्दी जटिल हो जाती हैं। // मान लीजिए कि fopen विफल हो सकता है, और वह doSomethingWithTheFile और // doSomethingElseWithIt विफल होने पर त्रुटि कोड लौटाता है। // (अपवाद विफलता से निपटने का पसंदीदा तरीका है, // लेकिन कुछ प्रोग्रामर, विशेष रूप से C बैकग्राउंड वाले, // अपवादों की उपयोगिता पर असहमत)। // अब हमें विफलता के लिए प्रत्येक कॉल की जांच करनी होगी और फ़ाइल हैंडल को बंद करना होगा // यदि कोई समस्या हुई। bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // फ़ाइल को रीड मोड में खोलें if (fh == nullptr) // लौटाया गया सूचक विफलता पर शून्य है। return false; // Report that failure to the caller. // मान लें कि प्रत्येक फ़ंक्शन विफल होने पर गलत लौटाता है if (!doSomethingWithTheFile(fh)) { fclose(fh); // फ़ाइल हैंडल को बंद करें ताकि यह लीक न हो। return false; // त्रुटि का प्रचार करें। } if (!doSomethingElseWithIt(fh)) { fclose(fh); // फ़ाइल हैंडल को बंद करें ताकि यह लीक न हो। return false; // त्रुटि का प्रचार करें। } fclose(fh); // फ़ाइल हैंडल को बंद करें ताकि यह लीक न हो। return true; // सफलता का संकेत दें } // सी प्रोग्रामर अक्सर गोटो का उपयोग करके इसे थोड़ा साफ करते हैं: bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); if (fh == nullptr) return false; if (!doSomethingWithTheFile(fh)) goto failure; if (!doSomethingElseWithIt(fh)) goto failure; fclose(fh); // Close the file return true; // Indicate success failure: fclose(fh); return false; // Propagate the error } // यदि फ़ंक्शन अपवादों का उपयोग करके त्रुटियों को इंगित करता है, // चीजें थोड़ी साफ हैं, लेकिन फिर भी उप-इष्टतम हैं। void doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Open the file in shared_ptrread mode if (fh == nullptr) throw std::runtime_error("Could not open the file."); try { doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } catch (...) { fclose(fh); // Be sure to close the file if an error occurs. throw; // Then re-throw the exception. } fclose(fh); // Close the file // Everything succeeded } // इसकी तुलना C++ के फाइल स्ट्रीम क्लास (fstream) के उपयोग से करें // fstream फ़ाइल को बंद करने के लिए अपने विनाशक का उपयोग करता है। // ऊपर से याद करें कि विध्वंसक स्वचालित रूप से कहलाते हैं // जब भी कोई वस्तु दायरे से बाहर हो जाती है। void doSomethingWithAFile(const std::string& filename) { // ifstream इनपुट फ़ाइल स्ट्रीम के लिए छोटा है std::ifstream fh(filename); // Open the file // Do things with the file doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } //फ़ाइल स्वचालित रूप से यहाँ विध्वंसक द्वारा बंद कर दी गई है // इसके _massive_ फायदे हैं: // 1. चाहे कुछ भी हो जाए, // संसाधन (इस मामले में फ़ाइल हैंडल) को साफ किया जाएगा। // एक बार जब आप विध्वंसक को सही ढंग से लिख लेते हैं, // हैंडल को बंद करना और रिसोर्स को लीक करना भूल जाना _असंभव_ है। // 2. ध्यान दें कि कोड ज्यादा साफ है। // विनाशक पर्दे के पीछे फ़ाइल को बंद करने का प्रबंधन करता है // आपको इसके बारे में चिंता किए बिना। // 3. कोड अपवाद सुरक्षित है। // फंक्शन और क्लीनअप में कहीं भी एक अपवाद फेंका जा सकता है // अभी भी होगा। // सभी मुहावरेदार सी ++ कोड सभी संसाधनों के लिए बड़े पैमाने पर आरएआईआई का उपयोग करता है। // अतिरिक्त उदाहरणों में शामिल हैं // - unique_ptr और shared_ptr . का उपयोग करके मेमोरी // - कंटेनर - मानक पुस्तकालय लिंक्ड सूची, // वेक्टर (यानी स्व-आकार देने वाला सरणी), हैश मैप, और इसी तरह // जब वे दायरे से बाहर हो जाते हैं तो सभी स्वचालित रूप से अपनी सामग्री को नष्ट कर देते हैं। // - लॉक_गार्ड और यूनिक_लॉक का उपयोग करने वाले म्यूटेक्स ///////////////////// // स्मार्ट पॉइंटर ///////////////////// // आम तौर पर एक स्मार्ट पॉइंटर एक ऐसा वर्ग होता है जो "रॉ पॉइंटर" ("नया" का उपयोग) को लपेटता है // क्रमशः सी में मॉलोक / कॉलोक)। लक्ष्य सक्षम होना है // स्पष्ट रूप से हटाने की आवश्यकता के बिना इंगित की जा रही वस्तु के जीवनकाल का प्रबंधन करें // वस्तु। यह शब्द केवल पॉइंटर्स के एक सेट का वर्णन करता है जिसमें // अमूर्त का उल्लेख किया। // स्मार्ट पॉइंटर्स को रोकने के लिए कच्चे पॉइंटर्स पर प्राथमिकता दी जानी चाहिए // जोखिम भरा मेमोरी लीक, जो तब होता है जब आप किसी ऑब्जेक्ट को हटाना भूल जाते हैं। // कच्चे सूचक का उपयोग: Dog* ptr = new Dog(); ptr->bark(); delete ptr; // स्मार्ट पॉइंटर का उपयोग करके, आपको हटाने के बारे में चिंता करने की ज़रूरत नहीं है // अब वस्तु का। // एक स्मार्ट पॉइंटर एक नीति का वर्णन करता है, जिसमें संदर्भों की गणना की जाती है // सूचक। वस्तु नष्ट हो जाती है जब अंतिम // वस्तु का संदर्भ नष्ट हो जाता है। // "std::shared_ptr" का उपयोग: void foo() { // It's no longer necessary to delete the Dog. std::shared_ptr doggo(new Dog()); doggo->bark(); } // संभावित परिपत्र संदर्भों से सावधान रहें !!! // हमेशा एक संदर्भ होगा, इसलिए इसे कभी नष्ट नहीं किया जाएगा! std::shared_ptr doggo_one(new Dog()); std::shared_ptr doggo_two(new Dog()); doggo_one = doggo_two; // p1 references p2 doggo_two = doggo_one; // p2 references p1 // कई प्रकार के स्मार्ट पॉइंटर्स हैं। // उनका उपयोग करने का तरीका हमेशा एक जैसा होता है। // यह हमें इस प्रश्न की ओर ले जाता है: हमें प्रत्येक प्रकार के स्मार्ट पॉइंटर का उपयोग कब करना चाहिए? // std::unique_ptr - इसका उपयोग तब करें जब आप केवल एक संदर्भ रखना चाहते हैं // वस्तु। // std::shared_ptr - इसका उपयोग तब करें जब आप इसके लिए कई संदर्भ रखना चाहते हैं // एक ही वस्तु और यह सुनिश्चित करना चाहते हैं कि इसे हटा दिया गया है // जब सभी संदर्भ चले गए हैं। // std::weak_ptr - जब आप एक्सेस करना चाहते हैं तो इसका इस्तेमाल करें // एक std::shared_ptr की अंतर्निहित वस्तु उस वस्तु को आवंटित किए बिना। // कमजोर पॉइंटर्स का उपयोग सर्कुलर रेफरेंसिंग को रोकने के लिए किया जाता है। ///////////////////// // कंटेनर ///////////////////// // कंटेनर या मानक टेम्पलेट लाइब्रेरी कुछ पूर्वनिर्धारित टेम्पलेट हैं। // वे इसके तत्वों के लिए भंडारण स्थान का प्रबंधन करते हैं और प्रदान करते हैं // सदस्य उन्हें एक्सेस और हेरफेर करने के लिए कार्य करता है। // कुछ कंटेनर इस प्रकार हैं: // वेक्टर (गतिशील सरणी) // हमें रन टाइम पर ऐरे या ऑब्जेक्ट्स की सूची को परिभाषित करने की अनुमति दें #include string val; vector my_vector; // initialize the vector cin >> val; my_vector.push_back(val); // will push the value of 'val' into vector ("array") my_vector my_vector.push_back(val); // will push the value into the vector again (now having two elements) // एक वेक्टर के माध्यम से पुनरावृति करने के लिए हमारे पास 2 विकल्प हैं: // या तो क्लासिक लूपिंग (वेक्टर के माध्यम से इंडेक्स 0 से उसके अंतिम इंडेक्स तक पुनरावृति): for (int i = 0; i < my_vector.size(); i++) { cout << my_vector[i] << endl; // वेक्टर के तत्व तक पहुँचने के लिए हम ऑपरेटर का उपयोग कर सकते हैं [] } // या एक पुनरावर्तक का उपयोग करना: vector::iterator it; // initialize the iterator for vector for (it = my_vector.begin(); it != my_vector.end(); ++it) { cout << *it << endl; } // सेट // सेट कंटेनर हैं जो एक विशिष्ट क्रम के बाद अद्वितीय तत्वों को संग्रहीत करते हैं। // सेट अद्वितीय मूल्यों को क्रमबद्ध क्रम में संग्रहीत करने के लिए एक बहुत ही उपयोगी कंटेनर है // बिना किसी अन्य फ़ंक्शन या कोड के। #include set ST; // Will initialize the set of int data type ST.insert(30); // Will insert the value 30 in set ST ST.insert(10); // Will insert the value 10 in set ST ST.insert(20); // Will insert the value 20 in set ST ST.insert(30); // Will insert the value 30 in set ST // अब सेट के तत्व इस प्रकार हैं // 10 20 30 // किसी तत्व को मिटाने के लिए ST.erase(20); // मान 20 . के साथ तत्व मिटा देगा // एसटी सेट करें: 10 30 // सेट के माध्यम से पुनरावृति करने के लिए हम पुनरावृत्तियों का उपयोग करते हैं set::iterator it; for(it=ST.begin();it!=ST.end();it++) { cout << *it << endl; } // Output: // 10 // 30 // पूरे कंटेनर को साफ करने के लिए हम कंटेनर_नाम.क्लियर () का उपयोग करते हैं ST.clear(); cout << ST.size(); // will print the size of set ST // आउटपुट: 0 // नोट: डुप्लिकेट तत्वों के लिए हम मल्टीसेट का उपयोग कर सकते हैं // नोट: हैश सेट के लिए, unordered_set का उपयोग करें। वे अधिक कुशल हैं लेकिन // आदेश को संरक्षित न करें। unordered_set C++11 के बाद से उपलब्ध है // नक्शा // मैप्स एक प्रमुख मूल्य के संयोजन द्वारा गठित तत्वों को संग्रहीत करता है // और एक विशिष्ट क्रम के बाद एक मैप किया गया मान। #include map mymap; // Will initialize the map with key as char and value as int mymap.insert(pair('A',1)); // Will insert value 1 for key A mymap.insert(pair('Z',26)); // Will insert value 26 for key Z // To iterate map::iterator it; for (it=mymap.begin(); it!=mymap.end(); ++it) std::cout << it->first << "->" << it->second << std::cout; // आउटपुट: // ए-> 1 // जेड-> 26 // कुंजी के अनुरूप मान ज्ञात करने के लिए it = mymap.find('Z'); cout << it->second; // आउटपुट: 26 // नोट: हैश मैप के लिए, unordered_map का उपयोग करें। वे अधिक कुशल हैं लेकिन करते हैं // आदेश को संरक्षित नहीं करें। unordered_map C++11 के बाद से उपलब्ध है। // गैर-आदिम मूल्यों (कस्टम वर्ग) की ऑब्जेक्ट कुंजियों वाले कंटेनरों की आवश्यकता होती है // ऑब्जेक्ट में या फ़ंक्शन पॉइंटर के रूप में फ़ंक्शन की तुलना करें। पुरातन // डिफ़ॉल्ट तुलनित्र हैं, लेकिन आप इसे ओवरराइड कर सकते हैं। class Foo { public: int j; Foo(int a) : j(a) {} }; struct compareFunction { bool operator()(const Foo& a, const Foo& b) const { return a.j < b.j; } }; // इसकी अनुमति नहीं है (हालांकि यह कंपाइलर के आधार पर भिन्न हो सकता है) // एसटीडी :: नक्शा <फू, इंट> फूमैप; std::map fooMap; fooMap[Foo(1)] = 1; fooMap.find(Foo(1)); //true //////////////////////////////////// // लैम्ब्डा एक्सप्रेशन (सी ++ 11 और ऊपर) //////////////////////////////////// // लैम्ब्डा एक अनाम फ़ंक्शन को परिभाषित करने का एक सुविधाजनक तरीका है // वस्तु उस स्थान पर ठीक है जहां इसे लागू किया गया है या पारित किया गया है // किसी फ़ंक्शन के लिए एक तर्क। // उदाहरण के लिए, दूसरे का उपयोग करके जोड़े के वेक्टर को सॉर्ट करने पर विचार करें // जोड़ी का मूल्य vector > tester; tester.push_back(make_pair(3, 6)); tester.push_back(make_pair(1, 9)); tester.push_back(make_pair(5, 0)); // लैम्ब्डा एक्सप्रेशन को सॉर्ट फ़ंक्शन के तीसरे तर्क के रूप में पास करें // सॉर्ट <एल्गोरिदम> हेडर से है sort(tester.begin(), tester.end(), [](const pair& lhs, const pair& rhs) { return lhs.second < rhs.second; }); // लैम्ब्डा एक्सप्रेशन के सिंटैक्स पर ध्यान दें, // [] लैम्ब्डा में चर को "कैप्चर" करने के लिए प्रयोग किया जाता है // "कैप्चर लिस्ट" परिभाषित करती है कि लैम्ब्डा के बाहर से फंक्शन बॉडी के अंदर क्या उपलब्ध होना चाहिए और कैसे। // यह या तो हो सकता है: // 1. एक मान: [x] // 2. एक संदर्भ: [&x] // 3. संदर्भ के अनुसार वर्तमान में कोई भी चर [&] // 4. ३ के समान, लेकिन मूल्य से [=] // उदाहरण: vector dog_ids; // number_of_dogs = 3; for(int i = 0; i < 3; i++) { dog_ids.push_back(i); } int weight[3] = {30, 50, 10}; // मान लें कि आप कुत्तों के वजन के अनुसार dog_ids को सॉर्ट करना चाहते हैं // तो dog_ids अंत में बन जाना चाहिए: [२, ०, १] // यहाँ वह जगह है जहाँ लैम्ब्डा के भाव काम आते हैं sort(dog_ids.begin(), dog_ids.end(), [&weight](const int &lhs, const int &rhs) { return weight[lhs] < weight[rhs]; }); // ध्यान दें कि हमने उपरोक्त उदाहरण में संदर्भ द्वारा "वजन" पर कब्जा कर लिया है। // सी ++ में लैम्ब्डा पर अधिक: https://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11 ///////////////////////////// // रेंज के लिए (सी ++ 11 और ऊपर) ///////////////////////////// // आप एक कंटेनर पर लूप को पुनरावृत्त करने के लिए एक श्रेणी का उपयोग कर सकते हैं int arr[] = {1, 10, 3}; for(int elem: arr){ cout << elem << endl; } // आप "ऑटो" का उपयोग कर सकते हैं और कंटेनर के तत्वों के प्रकार के बारे में चिंता न करें // उदाहरण के लिए: for(auto elem: arr) { // Do something } ///////////////////// // मजेदार चीजें ///////////////////// // सी ++ के पहलू जो नवागंतुकों (और यहां तक कि कुछ दिग्गजों) के लिए आश्चर्यजनक हो सकते हैं। // यह खंड, दुर्भाग्य से, बेतहाशा अधूरा है; सी ++ सबसे आसान में से एक है // भाषाएं जिनके साथ अपने आप को पैर में गोली मारनी है। // आप निजी तरीकों को ओवरराइड कर सकते हैं! class Foo { virtual void bar(); }; class FooSub : public Foo { virtual void bar(); // Overrides Foo::bar! }; // 0 == false == NULL (most of the time)! bool* pt = new bool; *pt = 0; // मान बिंदुओं को 'पीटी' द्वारा गलत पर सेट करता है। pt = 0; // 'पीटी' को अशक्त सूचक पर सेट करता है। दोनों पंक्तियाँ बिना किसी चेतावनी के संकलित हैं। // nullptr उस समस्या में से कुछ को ठीक करने वाला है: int* pt2 = new int; *pt2 = nullptr; // Doesn't compile pt2 = nullptr; // Sets pt2 to null. // बूल के लिए एक अपवाद बनाया गया है। // यह आपको if(!ptr) के साथ नल पॉइंटर्स के लिए परीक्षण करने की अनुमति देता है, // लेकिन परिणामस्वरूप आप सीधे बूल को नलप्टर असाइन कर सकते हैं! *pt = nullptr; // This still compiles, even though '*pt' is a bool! // '=' != '=' != '='! // कॉल फू :: फू (कॉन्स्ट फू एंड) या कुछ प्रकार (मूव शब्दार्थ देखें) कॉपी // कंस्ट्रक्टर। Foo f2; Foo f1 = f2; // कॉल फू :: फू (कॉन्स्ट फू एंड) या संस्करण, लेकिन केवल 'फू' भाग की प्रतिलिपि बनाता है // 'फूसब'। 'fooSub' के किसी भी अतिरिक्त सदस्य को छोड़ दिया जाता है। यह कभी कभी // भयानक व्यवहार को "ऑब्जेक्ट स्लाइसिंग" कहा जाता है। FooSub fooSub; Foo f1 = fooSub; // Calls Foo::operator=(Foo&) or variant. Foo f1; f1 = f2; //////////////////////////////////// // टुपल्स (सी ++ 11 और ऊपर) //////////////////////////////////// #include // वैचारिक रूप से, टुपल्स पुराने डेटा संरचनाओं (सी-जैसी संरचना) के समान हैं // लेकिन डेटा सदस्यों को नामित करने के बजाय, // इसके तत्वों को टपल में उनके क्रम द्वारा एक्सेस किया जाता है। // हम एक टपल के निर्माण के साथ शुरू करते हैं। // मूल्यों को टपल में पैक करें auto first = make_tuple(10, 'A'); const int maxN = 1e9; const int maxL = 15; auto second = make_tuple(maxN, maxL); // Printing elements of 'first' tuple cout << get<0>(first) << " " << get<1>(first) << '\n'; //prints : 10 A // Printing elements of 'second' tuple cout << get<0>(second) << " " << get<1>(second) << '\n'; // prints: 1000000000 15 // टपल को वेरिएबल में अनपैक करना int first_int; char first_char; tie(first_int, first_char) = first; cout << first_int << " " << first_char << '\n'; // prints : 10 A // हम इस तरह टपल भी बना सकते हैं। tuple third(11, 'A', 3.14141); // tuple_size टपल में तत्वों की संख्या लौटाता है (एक कॉन्स्टेक्स के रूप में) cout << tuple_size::value << '\n'; // prints: 3 // tuple_cat सभी टुपल्स के तत्वों को एक ही क्रम में संयोजित करता है। auto concatenated_tuple = tuple_cat(first, second, third); // concatenated_tuple बन जाता है = (10, 'ए', 1e9, 15, 11, 'ए', 3.14141) cout << get<0>(concatenated_tuple) << '\n'; // prints: 10 cout << get<3>(concatenated_tuple) << '\n'; // prints: 15 cout << get<5>(concatenated_tuple) << '\n'; // prints: 'A' ///////////////////////////////// // लॉजिकल और बिटवाइज ऑपरेटर्स //////////////////////////////// // सी ++ में अधिकांश ऑपरेटर अन्य भाषाओं की तरह ही हैं // लॉजिकल ऑपरेटर्स // सी ++ बूलियन अभिव्यक्तियों के लिए शॉर्ट-सर्किट मूल्यांकन का उपयोग करता है, यानी, दूसरा तर्क निष्पादित किया जाता है या // केवल तभी मूल्यांकन किया जाता है जब पहला तर्क अभिव्यक्ति के मूल्य को निर्धारित करने के लिए पर्याप्त नहीं है true && false // निष्पादित करता है **तार्किक और** असत्य उत्पन्न करने के लिए true || false // सत्य उत्पन्न करने के लिए **तार्किक या** करता है ! true // प्रदर्शन करता है **तार्किक नहीं** झूठा उत्पन्न करने के लिए // प्रतीकों का उपयोग करने के बजाय समकक्ष कीवर्ड का उपयोग किया जा सकता है true and false // प्रदर्शन करता है **तार्किक और ** गलत उत्पन्न करने के लिए true or false // सत्य उत्पन्न करने के लिए **तार्किक या ** करता है not true // निष्पादित करता है **तार्किक नहीं ** असत्य उत्पन्न करने के लिए // बिटवाइज ऑपरेटर्स // **<<** लेफ्ट शिफ्ट ऑपरेटर // << बिट्स को बाईं ओर शिफ्ट करता है 4 << 1 // 8 देने के लिए 4 के बिट्स को 1 से बायीं ओर शिफ्ट करता है // x << n को x * 2^n . के रूप में माना जा सकता है // **>>** राइट शिफ्ट ऑपरेटर // >> बिट्स को दाईं ओर शिफ्ट करता है 4 >> 1 // २ देने के लिए ४ के बिट्स को १ से दायीं ओर शिफ्ट करता है // x >> n को x / 2^n . के रूप में माना जा सकता है ~4 // Performs a bitwise not 4 | 3 // Performs bitwise or 4 & 3 // Performs bitwise and 4 ^ 3 // Performs bitwise xor // समतुल्य कीवर्ड हैं compl 4 // Performs a bitwise not 4 bitor 3 // Performs bitwise or 4 bitand 3 // Performs bitwise and 4 xor 3 // Performs bitwise xor ``` अग्रिम पठन: * एक अप-टू-डेट भाषा संदर्भ [सीपीपी संदर्भ](http://cppreference.com/w/cpp) पर पाया जा सकता है। * अतिरिक्त संसाधन [CPlusPlus](http://cplusplus.com) पर मिल सकते हैं। * [TheChernoProject - C++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb) पर भाषा की बुनियादी बातों और कोडिंग परिवेश को सेट करने वाला एक ट्यूटोरियल उपलब्ध है। ================================================ FILE: hi/d.md ================================================ --- contributors: - ["Nick Papanastasiou", "www.nickpapanastasiou.github.io"] --- ```d //क्या आ रहा है पता है ... module hello; import std.stdio; void main(string[] args) { writeln("Hello, World!"); } ``` अगर आप मेरे जैसे हैं और इंटरनेट पर समय बहुत अधिक समय खर्च करते हैं, तो आप बाधाओं के बारे में सुना है के बारे में [डी](http://dlang.org/)। डी प्रोग्रामिंग भाषा में एक आधुनिक, सामान्य प्रयोजन है , सब कुछ के लिए समर्थन कम स्तर की सुविधाओं से करने के साथ बहु - प्रतिमान भाषा अर्थपूर्ण उच्च स्तरीय चीजें । D सक्रिय रूप से सुपर स्मार्ट लोगों का एक बड़ा समूह द्वारा विकसित की है और नेतृत्व द्वारा किया जाता है [वाल्टर ब्राइट](https://en.wikipedia.org/wiki/Walter_Bright) और [आंद्रेई Alexandrescu](https://en.wikipedia.org/wiki/Andrei_Alexandrescu)। जिस तरह की है कि सभी के साथ बाहर, चलो कुछ उदाहरणों पर गौर करते हैं! ```d import std.stdio; void main() { for(int i = 0; i < 10000; i++) { writeln(i); } // 'auto' can be used for inferring types. auto n = 1; // संख्यात्मक literals स्पष्टता के लिए एक अंकों विभाजक के रूप में '_' का उपयोग कर सकते हैं। while(n < 10_000) { n += n; } do { n -= (n / 2); } while(n > 0); // लिए और जब तक अच्छा कर रहे हैं, लेकिन D में हम 'foreach' छोरों पसंद करते हैं। // '..' पहला मान सहित एक सतत श्रृंखला बनाता है, // लेकिन पिछले छोड़कर। foreach(i; 1..1_000_000) { if(n % 2 == 0) writeln(i); } // वहाँ भी 'foreach_reverse' आप पीछे की ओर पाश करना चाहते हैं। foreach_reverse(i; 1..int.max) { if(n % 2 == 1) { writeln(i); } else { writeln("No!"); } } } ``` हम `struct`, `class`, `union`, और `enum` साथ नए प्रकार परिभाषित कर सकते हैं। Structs और unions मूल्य से कार्य करने के लिए पारित कर रहे हैं (यानी नकल) और वर्गों के संदर्भ द्वारा पारित कर रहे हैं। इसके अलावा, हम प्रकारों और मानों दोनों पर करने के लिए टेम्पलेट का उपयोग कर सकते हैं! ```d // इधर, 'T' एक प्रकार पैरामीटर है। लगता है कि '<+T>' C++ / C/ Java से। struct LinkedList(T) { T data = null; // '!'का प्रयोग करें , एक पैरामिट्रीकृत प्रकार इन्स्तांत । फिर, '' लगता है। LinkedList!(T)* next; } class BinTree(T) { T data = null; // केवल एक टेम्पलेट पैरामीटर नहीं है, तो , हम कोष्ठकों छोड़ सकते हैं। BinTree!T left; BinTree!T right; } enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, } // उपयोग उर्फ प्रकार (alias) के लिए संक्षिप्त बनाने के लिए। alias IntList = LinkedList!int; alias NumTree = BinTree!double; //हम के रूप में अच्छी तरह से कार्य टेम्पलेट्स बना सकते हैं! T max(T)(T a, T b) { if(a < b) return b; return a; } // संदर्भ द्वारा पारित सुनिश्चित करने के लिए रेफरी कीवर्ड का प्रयोग करें । यही कारण है कि यहां तक कि 'A' और 'B' , तो है //मान प्रकार वे हमेशा ' swap()' के संदर्भ द्वारा पारित हो जाएगा हैं । void swap(T)(ref T a, ref T b) { auto temp = a; a = b; b = temp; } // टेम्पलेट्स के साथ, हम भी मूल्यों पर परमेटेराइज़ कर सकते हैं , न सिर्फ types.With टेम्पलेट्स, हम भी नहीं है, बस प्रकार , मूल्यों पर parameterize कर सकते हैं। class Matrix(uint m, uint n, T = int) { T[m] rows; T[n] columns; } auto mat = new Matrix!(3, 3); ``` Classes की बात हो रही है , एक दूसरे के लिए गुणों के बारे में बात करते हैं। एक संपत्ति एक value की तरह कार्य कर सकते हैं कि एक समारोह में मोटे तौर पर है, इसलिए हम कर सकते हैं के शब्दों के साथ पॉड संरचनाओं की वाक्य रचना (`structure.x = 7`) है मनुष्य और सेटर तरीकों (`object.setX(7)`) ! ```d // Consider a class parameterized on types 'T' & 'U'. class MyClass(T, U) { T _data; U _other; } // And "getter" and "setter" methods like so: class MyClass(T, U) { T _data; U _other; // भवन निर्माताओं हमेशा नामित कर रहे हैं 'this'. this(T t, U u) { //यह नीचे सेटर तरीकों से मुलाकात करेंगे। data = t; other = u; } // getters @property T data() { return _data; } @property U other() { return _other; } // setters @property void data(T t) { _data = t; } @property void other(U u) { _other = u; } } //और हम इस तरह से उन का उपयोग करें : void main() { auto mc = new MyClass!(int, string)(7, "seven"); // करने के लिए लिखने के लिए मानक पुस्तकालय से // आयात ' stdio ' मॉड्यूल // सांत्वना (आयात एक गुंजाइश के लिए स्थानीय हो सकता है) । import std.stdio; // Call the getters to fetch the values. writefln("Earlier: data = %d, str = %s", mc.data, mc.other); // Call the setters to assign new values. mc.data = 8; mc.other = "eight"; // Call the getters again to fetch the new values. writefln("Later: data = %d, str = %s", mc.data, mc.other); } ``` गुणों के साथ, हम तर्क की किसी भी राशि को जोड़ सकते हैं हमारे मनुष्य और सेटर तरीकों, और की साफ वाक्य रचना रखना सीधे सदस्यों तक पहुँचने ! हमारे निपटान पर अन्य वस्तु उन्मुख उपहार `interface`s , `सार class`es शामिल और `तरीकों override`ing । डी सिर्फ जावा की तरह विरासत करता है: आप कृपया के रूप में कई इंटरफेस को लागू करने, एक वर्ग का विस्तार । हम डी एस OOP सुविधाओं देखा , लेकिन स्विच गियर छोड़ दिया । डी प्रस्तावों प्रथम श्रेणी के कार्यों के साथ कार्यात्मक प्रोग्रामिंग, `pure` काम करता है, और अपरिवर्तनीय डेटा । इसके अलावा, अपने पसंदीदा के सभी कार्यात्मक एल्गोरिदम ( नक्शा, फिल्टर , कम करने और मित्र हो सकते हैं) अद्भुत `std.algorithm` मॉड्यूल में पाया! ```d import std.algorithm : map, filter, reduce; import std.range : iota; // builds an end-exclusive range void main() { // हम भी ints के वर्गों की एक सूची का योग मुद्रित करना चाहते हैं // 1 से 100 के लिए आसान करने के लिए! // बस टेम्पलेट पैरामीटर के रूप में लैम्ब्डा भाव के पास! // आप आप की तरह किसी भी पुराने समारोह पारित कर सकते हैं , लेकिन lambdas यहाँ सुविधाजनक हैं। auto num = iota(1, 101).filter!(x => x % 2 == 0) .map!(y => y ^^ 2) .reduce!((a, b) => a + b); writeln(num); } ``` हम NUM गणना करने के लिए एक अच्छा Haskellian पाइपलाइन का निर्माण करने के लिए मिला सूचना कैसे ? यही कारण है कि एक डी नवाचार करने के लिए धन्यवाद वर्दी समारोह कॉल सिंटेक्स के रूप में जानते हैं। UFCS के साथ, हम एक विधि के रूप में एक समारोह कॉल लिखने के लिए चुन सकते हैं या मुफ्त समारोह कॉल ! वाल्टर इस पर एक अच्छा लेख लिखा था [यहाँ ।](http://www.drdobbs.com/cpp/uniform-function-call-syntax/232700394) संक्षेप में, आप जिनकी पहली पैरामीटर कार्यों कॉल कर सकते हैं एक विधि के रूप में ग्रुप ए की किसी भी अभिव्यक्ति पर कुछ प्रकार एक की है । मैं समानता चाहते । समानता की तरह कोई और? ज़रूर तुम करना। चलो कुछ करते हैं! ```d import std.stdio; import std.parallelism : parallel; import std.math : sqrt; void main() { // हम हमारे सरणी में वर्गमूल हर नंबर ले जाना चाहता हूँ , // हम उपलब्ध है के रूप में और के रूप में कई कोर का लाभ ले। auto arr = new double[1_000_000]; // संदर्भ के द्वारा एक सूचकांक , और एक सरणी तत्व का प्रयोग // और सिर्फ सरणी पर समानांतर फोन! foreach(i, ref elem; parallel(arr)) { ref = sqrt(i + 1.0); } } ``` ================================================ FILE: hi/json.md ================================================ --- contributors: - ["Anna Harren", "https://github.com/iirelu"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["himanshu", "https://github.com/himanshu81494"] - ["Michael Neth", "https://github.com/infernocloud"] - ["Athanasios Emmanouilidis", "https://github.com/athanasiosem"] translators: - ["Namami Shanker", "https://github.com/NamamiShanker"] --- जैसन(JSON) इस अत्यंत सरल डाटा-इंटरचेंज फॉर्मेट है| जैसा [json.org](https://json.org) कहती है, ये इंसानो के पढ़ने और लिखने के लिए भी आसान है और और मशीन के लिए इसे पार्स और उतपन्न करना भी बेहद सरल है| जैसन(JSON) के एक अंश को इनमे से किसी एक का प्रतिनिधित्व(represent) करना चाहिए: * एक नाम/वैल्यू जोड़े का कलेक्शन (`{ }`). कई दूसरी भाषाओ में इसे ऑब्जेक्ट, रिकॉर्ड, स्ट्रक्ट, डिक्शनरी, हैश टेबल, कीड लिस्ट, या असोसिएटिव ऐरे का भी नाम दिया जाता है| * वैल्यूज की एक व्यवस्थित लिस्ट(ordered list) (`[ ]`). कई दूसरी भाषाओ में इसे ऐरे, वेक्टर, लिस्ट, या सीक्वेंस भी कहा जाता है| जैसन(JSON) अपने शुद्धतम रूप में कमैंट्स सपोर्ट नहीं करता है, पर ज़्यादातर पारसर C स्टाइल की कमैंट्स (`//`, `/* */`) सपोर्ट करेंगे| कुछ पारसर्स अंतिम कॉमा भी स्वीकार करते हैं (जब आप किसी ऐरे के अंतिम एलिमेंट या किसी ऑब्जेक्ट की अंतिम प्रॉपर्टी के बार एक कॉमा छोड़ देते हैं), पर ऐसी गलतियों से बचना चाहिए बेहतर कम्पेटिबिलिटी के लिए| ये उदाहरण १०० प्रतिशत मान्य जैसन(JSON) है| किस्मत से, जैसन(JSON) डॉक्यूमेंट को पढ़ के ही आप इसे समझ जायेंगे| समर्थित डाटा टाइप्स: * स्ट्रिंग्स(Strings): `"नमस्ते"`, `"\"एक उद्धरण\""`, `"\u0abe"`, `"नयी पंक्ति|\n"` * अंक(Numbers): `23`, `0.11`, `12e10`, `3.141e-10`, `1.23e+4` * ऑब्जेक्ट्स(Objects): `{ "की": "मूल्य" }` * ऐरे(Arrays): `["बहुत सारे मूल्य"]` * विविध(Miscellaneous): `true`, `false`, `null` ```json { "की": "मूल्य", "की": "हमेशा दोहरे उद्धरण चिह्नों में संलग्न होना चाहिए", "अंक": 0, "स्ट्रिंग्स": "नमस्ते| यूनिकोड और \"एस्केप\" सीक्वेंस की अनुमति है|", "बूलियन है?": true, "शून्यता ": null, "बड़े अंक": 1.2e+100, "ऑब्जेक्ट्स": { "टिप्पणी": "आपके जैसन(JSON) ऑब्जेक्ट को ज़्यादातर ऑब्जेक्ट से ही ढांचा मिलेगा|", "ऐरे": [0, 1, 2, 3, "ऐरे में आप कुछ भी रख सकते हैं|", 5], "एक और ऑब्जेक्ट": { "टिप्पणी": "आप एक ऑब्जेक्ट दूसरे ऑब्जेक्ट के अंदर रख सकते हैं| ये बहुत उपयोगी होता है|" } }, "फ़र्ज़ी": [ { "पोटेशियम के स्रोत": ["केला"] }, [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, "नव"], [0, 0, 0, 1] ] ], "वैकल्पिक शैली": { "टिप्पणी": "ये देखिये!" , "कॉमा के स्थान": "से फरक नहीं पड़ता, अगर आपने उसे अगली की से पहले लगाया है तो वो मान्य है|" , "एक और टिप्पणी": "कितनी अच्छी बात है" }, "खाली स्थान": "से फरक नहीं पड़ता", "ये काफी छोटा था :>": "और ख़तम| अब आपको जैसन(JSON) के बारे में सब कुछ पता है|" } ``` ## और जानकारी के लिए * [JSON.org](https://json.org) पूरा जैसन(JSON) फ्लोचार्ट के माध्यम से खूबसूरत तरह से दर्शित| * [JSON Tutorial](https://www.youtube.com/watch?v=wI1CWzNtE-M) जैसन(JSON) का एक संक्षिप्त परिचय| ================================================ FILE: hjson.md ================================================ --- name: Hjson filename: learnhjson.hjson contributors: - ["MrTeferi", "https://github.com/MrTeferi"] --- Hjson is an attempt to make [JSON](../json/) more human readable. Hjson is a syntax extension to JSON. It's NOT a proposal to replace JSON or to incorporate it into the JSON spec itself. It's intended to be used like a user interface for humans, to read and edit before passing the JSON data to the machine. Let's take a look at examples to see the key syntax differences! ``` { # Comments are totally supported! // With forward slashes too! /* Even block style comments, neat! /* # Strings do not require quotes! # Just keep it to a single line human: readable quotes: "are fine too" # Notice that commas are also not required! # If using commas, strings DO require quotes! object: { name: Hjson properties: [ readable exciting fun ] with_commas: [ "quoted", "quoty", "quote" ] details: ["this", "is", "fine", "too"] } # Multiline quotes with proper whitespace handling are supported! diary: ''' I wish JSON was more human readable. If only there was a JSON for my needs! Oh wait.. there is! It's called Hjson. ''' # Backslashes are interpreted as an escape character ONLY in quoted strings slash: This will not have a new line\n slash-quoted: "This will definitely have a new line\n" # Make sure to use quotes when mixing whitespace with important punctuation example1: "If, you're, going, to, comma in a string, use, quotes!" example2: "Also if you want to use {} or [] or any JSON relevant punctuation!" example3: [because, this, is, totally, BROKEN!] example4: this is technically OK though: {}[],: # Enjoy working with Hjson! party-time: { Hjson-lovers: [ me my mom "my dad" ] Hjson-power-level: 9000 supported: { python: yes java: yes javascript: yes c++: yes Go: yes C#: yes Rust: yes } partial-support: ["C", "Kotlin", "Ruby", "Rust"] } } ``` ## Further Reading * [Hjson.github.io](https://hjson.github.io/) Main Hjson site including editor support, how-to, etc. * [Hjson Packages](https://github.com/hjson/) Various Hjson packages for different applications. ================================================ FILE: hocon.md ================================================ --- name: HOCON filename: learnhocon.conf contributors: - [TehBrian, 'https://tehbrian.xyz'] --- Human-Optimized Configuration Object Notation, or HOCON, is a configuration and data serialization format designed to be easily editable by humans. It's a superset of JSON, meaning that any valid JSON is valid HOCON, but it differs in being less opinionated. With its flexible yet determinable syntax, resulting configuration files are often less noisy than with other formats. Additionally, its support for comments makes it better-suited for user-facing configuration than JSON. ``` // Anything after // or # is a comment. This is a comment. # This is also a comment. ################## ### THE BASICS ### ################## # Everything in HOCON is either a key, a value, or a separator. # : and = are separators. They separate the key from the value. key: value another_key = another_value # You can use either separator with or without whitespace on either side. colon1:value colon2: value colon3 : value equals1=value equals2= value equals3 = value # As you'll see, HOCON has a very nonrestrictive syntax. # HOCON isn't opinionated on how keys look. THIS_IS_A_VALID_KEY: value this-is-also-a-valid-key: value keys can have spaces: value or even numbers like 12345: value "you can even quote keys if you'd like!": value # Keys are case sensitive. unique: value 1 UnIqUe: value 3 UNIQUE: value 2 # A key, followed by any separator, followed by a value, is called a field. this_entire_line_is: a field ################### ### VALUE TYPES ### ################### # A value can be of type: string, number, object, array, boolean, null. # Simple values are values of any type except array and object. ## SIMPLE VALUES ## quoted_string: "I like quoting my strings." unquoted_string: I don't like quoting my strings. # Special characters that cannot be used in unquoted strings are: # $ " { } [ ] : = , + # ` ^ ? ! @ * & # Unquoted strings do not support any kind of escaping. # To use one of those special characters in a string, use a quoted string. multiline_string: """This entire thing is a string! One giant, multiline string. You can put 'single' and "double" quotes without it being invalid.""" number: 123 negative: -123 fraction: 3.1415926536 scientific_notation: 1.2e6 // 1.2 * 10^6 boolean: true # or false empty: null ## ARRAYS ## # Arrays hold lists of values. # Values in arrays can be separated with commas.. array: [ 1, 2, 3, 4, 5 ] fibonacci: [1,1,2,3,5,8,13] multiples_of_5: [5, 10, 15, 20,] # Notice the trailing comma. That's allowed. # or newlines.. friends: [ "Brian" "Sophie" "Maya" "Sabina" ] # or both! ingredients: [ "Egg", "Sugar", "Oil", "Flour", # Trailing comma. That's allowed here too. ] # Once again, HOCON has a very liberal syntax. Use whichever style you prefer. no newline before or after bracket: ["This" "is" "an" "array!"] # Arrays can hold other arrays. array in array: [ [1, 2, 3], ["a", "b", "c"] ] array in array in array: [ [ [1, 2], [8, 9] ], [ ["a", "b" ], ["y", "z"] ] ] ## OBJECTS ## # Objects hold fields. # Just like arrays, fields in objects can be separated with commas.. object: { key: value, another_key: another_value } server_connection: {ip: "127.0.0.1", port: 80} first: {letter: a, number: 1,} # Trailing comma. # or newlines.. power_grid: { max_capacity: 15000 current_power: 1200 } # or both! food_colors: { carrot: orange, pear: green, apple: red, plum: purple, banana: yellow, # Trailing comma. These pesky things show up everywhere! } # Arrays can hold objects. coworkers: [ { name: Jeff age: 27 }, { name: Henry age: 35 }, { name: Timmy age: 12 } ] # The field separator may be omitted if the key is followed by { no_separator { key: value speed_of_light: very fast ten: 10 # Objects can hold other objects. another_object { twenty: 20 speed_of_sound: also pretty fast } } # In fact, the entirety of any HOCON document is an actually just an object. # That object is called the root object. The only difference between it and any # other object is that the curly brackets at the top and bottom of the document # may be omitted. # This means that HOCON documents can be formatted in the same way that # regular objects can be formatted, including separating fields with commas # rather than with newlines. # Additionally, while the entirety of a HOCON document can be and is usually an # object, it can also be an array. If it is an array, the opening and closing # brackets at the top and bottom of the document must be explicitly written. ###################### ### DUPLICATE KEYS ### ###################### is_happy: false # If there is a duplicate key, the new value overrides the previous value. is_happy: true online_users: [Jacob, Mike] # Same with arrays. online_users: [Jacob, Mike, Henry] # For objects, it's a bit different. my_car: { color: blue speed: 9001 passengers: null engine: { running: true temperature: 137 } } # If there is a duplicate key and both values are objects, # then the objects are merged. my_car: { // These fields are added to the old, previous object. nickname: "My Favorite Car" type: 2-door sedan // Since the value of this duplicate key is NOT an object, // it simply overrides the previous value. speed: 60 // Same with arrays. They override, not merge. passengers: ["Nate", "Ty"] // This object is recursively merged with the other object. engine: { // These two fields are added to the previous object. type: gas oil_level: 10 // This field overrides the previous value. temperature: 179 } } # Object merging is done two at a time. That is to say, the first two objects # merge into one, then that object merges with the next object, and so on. # Because of this, if you set a field with an object value to a non-object value # and then back to an object value, the new object will completely override any # previous value. // Null, a non-object value, overrides the object. my_car: null // Then, this object overrides null. my_car: { nickname: "My New Car" type: 4-door minivan color: gray speed: 90 passengers: ["Ayden", "Liz"] } ########################### ### VALUE CONCATENATION ### ########################### ## SIMPLE VALUE CONCATENATION ## # Simple values (all value types except array and object) separated by # whitespace are concatenated into a single string. The whitespace between # values is preserved. number_concat: 1 2 3 12.5 -3 2e5 // "1 2 3 12.5 -3 2e5" boolean_concat: true false true // "true false true" null_concat: null null null // "null null null" mixed_concat: 1 true null // "1 true null" # String value concatenation can appear anywhere that a quoted string can. number_concat_in_array: [1 2, 3 4, 5 6] // ["1 2", "3 4", "5 6"] # In fact, unquoted strings are actually just string value concatenations. unquoted_string_concat: his name is jeff // "his name is jeff" # Going further, even keys that are unquoted strings are actually just string # value concatenations. this is a key: value // the KEY is: "this is a key" # The following field is identical to the field above. "this is a key": value # Quoted strings can also be concatenated. # This will be useful later, when we cover substitutions. quoted_string_concat: "her"" name" "is ""jenna" // "her name is jenna" # Notice that the whitespace (or lack thereof) between values is preserved. ## ARRAY CONCATENATION ## # Arrays separated by whitespace are merged into a single array. array_concat: [1, 2, 3] [4, 5, 6] // [1, 2, 3, 4, 5, 6] # Arrays cannot be concatenated with a non-array value. //array_concat: true [false] // error! //array_concat: 1 [2] // error! ## OBJECT CONCATENATION ## # Objects separated by whitespace are merged into a single object. # The merge functionality is identical to that of duplicate key object merging. lamp: {on: true} {color: tan} // {on: true, color: tan} # Similarly to arrays, objects cannot be concatenated with a non-object value. //object_concat: true {on: false} // error! //object_concat: 1 {number: 2} // error! ######################## ### PATH EXPRESSIONS ### ######################## # Path expressions are used to write out a path through the object graph. # Think of it as navigating through objects to a specific field. # Each object to traverse through is called an element, and each element is # separated with a period. country: { city: { neighborhood: { house: { name: "My House" address: 123 Example Dr. } } } } # The path to the address could be written as: # country.city.neighborhood.house.address # Country, city, neighborhood, house, and address are all elements. # Path expressions are used in two places: substitutions (which we'll get to # in just a moment), and as keys. That's right: keys can be path expressions. foo: { bar: { baz: { number: 12 } } } # Rather than tediously specifying each object, a path expression could be used. # The following field represents the same object. foo.bar.baz.number: 12 # Fields and objects specified with path expressions are merged in the same way # that any object is usually merged. foo.bar.baz.bool: true // the object foo's value is: foo { bar { baz { number: 12, bool: true } } } ##################### ### SUBSTITUTIONS ### ##################### # Substitutions refer to a specific value from some path expression. # They're only allowed in values, not in keys or nested in other substitutions. me: { favorite_animal: parrots favorite_food: cookies } # There are two syntaxes for substitutions: # ${path_expression} and ${?path_expression}. # The latter syntax will be covered in a moment. my_fav_animal: ${me.favorite_animal} my_fav_food: ${me.favorite_food} # Substitutions are not parsed inside quoted strings. To get around this, # either use an unquoted string or value concatenation. animal_announcement: My favorite animal is ${my_fav_animal} // "My favorite animal is parrots" food_announcement: "My favorite food is "${my_fav_food}"!" // "My favorite food is cookies!" # Substitutions are parsed last in the document. Because of this, you can # reference a key that hasn't been defined yet. color_announcement: "My favorite color is" ${my_fav_color}"!" // "My favorite color is blue!" my_fav_color: blue # Another effect of substitutions being parsed last is that substitutions will # always use the latest, as in last, value assigned in the entire document. color: green their_favorite_color: ${color} // orange color: orange # This includes merged objects. random_object: { number: 12 } the_number: ${random_object.number} // 15 random_object: { number: 15 } ############################### ### UNDEFINED SUBSTITUTIONS ### ############################### # A substitution using the ${path_expression} syntax with an undefined path # expression, meaning a path expression that does not point to a defined value, # is invalid and will therefore generate an error. //${does.not.exist} // error! # However, an undefined substitution using the ${?path_expression} syntax # has different behavior depending on what it is the value of. request: { # If it is the value of a field, then the field won't be created. response: ${?does.not.exist} // this field does not exist type: HTTP } request: { # Additionally, if it would have overridden a previous value, then the # previous value remains unchanged. type: ${?does.not.exist} // request.type is still HTTP } # If it is a value in an array, then it is simply not added. values: [ 172, "Brian", ${?does.not.exist}, null, true, ] // [ 172, "Brian", null, true ] # If it is part of simple value concatenation, it acts as an empty string. final_string: "String One"${?does.not.exist}"String Two" // "String OneString Two" # If it is part of array concatenation, it acts as an empty array. final_array: [ 1, 2, 3 ] ${?does.not.exist} [ 7, 8, 9 ] // [ 1, 2, 3, 7, 8, 9 ] # If it is part of object concatenation, it acts as an empty object. final_object: { a: 1 } ${?does.not.exist} { c: 3 } // { a: 1, c: 3 } ###################################### ### SELF-REFERENTIAL SUBSTITUTIONS ### ###################################### # Substitutions normally "look forward" and use the final value defined in the # document. However, in cases when this would create a cycle, the substitution # looks only backwards. # A field that contains a substitution that points to itself or points to # other fields that eventually point back to itself is called a # self-referential field. letters: "a b c" // "a b c" letters: ${letters}" d" // "a b c d" letters: ${letters}" e" // "a b c d e" PATH: [/bin] // [/bin] PATH: ${PATH} [/usr/bin] // [/bin, /usr/bin] PATH: ${PATH} [/usr/local/bin] // [/bin, /usr/bin, /usr/local/bin] x: "x" // "x" y: ${x}"y" // "xy" x: ${y}"z" // "xyz" ########################## ### += FIELD SEPARATOR ### ########################## # In addition to : and =, there actually exists another separator: += # A field separated with += implies self-referential array concatenation. # Essentially, it appends an element to a previously defined array. a: [1] b: [1] # These two fields are equivalent. a += 2 // [1, 2] b: ${?b} [2] // [1, 2] USERS: [/usr/luke] // [/usr/luke] USERS += /usr/devon // [/usr/luke, /usr/devon] USERS += /usr/michael // [/usr/luke, /usr/devon, /usr/michael] # Since += only appends elements to a previously existing array, if the previous # value was not an array, an error will be generated. OTHER_USERS: /usr/luke //OTHER_USERS += /usr/devon // error! # The underlying substitution syntax used is ${?path}, not ${path}. # Recall that, using the ${?} syntax, an undefined substitution in array # concatenation acts as an empty array. Because of this, it is perfectly # acceptable if the field that is being set is initially undefined. //z: [] // not necessary z += 3 // [3] z += 4 // [3, 4] NEW_USERS += /usr/sandra // [/usr/sandra] NEW_USERS += /usr/kennedy // [/usr/sandra, /usr/kennedy] NEW_USERS += /usr/robin // [/usr/sandra, /usr/kennedy, /usr/robin] ################ ### INCLUDES ### ################ # Includes allow you to "import" one HOCON document into another. # An include statement consists of the unquoted string "include" followed by # whitespace and then a resource name, which is one of the following: # - a single quoted string which is heuristically interpreted as a URL, # filename, or a Java classpath resource. # - url(), file(), or classpath(), with the parentheses surrounding a quoted # string which is either a URL, filename, or classpath resource respectively. # - required(), with the parentheses surrounding one of the above. include "https://example.com/config.conf" include "/foo/bar/config.conf" include "config.conf" include url("https://example.com/config.conf") include file("/foo/bar/config.conf") include classpath("config.conf") # If the included file does not exist, it will be silently ignored and act as if # it were an empty object. However, if it is wrapped around required(), then # parsing will explicitly error if the file cannot be resolved. //include required("doesnt_exist.conf") // error! //include required(url("https://example.com/doesnt_exist.conf")) // error! //include required(file("doesnt_exist.conf")) // error! //include required(classpath("doesnt_exist.conf")) // error! # The file specified by the include statement is called the included file. # The file containing the include statement is called the including file. # Including a file functions as if you directly replaced the include statement, # wherever it may be, with the contents of the included file's root object. # An included file must have an object as its root value and not an array. # If the included file has an array as its root value, then it is invalid and # an error will be generated. # Pretend that the following is in a file called user_config.conf: username: RandomUser1337 auto_login: true color_theme: dark screensaver: { image: usr/images/screensaver.jpg turn_on_after: 1m } # Then, we include that file. include file("user_config.conf") # We can now reference values from that file! path_to_user_screensaver: ${screensaver.image} // "usr/images/screensaver.jpg" greeting: "Welcome, "${username}"!" // "Welcome, RandomUser1337!" # Duplicate keys override as they normally do. status: "Auto Login: "${auto_login} // "Auto Login: true" auto_login: false status: "Auto Login: "${auto_login} // "Auto Login: false" # Object merging is the same as usual. screensaver: { // This gets added to the screensaver object. enable_during_day: false // This overrides the previous value. turn_on_after: 30s } # Include statements can appear in place of a field. Anywhere that a field # could appear, an include statement could appear as well. # Pretend that the following is in a file called server_settings.conf: max_connections: 10 url: example.com port: 80 admin_page: { username: admin password: pass12345 } # Then, we include that file nested inside an object. websites: { my_epic_website: { include file("server_settings.conf") } } # Now, we can reference the contents of server_settings.conf as if they # had been written directly into the object my_epic_website. server_port: ${websites.my_epic_website.port} the_password: "The password is: "${websites.my_epic_website.admin_page.password} // "The password is: pass12345" max_conn: "Max Connections: "${websites.my_epic_website.max_connections} // "Max Connections: 10" ``` ### More Resources + [Official HOCON Specification](https://github.com/lightbend/config/blob/master/HOCON.md) + [HOCON Playground](https://hocon-playground.tehbrian.dev) ================================================ FILE: hq9+.md ================================================ --- name: HQ9+ filename: hq9+.txt contributors: - ["Alexey Nazaroff", "https://github.com/rogaven"] --- HQ9+ is a joke programming language created by Cliff Biffle. It has only four commands and it isn't Turing-complete. ``` There is only 4 commands, represented by next characters H: print "Hello, world!" Q: print the program's source code (a Quine) 9: print the lyrics to "99 Bottles of Beer" +: add one to the accumulator (the value of the accumulator cannot be accessed) Any other character is ignored. Ok. Let's write some program: HQ9 Result: Hello world! HQ9 HQ9+ is very simple, but allows you to do some things that are very difficult in other languages. For example, here is a program that creates three copies of itself on the screen: QQQ This produces: QQQ QQQ QQQ ``` And that's all. There are a lot of interpreters for HQ9+. Below you can find one of them + [One of online interpreters](https://almnet.de/esolang/hq9plus.php) + [HQ9+ official website](http://cliffle.com/esoterica/hq9plus.html) ================================================ FILE: hre.csv ================================================ Ix,Dynasty,Name,Birth,Death,Coronation 1,Coronation 2,Ceased to be Emperor N/A,Carolingian,Charles I,2 April 742,28 January 814,25 December 800,N/A,28 January 814 N/A,Carolingian,Louis I,778,20 June 840,11 September 813,5 October 816,20 June 840 N/A,Carolingian,Lothair I,795,29 September 855,5 April 823,N/A,29 September 855 N/A,Carolingian,Louis II,825,12 August 875,15 June 844,18 May 872,12 August 875 N/A,Carolingian,Charles II,13 June 823,6 October 877,29 December 875,N/A,6 October 877 N/A,Carolingian,Charles III,13 June 839,13 January 888,12 February 881,N/A,11 November 887 N/A,Widonid,Guy III,835,12 December 894,21 February 891,N/A,12 December 894 N/A,Widonid,Lambert I,880,15 October 898,30 April 892,N/A,15 October 898 N/A,Carolingian,Arnulph,850,8 December 899,22 February 896,N/A,8 December 899 N/A,Bosonid,Louis III,880,5 June 928,22 February 901,N/A,21 July 905 N/A,Unruoching,Berengar I,845,7 April 924,December 915,N/A,7 April 924 1,Ottonian,Otto I,23 November 912,7 May 973,2 February 962,N/A,7 May 973 2,Ottonian,Otto II,955,7 December 983,25 December 967,N/A,7 December 983 3,Ottonian,Otto III,980,23 January 1002,21 May 996,N/A,23 January 1002 4,Ottonian,Henry II,6 May 973,13 July 1024,14 February 1014,N/A,13 July 1024 5,Salian,Conrad II,990,4 June 1039,26 March 1027,N/A,4 June 1039 6,Salian,Henry III,29 October 1017,5 October 1056,25 December 1046,N/A,5 October 1056 7,Salian,Henry IV,11 November 1050,7 August 1106,31 March 1084,N/A,December 1105 8,Salian,Henry V,8 November 1086,23 May 1125,13 April 1111,N/A,23 May 1125 9,Supplinburg,Lothair III,9 June 1075,4 December 1137,4 June 1133,N/A,4 December 1137 10,Staufen,Frederick I,1122,10 June 1190,18 June 1155,N/A,10 June 1190 11,Staufen,Henry VI,November 1165,28 September 1197,14 April 1191,N/A,28 September 1197 12,Welf,Otto IV,1175,19 May 1218,4 October 1209,N/A,1215 13,Staufen,Frederick II,26 December 1194,13 December 1250,22 November 1220,N/A,13 December 1250 14,Luxembourg,Henry VII,1275,24 August 1313,29 June 1312,N/A,24 August 1313 15,Wittelsbach,Louis IV,1 April 1282,11 October 1347,17 January 1328,N/A,11 October 1347 16,Luxembourg,Charles IV,14 May 1316,29 November 1378,5 April 1355,N/A,29 November 1378 17,Luxembourg,Sigismund,14 February 1368,9 December 1437,31 May 1433,N/A,9 December 1437 18,Habsburg,Frederick III,21 September 1415,19 August 1493,19 March 1452,N/A,19 August 1493 19,Habsburg,Maximilian I,22 March 1459,12 January 1519,N/A,N/A,12 January 1519 20,Habsburg,Charles V,24 February 1500,21 September 1558,February 1530,N/A,16 January 1556 21,Habsburg,Ferdinand I,10 March 1503,25 July 1564,N/A,N/A,25 July 1564 22,Habsburg,Maximilian II,31 July 1527,12 October 1576,N/A,N/A,12 October 1576 23,Habsburg,Rudolph II,18 July 1552,20 January 1612,30 June 1575,N/A,20 January 1612 24,Habsburg,Matthias,24 February 1557,20 March 1619,23 January 1612,N/A,20 March 1619 25,Habsburg,Ferdinand II,9 July 1578,15 February 1637,10 March 1619,N/A,15 February 1637 26,Habsburg,Ferdinand III,13 July 1608,2 April 1657,18 November 1637,N/A,2 April 1657 27,Habsburg,Leopold I,9 June 1640,5 May 1705,6 March 1657,N/A,5 May 1705 28,Habsburg,Joseph I,26 July 1678,17 April 1711,1 May 1705,N/A,17 April 1711 29,Habsburg,Charles VI,1 October 1685,20 October 1740,22 December 1711,N/A,20 October 1740 30,Wittelsbach,Charles VII,6 August 1697,20 January 1745,12 February 1742,N/A,20 January 1745 31,Lorraine,Francis I,8 December 1708,18 August 1765,N/A,N/A,18 August 1765 32,Habsburg-Lorraine,Joseph II,13 March 1741,20 February 1790,19 August 1765,N/A,20 February 1790 33,Habsburg-Lorraine,Leopold II,5 May 1747,1 March 1792,N/A,N/A,1 March 1792 34,Habsburg-Lorraine,Francis II,12 February 1768,2 March 1835,4 March 1792,N/A,6 August 1806 ================================================ FILE: html.md ================================================ --- name: HTML filename: learnhtml.txt contributors: - ["Christophe THOMAS", "https://github.com/WinChris"] translators: - ["Robert Steed", "https://github.com/robochat"] - ["Dimitri Kokkonis", "https://github.com/kokkonisd"] --- HTML stands for Hypertext Markup Language. It is a language which allows us to write pages for the World Wide Web. It is a markup language, it enables us to write webpages using code to indicate how text and data should be displayed. In fact, HTML files are simple text files. What is this markup? It is a method of organising the page's data by surrounding it with opening tags and closing tags. This markup serves to give significance to the text that it encloses. Like other computer languages, HTML has many versions. Here we will talk about HTML5. **NOTE :** You can test the different tags and elements as you progress through the tutorial on a site like [codepen](http://codepen.io/pen/) in order to see their effects, understand how they work and familiarise yourself with the language. This article is concerned principally with HTML syntax and some useful tips. ```html My Site

Hello, world!

Come look at what this shows

This is a paragraph.

This is another paragraph.

  • This is an item in a non-enumerated list (bullet list)
  • This is another item
  • And this is the last item on the list
My Site

Hello, world!

Come look at what this shows

This is a paragraph.

This is another paragraph.

  • This is an item in a non-enumerated list (bullet list)
  • This is another item
  • And this is the last item on the list
First Header Second Header
first row, first column first row, second column
second row, first column second row, second column
``` ## Usage HTML is written in files ending with `.html` or `.htm`. The mime type is `text/html`. **HTML is NOT a programming language** ## To Learn More * [Wikipedia](https://en.wikipedia.org/wiki/HTML) * [HTML Tutorial](https://developer.mozilla.org/en-US/docs/Web/HTML) * [W3Schools](http://www.w3schools.com/html/html_intro.asp) ================================================ FILE: httpie.md ================================================ --- category: tool name: HTTPie contributors: - ["Adaías Magdiel", "https://github.com/AdaiasMagdiel"] filename: learn-httpie.sh --- HTTPie is a powerful command-line HTTP client designed for easy interaction with HTTP servers. It provides a simple and intuitive interface, making it an excellent tool for developers, testers, and system administrators. ## Basic Usage HTTPie follows a simple syntax: http [flags] [METHOD] URL [items]. ```bash http GET https://api.example.com/posts ``` You can print the request without sending it by using the `--offline` flag. ```bash http --offline https://api.example.com/posts ``` ### URL shortcuts for `localhost` HTTPie supports a curl-like shorthand for localhost. For instance, `:3000` expands to `http://localhost:3000`. If the port is omitted, it assumes port 80. ```bash http :/users # http://localhost/users http :5000/rss # http://localhost:5000/rss ``` ### Optional GET and POST If you don't specify the METHOD, the HTTPie will use: - GET for requests without body - POST for requests with body ```bash http https://api.example.com/tags # GET tags http https://api.example.com/tags title="Tutorial" slug="tutorial" # POST a new tag ``` ## Querystring Parameters If you're manually adding query string parameters in the terminal, try the `param==value` syntax. It avoids shell escaping for & separators and automatically URL-escapes special characters in parameter names and values. This differs from parameters in the full URL, which HTTPie doesn't modify. ```bash http https://api.example.com/search q==httpie per_page==20 ``` ## Sending Data You can send data in various formats such as JSON, form data, or files. ### JSON Data ```bash http POST https://api.example.com/posts title="Hello" body="World" ``` ### Form Data ```bash http -f POST https://api.example.com/submit name=John email=john@example.com ``` ### Files ```bash http --form POST https://api.example.com/upload file@/path/to/file.txt ``` ## Headers and Authentication HTTPie allows you to set headers and handle authentication easily. ### Headers ```bash http GET https://api.example.com/posts Authorization:"Bearer Token" User-Agent:"HTTPie" ``` ### Basic Authentication ```bash http -a username:password GET https://api.example.com/protected ``` ### Bearer Authentication ```bash https -A bearer -a token https://api.example.com/admin ``` ## Response Handling HTTPie provides various options for handling responses. ```bash http GET https://api.example.com/data Accept:application/json # Pretty Print JSON http GET https://api.example.com/image --output image.png # Save Response to File http --follow GET https://example.com # Follow Redirects ``` ## Further Reading - [Official Documentation](https://httpie.io/docs/cli) - [GitHub](https://github.com/httpie) ================================================ FILE: hu/coffeescript.md ================================================ --- contributors: - ["Tenor Biel", "http://github.com/L8D"] - ["Xavier Yao", "http://github.com/xavieryao"] translators: - ["Tamás Diószegi", "http://github.com/ditam"] --- A CoffeeScript egy apró nyelv ami egy-az-egyben egyenértékű JavaScript kódra fordul, és így futásidőben már nem szükséges interpretálni. Mint a JavaScript egyik követője, a CoffeeScript mindent megtesz azért, hogy olvasható, jól formázott és jól futó JavaScript kódot állítson elő, ami minden JavaScript futtatókörnyezetben jól működik. Rézletekért lásd még a [CoffeeScript weboldalát](http://coffeescript.org/), ahol egy teljes CoffeScript tutorial is található. ```coffeescript # A CoffeeScript egy hipszter nyelv. # Követi több modern nyelv trendjeit. # Így a kommentek, mint Ruby-ban és Python-ban, a szám szimbólummal kezdődnek. ### A komment blokkok ilyenek, és közvetlenül '/ *' és '* /' jelekre fordítódnak az eredményül kapott JavaScript kódban. Mielőtt tovább olvasol, jobb, ha a JavaScript alapvető szemantikájával tisztában vagy. (A kód példák alatt kommentként látható a fordítás után kapott JavaScript kód.) ### # Értékadás: number = 42 #=> var number = 42; opposite = true #=> var opposite = true; # Feltételes utasítások: number = -42 if opposite #=> if(opposite) { number = -42; } # Függvények: square = (x) -> x * x #=> var square = function(x) { return x * x; } fill = (container, liquid = "coffee") -> "Filling the #{container} with #{liquid}..." #=>var fill; # #fill = function(container, liquid) { # if (liquid == null) { # liquid = "coffee"; # } # return "Filling the " + container + " with " + liquid + "..."; #}; # Szám tartományok: list = [1..5] #=> var list = [1, 2, 3, 4, 5]; # Objektumok: math = root: Math.sqrt square: square cube: (x) -> x * square x #=> var math = { # "root": Math.sqrt, # "square": square, # "cube": function(x) { return x * square(x); } # }; # "Splat" jellegű függvény-paraméterek: race = (winner, runners...) -> print winner, runners #=>race = function() { # var runners, winner; # winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : []; # return print(winner, runners); # }; # Létezés-vizsgálat: alert "I knew it!" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); } # Tömb értelmezések: (array comprehensions) cubes = (math.cube num for num in list) #=>cubes = (function() { # var _i, _len, _results; # _results = []; # for (_i = 0, _len = list.length; _i < _len; _i++) { # num = list[_i]; # _results.push(math.cube(num)); # } # return _results; # })(); foods = ['broccoli', 'spinach', 'chocolate'] eat food for food in foods when food isnt 'chocolate' #=>foods = ['broccoli', 'spinach', 'chocolate']; # #for (_k = 0, _len2 = foods.length; _k < _len2; _k++) { # food = foods[_k]; # if (food !== 'chocolate') { # eat(food); # } #} ``` ## További források - [Smooth CoffeeScript](http://autotelicum.github.io/Smooth-CoffeeScript/) - [CoffeeScript Ristretto](https://leanpub.com/coffeescript-ristretto/read) ================================================ FILE: hu/go.md ================================================ --- contributors: - ["Sonia Keys", "https://github.com/soniakeys"] translators: - ["Szabó Krisztián", "https://github.com/thenonameguy/"] - ["Árpád Goretity", "https://github.com/H2CO3"] --- A Go programozási nyelv az életszerű feladatok könnyebb elvégzése miatt született. A mai legújabb programozási trendeket elkerülve, praktikus megoldást nyújt a valós, üzleti problémákra. C-szerű szintaktikával és statikus típuskezeléssel rendelkezik. A fordító szempillantás alatt végez és egy gyorsan futó,statikus futtatható állományt hoz létre. A nyelv könnyen érthető, folyamatok közötti csatornákon áthaladó üzenetekkel kommunikáló konkurens programozást tesz lehetővé, így könnyen ki lehet használni a mai számítógépek több magos processzorait, ez nagy rendszerek építéséhez ideális. A Go alap könyvtára mindenre területre kiterjed, ennek köszönhetően a nyelvnek egyre növekvő tábora van. ```go // Egy soros komment /* Több soros komment */ // Minden forrás fájl egy csomag-definícióval kezdődik, ez hasonlít a Python // csomagkezelésére // A main egy különleges csomagnév, ennek a fordítása futtatható állományt hoz // létre egy könyvtár helyett. package main // Az import rész meghatározza melyik csomagokat kívánjuk használni ebben a // forrásfájlban import ( "fmt" // A Go alap könyvtárának része "net/http" // Beépített webszerver! "strconv" // Stringek átalakítására szolgáló csomag ) // Függvénydeklarálás, a main nevű függvény a program kezdőpontja. func main() { // Println kiírja a beadott paramétereket a standard kimenetre. // Ha más csomagot függvényeit akarjuk használni, akkor azt jelezni kell a // csomag nevével fmt.Println("Hello world!") // Meghívunk egy másik függvényt ebből a csomagból beyondHello() } // A függvények paraméterei zárójelek között vannak. // Ha nincsenek paraméterek, akkor is kötelező a zárójel-pár. func beyondHello() { var x int // Változó deklaráció, használat előtt muszáj ezt megtenni. x = 3 // Változó értékadás // "Rövid" deklaráció is létezik, ez az érték alapján deklarálja, // definiálja és értéket is ad a változónak y := 4 sum, prod := learnMultiple(x, y) // a függvényeknek több // visszatérési értéke is lehet fmt.Println("sum:", sum, "prod:", prod) // egyszerű kiíratás learnTypes() } // A funkcióknak elnevezett visszatérési értékük is lehet func learnMultiple(x, y int) (sum, prod int) { return x + y, x * y // visszatérünk két értékkel /* sum = x + y prod = x * y return Ez ugyanezzel az eredménnyel járt volna, mint a fenti sor. Üres return esetén, az elnevezett visszatérési változók aktuális értékeikkel térnek vissza. */ } // Beépített típusok func learnTypes() { // Rövid deklarálás az esetek többségében elég lesz a változókhoz s := "Tanulj Go-t!" // string típus s2 := `A "nyers" stringekben lehetnek újsorok is!` // de ettől még ez is ugyanolyan string mint az s, nincs külön // típusa // nem ASCII karakterek. Minden Go forrás UTF-8 és a stringek is azok. g := 'Σ' // rúna(rune) típus, megegyezik az uint32-vel, egy UTF-8 karaktert // tárol f := 3.14159 // float64, az IEEE-754 szabványnak megfelelő 64-bites // lebegőpontos szám c := 3 + 4i // complex128, belsőleg két float64-gyel tárolva // Var szintaxis változótípus-definiálással var u uint = 7 // unsigned, az implementáció dönti el mekkora, akárcsak az // int-nél var pi float32 = 22. / 7 // Rövid deklarásnál átalakítás is lehetséges n := byte('\n') // byte típus, ami megegyezik az uint8-al // A tömböknek fordítás-időben fixált méretük van var a4 [4]int // egy tömb 4 int-tel, mind 0-ra inicializálva a3 := [...]int{3, 1, 5} // egy tömb 3 int-tel, láthatóan inicalizálva egyedi // értékekre // A "szeleteknek" (slices) dinamikus a méretük. A szeleteknek és a tömböknek is // megvannak az előnyeik de a szeleteket sokkal gyakrabban használjuk. s3 := []int{4, 5, 9} // vesd össze a3-mal, nincsenek pontok. s4 := make([]int, 4) // allokál 4 int-et, mind 0-ra inicializálva var d2 [][]float64 // ez csak deklaráció, semmi sincs még allokálva bs := []byte("a slice") // típus konverzió szintaxisa p, q := learnMemory() // deklarál két mutatót (p,q), két int-re fmt.Println(*p, *q) // * követi a mutatót. Ez a sor kiírja a két int értékét. // A map a dinamikusan növelhető asszociatív tömb része a nyelvnek, hasonlít // a hash és dictionary típusokra más nyelvekben. m := map[string]int{"three": 3, "four": 4} m["one"] = 1 // A felhasználatlan változók fordítás-idejű hibát okoznak a Go-ban. // Az aláhúzással "használod" a változókat, de eldobod az értéküket. _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs // Kiíratás is természetesen használatnak minősül fmt.Println(s, c, a4, s3, d2, m) learnFlowControl() } // A Go nyelvben szemétgyűjtés (garbage collection) működik. Megtalálhatók benne // mutatók, de nincs pointeraritmetika. Ez azt jelenti, hogy üres (null) mutatóval még // mindig hibázhatsz, de hozzáadni/műveleteket végezni már nem lehet. func learnMemory() (p, q *int) { // Elnevezett visszatérési változóknak int-re mutató a típusa p = new(int) // a beépített "new" funkció, egy típusnak elegendő memóriát // allokál, és visszaad rá egy mutatót. // Az allokált int nullázva van, p többé nem üres mutató. s := make([]int, 20) // allokáljunk 20 int változót egy memóriaterületen. s[3] = 7 // adjunk értéket az egyiknek r := -2 // hozzánk létre egy lokális változót return &s[3], &r // A & megadja a memóriacímét a változónak } func expensiveComputation() int { return 1e6 } func learnFlowControl() { // Az elágazásoknak kötelező a kapcsos zárójel, a zárójel nem szükséges. if true { fmt.Println("megmondtam") } // A kód formátumát a nyelvvel járó "go" parancssori program "go fmt" // parancsa szabványosítja if false { // így lehet } else { // if/else-t csinálni } // Használjunk switchet a hosszabb elágazások alkalmazása helyett. x := 1 switch x { case 0: case 1: // Az "esetek" nem "esnek át", tehát case 2: // ez nem fog lefutni, nincs szükség break-ekre. } // A for ciklus sem használ zárójeleket for x := 0; x < 3; x++ { fmt.Println("iteráció", x) } // itt az x == 1. // A for az egyetlen ciklus fajta a Go-ban, de több formája van. for { // végtelen ciklus break // csak vicceltem continue // soha nem fut le } //Akárcsak a for-nál, az if-nél is lehet rövid deklarálással egy lokális változót létrehozni, //ami a blokk összes if/else szerkezetén keresztül érvényes marad. if y := expensiveComputation(); y > x { x = y } // Függvényeket használhatjuk closure-ként is. xBig := func() bool { return x > 100 // a switch felett deklarált x-et használjuk itt } fmt.Println("xBig:", xBig()) // igaz (utoljára 1e6 lett az értéke az x-nek) x /= 1e5 // így most már x == 10 fmt.Println("xBig:", xBig()) // 10 pedig kisebb mint 100, tehát hamis // Ha nagyon-nagyon szükséges, akkor használhatjuk a jó öreg goto-t. goto love love: learnInterfaces() // Itt kezdődnek az érdekes dolgok! } // Definiáljuk a Stringert egy olyan interfésznek, amelynek egy metódusa van, a // String, ami visszatér egy stringgel. type Stringer interface { String() string } // Definiáljuk a pair-t egy olyan struktúrának amelynek két int változója van, // x és y. type pair struct { x, y int } // Definiáljunk egy metódust a pair struktúrának, ezzel teljesítve a Stringer interfészt. func (p pair) String() string { // p lesz a "fogadó" (receiver) // Sprintf az fmt csomag egy publikus függvénye, műkődése megegyezik a C-s // megfelelőjével. A pontokkal érjük el a mindenkori p struktúra elemeit return fmt.Sprintf("(%d, %d)", p.x, p.y) } func learnInterfaces() { // A kapcsos zárójellel jelezzük, hogy egyből inicializálni // szeretnénk a struktúra változóit a sorrendnek megfelelően. p := pair{3, 4} fmt.Println(p.String()) // meghívjuk a p String metódusát. var i Stringer // deklaráljuk i-t Stringer típusú interfésznek i = p // lehetséges, mert a pair struktúra eleget tesz a // Stringer interfésznek // Meghívjuk i String metódusát, az eredmény ugyanaz, mint az előbb. fmt.Println(i.String()) // Az fmt csomag függvényei automatikusan meghívják a String függvényt // hogy megtudják egy objektum szöveges reprezentációját. fmt.Println(p) // ugyan az az eredmény mint az előbb, a Println meghívja // a String metódust. fmt.Println(i) // dettó learnErrorHandling() } func learnErrorHandling() { // ", ok" szokásos megoldás arra, hogy jól működött-e a függvény. m := map[int]string{3: "three", 4: "four"} if x, ok := m[1]; !ok { // ok hamis lesz, mert az 1 nincs benne a map-ban. fmt.Println("nincs meg") } else { fmt.Print(x) // x lenne az érték, ha benne lenne a map-ban. } // A hiba érték többet is elmond a függvény kimeneteléről, mint hogy minden // "ok" volt-e if _, err := strconv.Atoi("non-int"); err != nil { // _ eldobja az értéket, // úgy se lesz jó jelen // esetben // kiírja, hogy "strconv.ParseInt: parsing "non-int": invalid syntax" fmt.Println(err) } // Az interfészekre még visszatérünk, addig is jöjjön a konkurens programozás! learnConcurrency() } // c egy csatorna, egy konkurens-biztos kommunikációs objektum. func inc(i int, c chan int) { c <- i + 1 // <- a "küldés" operátor, ha a bal oldalán csatorna van, így // i+1-et küld be a csatornába } // Az inc-et fogjuk arra használni, hogy konkurensen megnöveljünk számokat func learnConcurrency() { // Ugyanaz a make függvény, amivel korábban szeleteket hoztunk létre. // A make allokál map-eket, szeleteket és csatornákat. c := make(chan int) // Indítsunk három konkurens goroutine-t. A számok konkurensen lesznek // megnövelve, ha a számítógép képes rá és jól be van állítva, akkor pedig // paralellizálva/egymás mellett. Mind a 3 ugyanabba a csatornába küldi az // eredményeket. go inc(0, c) // A go utasítás indít el goroutine-okat. go inc(10, c) go inc(-805, c) // Beolvassuk 3x a csatornából az eredményeket és kiírjuk őket a kimenetre. // Nem lehet tudni milyen sorrendben fognak érkezni az eredmények! fmt.Println(<-c, <-c, <-c) // hogyha a jobb oldalon csatorna van, akkor a // "<-" a beolvasó/kapó operátor cs := make(chan string) // még egy csatorna, ez stringekkel kommunikál cc := make(chan chan string) // egy csatorna csatornával go func() { c <- 84 }() // indítsunk egy új goroutine-t, csak azért // hogy küldjünk egy számot go func() { cs <- "wordy" }() // ugyanez, csak a cs csatornába stringet // küldünk // A select olyan mint a switch, csak feltételek helyett csatorna műveletek // vannak. Véletlenszerűen kiválasztja az első olyan esetet, ahol létrejöhet // kommunikáció. select { case i := <-c: // a megkapott értéket el lehet tárolni egy változóban fmt.Println("ez egy", i) case <-cs: // vagy el lehet dobni az értékét fmt.Println("ez egy string volt") case <-cc: // üres csatorna, soha nem fog rajta semmi se érkezni fmt.Println("sose futok le :'( ") } // Ezen a ponton vagy c vagy a cs goroutine-ja lefutott. // Amelyik hamarabb végzett, annak a megfelelő case-e lefutott, a másik // blokkolva vár. learnWebProgramming() // a Go képes rá. Te is képes akarsz rá lenni. } // Egy függvény a http csomagból elindít egy webszervert. func learnWebProgramming() { // A ListenAndServe első paramétre egy TCP port, amin kiszolgálunk majd. // Második paramétere egy interfész, pontosabban a http.Handler interfész. err := http.ListenAndServe(":8080", pair{}) fmt.Println(err) // nem felejtjük el kiírni az esetleges hibákat! } // Csináljunk a pair-ból egy http.Handler-t úgy, hogy implementáljuk az // egyetlen metódusát, a ServeHTTP-t. func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Minden kapcsolatra elküldjük ezt a http.ResponseWriter-rel w.Write([]byte("Megtanultad a Go-t Y perc alatt!")) } ``` ## További olvasmányok Minden Go-val kapcsolatos megtaláható a [hivatalos Go weboldalon](https://go.dev/). Ott követhetsz egy tutorialt, játszhatsz a nyelvvel az interneten, és sok érdekességet olvashatsz. A nyelv specifikációját kifejezetten érdemes olvasni, viszonylag rövid és sokat tanul belőle az ember. Ha pedig jobban bele akarod vetni magad a Go-ba, akkor a legjobb praktikákat kilesheted a standard könyvtárból. TIPP: a dokumentációban kattints egy függvény nevére és rögtön megmutatja a hozzá tartozó kódot! Ha pedig a nyelvnek egy bizonyos részéről szeretnél hasonló leírást találni, akkor a [gobyexample.com](https://gobyexample.com/)-on megtalálod, amit keresel. ================================================ FILE: hu/pythonlegacy.md ================================================ --- contributors: - ["Louie Dinh", "http://ldinh.ca"] - ["Amin Bandali", "https://aminb.org"] - ["Andre Polykanine", "https://github.com/Oire"] - ["evuez", "http://github.com/evuez"] - ["asyne", "https://github.com/justblah"] - ["habi", "http://github.com/habi"] translators: - ["Tamás Diószegi", "https://github.com/ditam"] --- A Python nyelvet Guido Van Rossum alkotta meg a 90-es évek elején. Manapság az egyik legnépszerűbb programozási nyelv. Én a tiszta szintaxisa miatt szerettem bele. Tulajdonképpen futtatható pszeudokód. Figyelem: ez a leírás a Python 2.7 verziójára vonatkozik, illetve általánosságban a 2.x verziókra. A Python 2.7 azonban már csak 2020-ig lesz támogatva, ezért kezdőknek ajánlott, hogy a Python 3-mal kezdjék az ismerkedést. A Python 3.x verzióihoz a [Python 3 bemutató](/python/) ajánlott. Lehetséges olyan Python kódot írni, ami egyszerre kompatibilis a 2.7 és a 3.x verziókkal is, a Python [`__future__` imports](https://docs.python.org/2/library/__future__.html) használatával. A `__future__` import használata esetén Python 3-ban írhatod a kódot, ami Python 2 alatt is futni fog, így ismét a fenti Python 3 bemutató ajánlott. ```python # Az egysoros kommentek kettőskereszttel kezdődnek """ Többsoros stringeket három darab " közé fogva lehet írni, ezeket gyakran használják több soros kommentként. """ #################################################### # 1. Egyszerű adattípusok és operátorok #################################################### # Használhatsz számokat 3 # => 3 # Az alapműveletek meglepetésektől mentesek 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7 # Az osztás kicsit trükkös. Egész osztást végez, és a hányados alsó egész része # lesz az eredmény 5 / 2 # => 2 # Az osztás kijavításához a (lebegőpontos) float típust kell használnunk 2.0 # Ez egy float 11.0 / 4.0 # => 2.75 áh... máris jobb # Az egész osztás a negatív számok esetén is az alsó egész részt eredményezi 5 // 3 # => 1 5.0 // 3.0 # => 1.0 # floatok esetén is -5 // 3 # => -2 -5.0 // 3.0 # => -2.0 # Ha importáljuk a division modult (ld. 6. Modulok rész), # akkor a '/' jellel pontos osztást tudunk végezni. from __future__ import division 11 / 4 # => 2.75 ...sima osztás 11 // 4 # => 2 ...egész osztás # Modulo művelet 7 % 3 # => 1 # Hatványozás (x az y. hatványra) 2 ** 4 # => 16 # A precedencia zárójelekkel befolyásolható (1 + 3) * 2 # => 8 # Logikai operátorok # Megjegyzés: az "and" és "or" csak kisbetűkkel helyes True and False # => False False or True # => True # A logikai operátorok egészeken is használhatóak 0 and 2 # => 0 -5 or 0 # => -5 0 == False # => True 2 == True # => False 1 == True # => True # Negálni a not kulcsszóval lehet not True # => False not False # => True # Egyenlőségvizsgálat == 1 == 1 # => True 2 == 1 # => False # Egyenlőtlenség != 1 != 1 # => False 2 != 1 # => True # További összehasonlítások 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # Az összehasonlítások láncolhatóak! 1 < 2 < 3 # => True 2 < 3 < 2 # => False # Stringeket " vagy ' jelek közt lehet megadni "Ez egy string." 'Ez egy másik string.' # A stringek összeadhatóak! "Hello " + "world!" # => "Hello world!" # '+' jel nélkül is összeadhatóak "Hello " "world!" # => "Hello world!" # ... illetve szorozhatóak "Hello" * 3 # => "HelloHelloHello" # Kezelhető karakterek indexelhető listájaként "This is a string"[0] # => 'T' # A string hosszát a len függvény adja meg len("This is a string") # => 16 # String formázáshoz a % jel használható # A Python 3.1-gyel a % már deprecated jelölésű, és később eltávolításra fog # kerülni, de azért jó tudni, hogyan működik. x = 'alma' y = 'citrom' z = "A kosárban levő elemek: %s és %s" % (x, y) # A string formázás újabb módja a format metódus használatával történik. # Jelenleg ez a javasolt megoldás. "{} egy {} szöveg".format("Ez", "helytartó") "A {0} pedig {1}".format("string", "formázható") # Ha nem akarsz számolgatni, nevesíthetőek a pozíciók. "{name} kedvence a {food}".format(name="Bob", food="lasagna") # None egy objektum None # => None # A None-nal való összehasonlításhoz ne használd a "==" jelet, # használd az "is" kulcsszót helyette "etc" is None # => False None is None # => True # Az 'is' operátor objektum egyezést vizsgál. # Primitív típusok esetén ez nem túl hasznos, # objektumok esetén azonban annál inkább. # Bármilyen objektum használható logikai kontextusban. # A következő értékek hamis-ra értékelődnek ki (ún. "falsey" értékek): # - None # - bármelyik szám típus 0 értéke (pl. 0, 0L, 0.0, 0j) # - üres sorozatok (pl. '', (), []) # - üres konténerek (pl., {}, set()) # - egyes felhasználó által definiált osztályok példányai bizonyos szabályok szerint, # ld: https://docs.python.org/2/reference/datamodel.html#object.__nonzero__ # # Minden egyéb érték "truthy" (a bool() függvénynek átadva igazra értékelődnek ki) bool(0) # => False bool("") # => False #################################################### # 2. Változók és kollekciók #################################################### # Létezik egy print utasítás print "I'm Python. Nice to meet you!" # => I'm Python. Nice to meet you! # Így lehet egyszerűen bemenetet kérni a konzolról: input_string_var = raw_input( "Enter some data: ") # Visszatér a megadott stringgel input_var = input("Enter some data: ") # Kiértékeli a bemenetet python kódként # Vigyázat: a fentiek miatt az input() metódust körültekintően kell használni # Megjegyzés: Python 3-ban az input() már deprecated, és a raw_input() lett input()-ra átnevezve # A változókat nem szükséges a használat előtt deklarálni some_var = 5 # Konvenció szerint a névben kisbetu_es_alulvonas some_var # => 5 # Érték nélküli változóra hivatkozás hibát dob. # Lásd a Control Flow szekciót a kivételkezelésről. some_other_var # name error hibát dob # az if használható kifejezésként # a C nyelv '?:' ternáris operátorával egyenértékűen "yahoo!" if 3 > 2 else 2 # => "yahoo!" # A listákban sorozatok tárolhatóak li = [] # Már inicializáláskor megadhatóak elemek other_li = [4, 5, 6] # A lista végére az append metódus rak új elemet li.append(1) # li jelenleg [1] li.append(2) # li jelenleg [1, 2] li.append(4) # li jelenleg [1, 2, 4] li.append(3) # li jelenleg [1, 2, 4, 3] # A végéről a pop metódus távolít el elemet li.pop() # => 3 és li jelenleg [1, 2, 4] # Rakjuk vissza li.append(3) # li jelenleg [1, 2, 4, 3], újra. # A lista elemeket tömb indexeléssel lehet hivatkozni li[0] # => 1 # A már inicializált értékekhez a = jellel lehet új értéket rendelni li[0] = 42 li[0] # => 42 li[0] = 1 # csak visszaállítjuk az eredeti értékére # Így is lehet az utolsó elemre hivatkozni li[-1] # => 3 # A túlindexelés eredménye IndexError li[4] # IndexError hibát dob # A lista részeit a slice szintaxissal lehet kimetszeni # (Matekosoknak ez egy zárt/nyitott intervallum.) li[1:3] # => [2, 4] # A lista eleje kihagyható így li[2:] # => [4, 3] # Kihagyható a vége li[:3] # => [1, 2, 4] # Minden második elem kiválasztása li[::2] # =>[1, 4] # A lista egy másolata, fordított sorrendben li[::-1] # => [3, 4, 2, 1] # A fentiek kombinációival bonyolultabb slice parancsok is képezhetőek # li[start:end:step] # Listaelemek a "del" paranccsal törölhetőek del li[2] # li jelenleg [1, 2, 3] # A listák összeadhatóak li + other_li # => [1, 2, 3, 4, 5, 6] # Megjegyzés: az eredeti li és other_li értékei változatlanok # Összefőzhetőek (konkatenálhatóak) az "extend()" paranccsal li.extend(other_li) # li jelenleg [1, 2, 3, 4, 5, 6] # Egy elem első előfordulásának eltávolítása li.remove(2) # li jelenleg [1, 3, 4, 5, 6] li.remove(2) # ValueError hibát dob, mivel a 2 nem szerepel már a listában # Elemek beszúrhatóak tetszőleges helyre li.insert(1, 2) # li jelenleg [1, 2, 3, 4, 5, 6], ismét # Egy elem első előfordulási helye li.index(2) # => 1 li.index(7) # ValueError hibát dob, mivel a 7 nem szerepel a listában # Egy listában egy elem előfordulása az "in" szóval ellenőrizhető 1 in li # => True # A lista hossza a "len()" függvénnyel len(li) # => 6 # Az N-esek ("tuple") hasonlítanak a listákhoz, de nem módosíthatóak tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # TypeError hibát dob # Az összes lista-műveletet ezeken is használható len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True # Az N-esek (és listák) kicsomagolhatóak külön változókba a, b, c = (1, 2, 3) # az a így 1, a b 2 és a c pedig 3 d, e, f = 4, 5, 6 # a zárójel elhagyható # Ha elhagyod a zárójeleket, alapértelmezés szerint tuple képződik g = 4, 5, 6 # => (4, 5, 6) # Nézd, milyen egyszerű két értéket megcserélni e, d = d, e # d most már 5 és az e 4 # A Dictionary típusokban hozzárendelések (kulcs-érték párok) tárolhatók empty_dict = {} # Ez pedig rögtön értékekkel van inicializálva filled_dict = {"one": 1, "two": 2, "three": 3} # Egy dictionary értékei [] jelek közt indexelhetőek filled_dict["one"] # => 1 # A "keys()" metódus visszatér a kulcsok listájával filled_dict.keys() # => ["three", "two", "one"] # Megjegyzés: egy dictionary párjainak sorrendje nem garantált # Lehet, hogy már a fenti példán is más sorrendben kaptad meg az elemeket. # Az értékek listája a "values()" metódussal kérhető le filled_dict.values() # => [3, 2, 1] # ld. a fenti megjegyzést az elemek sorrendjéről. # Az összes kulcs-érték pár megkapható N-esek listájaként az "items()" metódussal filled_dict.items() # => [("one", 1), ("two", 2), ("three", 3)] # Az "in" kulcssszóval ellenőrizhető, hogy egy kulcs szerepel-e a dictionary-ben "one" in filled_dict # => True 1 in filled_dict # => False # Nem létező kulcs hivatkozása KeyError hibát dob filled_dict["four"] # KeyError # A "get()" metódus használatával elkerülhető a KeyError filled_dict.get("one") # => 1 filled_dict.get("four") # => None # A metódusnak megadható egy alapértelmezett visszatérési érték is, hiányzó értékek esetén filled_dict.get("one", 4) # => 1 filled_dict.get("four", 4) # => 4 # Megjegyzés: ettől még filled_dict.get("four") => None # (vagyis a get nem állítja be az alapértelmezett értéket a dictionary-ben) # A kulcsokhoz értékek a listákhoz hasonló szintaxissal rendelhetőek: filled_dict["four"] = 4 # ez után filled_dict["four"] => 4 # A "setdefault()" metódus csak akkor állít be egy értéket, ha az adott kulcshoz még nem volt más megadva filled_dict.setdefault("five", 5) # filled_dict["five"] beállítva 5-re filled_dict.setdefault("five", 6) # filled_dict["five"] még mindig 5 # Egy halmaz ("set") olyan, mint egy lista, de egy elemet csak egyszer tárolhat empty_set = set() # Inicializáljuk ezt a halmazt néhány elemmel some_set = set([1, 2, 2, 3, 4]) # some_set jelenleg set([1, 2, 3, 4]) # A sorrend itt sem garantált, még ha néha rendezettnek is tűnhet another_set = set([4, 3, 2, 2, 1]) # another_set jelenleg set([1, 2, 3, 4]) # Python 2.7 óta már {} jelek közt is lehet halmazt definiálni filled_set = {1, 2, 2, 3, 4} # => {1, 2, 3, 4} # Új halmaz-elemek hozzáadása filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} # Halmaz metszés a & operátorral other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} # Halmaz unió | operátorral filled_set | other_set # => {1, 2, 3, 4, 5, 6} # Halmaz különbség - {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # Szimmetrikus differencia ^ {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} # Vizsgáljuk, hogy a bal oldali halmaz magában foglalja-e a jobb oldalit {1, 2} >= {1, 2, 3} # => False # Vizsgáljuk, hogy a bal oldali halmaz részhalmaza-e a jobb oldalinak {1, 2} <= {1, 2, 3} # => True # Halmazbeli elemek jelenléte az in kulcssszóval vizsgálható 2 in filled_set # => True 10 in filled_set # => False #################################################### # 3. Control Flow #################################################### # Legyen egy változónk some_var = 5 # Ez egy if elágazás. A behúzás mértéke (az indentáció) jelentéssel bír a nyelvben! # Ez a kód ezt fogja kiírni: "some_var kisebb 10-nél" if some_var > 10: print "some_var nagyobb, mint 10." elif some_var < 10: # Az elif kifejezés nem kötelező az if szerkezetben. print "some_var kisebb 10-nél" else: # Ez sem kötelező. print "some_var kereken 10." """ For ciklusokkal végigiterálhatunk listákon a kimenet: A(z) kutya emlős A(z) macska emlős A(z) egér emlős """ for animal in ["kutya", "macska", "egér"]: # A {0} kifejezéssel formázzuk a stringet, ld. korábban. print "A(z) {0} emlős".format(animal) """ "range(number)" visszatér számok listájával 0-től number-ig a kimenet: 0 1 2 3 """ for i in range(4): print i """ "range(lower, upper)" visszatér a lower és upper közti számok listájával a kimenet: 4 5 6 7 """ for i in range(4, 8): print i """ A while ciklus a feltétel hamissá válásáig fut. a kimenet: 0 1 2 3 """ x = 0 while x < 4: print x x += 1 # Rövidítés az x = x + 1 kifejezésre # A kivételek try/except blokkokkal kezelhetőek # Python 2.6-tól felfele: try: # A "raise" szóval lehet hibát dobni raise IndexError("Ez egy index error") except IndexError as e: pass # A pass egy üres helytartó művelet. Itt hívnánk a hibakezelő kódunkat. except (TypeError, NameError): pass # Ha szükséges, egyszerre több hiba típus is kezelhető else: # Az except blokk után opcionálisan megadható print "Minden rendben!" # Csak akkor fut le, ha fentebb nem voltak hibák finally: # Mindenképpen lefut print "Itt felszabadíthatjuk az erőforrásokat például" # Az erőforrások felszabadításához try/finally helyett a with használható with open("myfile.txt") as f: for line in f: print line #################################################### # 4. Függvények #################################################### # A "def" szóval hozhatunk létre új függvényt def add(x, y): print "x is {0} and y is {1}".format(x, y) return x + y # A return szóval tudunk értékeket visszaadni # Így hívunk függvényt paraméterekkel add(5, 6) # => a konzol kimenet "x is 5 and y is 6", a visszatérési érték 11 # Nevesített paraméterekkel (ún. "keyword arguments") is hívhatunk egy függvényt add(y=6, x=5) # Ez esetben a sorrendjük nem számít # Változó számú paramétert fogadó függvény így definiálható. # A * használatával a paramétereket egy N-esként kapjuk meg. def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) # Változó számú nevesített paramétert fogadó függvény is megadható, # a ** használatával a paramétereket egy dictionary-ként kapjuk meg def keyword_args(**kwargs): return kwargs # Nézzük meg, mi történik keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} # A két módszer egyszerre is használható def all_the_args(*args, **kwargs): print args print kwargs """ all_the_args(1, 2, a=3, b=4) kimenete: (1, 2) {"a": 3, "b": 4} """ # Függvények hívásakor a fenti args és kwargs módszerek inverze használható # A * karakter kifejt egy listát külön paraméterekbe, a ** egy dictionary-t nevesített paraméterekbe. args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # egyenértékű: foo(1, 2, 3, 4) all_the_args(**kwargs) # egyenértékű: foo(a=3, b=4) all_the_args(*args, **kwargs) # egyenértékű: foo(1, 2, 3, 4, a=3, b=4) # A fenti arg és kwarg paraméterek továbbadhatóak egyéb függvényeknek, # a * illetve ** operátorokkal kifejtve def pass_all_the_args(*args, **kwargs): all_the_args(*args, **kwargs) print varargs(*args) print keyword_args(**kwargs) # Függvény scope x = 5 def set_x(num): # A lokális x változó nem ugyanaz, mint a globális x x = num # => 43 print x # => 43 def set_global_x(num): global x print x # => 5 x = num # a globális x-et 6-ra állítjuk print x # => 6 set_x(43) set_global_x(6) # A pythonban a függvény elsőrendű (ún. "first class") típus def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 # Névtelen függvények is definiálhatóak (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 # Léteznek beépített magasabb rendű függvények map(add_10, [1, 2, 3]) # => [11, 12, 13] map(max, [1, 2, 3], [4, 2, 1]) # => [4, 2, 3] filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7] # A listaképző kifejezések ("list comprehensions") jól használhatóak a map és filter függvényekkel [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # halmaz és dictionary képzők is léteznek {x for x in 'abcddeef' if x in 'abc'} # => {'a', 'b', 'c'} {x: x ** 2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### # 5. Osztályok #################################################### # Az object osztály egy alosztályát képezzük class Human(object): # Osztály szintű mező: az osztály összes példányában azonos species = "H. sapiens" # Ez a függvény meghívódik az osztály példányosításakor. # Megjegyzés: a dupla aláhúzás a név előtt és után egy konvenció a python # előre definiált, a nyelv által belsőleg használt, de a felhasználó által # is látható objektumok és mezők neveire. # Ne vezessünk be új, ilyen elnevezési sémát használó neveket! def __init__(self, name): # A paramétert értékül adjuk a példány name attribútumának self.name = name # Inicializálunk egy mezőt self.age = 0 # Példány metódus. Minden metódus első paramétere a "self", a példány maga def say(self, msg): return "{0}: {1}".format(self.name, msg) # Egy osztálymetódus az osztály összes példány közt meg van osztva. # Hívásukkor az első paraméter mindig a hívó osztály. @classmethod def get_species(cls): return cls.species # Egy statikus metódus osztály és példányreferencia nélkül hívódik @staticmethod def grunt(): return "*grunt*" # Egy property jelölésű függvény olyan, mint egy getter. # Használatával az age mező egy csak-olvasható attribútummá válik. @property def age(self): return self._age # Így lehet settert megadni egy mezőhöz @age.setter def age(self, age): self._age = age # Így lehet egy mező törlését engedélyezni @age.deleter def age(self): del self._age # Példányosítsuk az osztályt i = Human(name="Ian") print i.say("hi") # kimenet: "Ian: hi" j = Human("Joel") print j.say("hello") # kimenet: "Joel: hello" # Hívjuk az osztály metódusunkat i.get_species() # => "H. sapiens" # Változtassuk meg az osztály szintű attribútumot Human.species = "H. neanderthalensis" i.get_species() # => "H. neanderthalensis" j.get_species() # => "H. neanderthalensis" # Hívjuk meg a statikus metódust Human.grunt() # => "*grunt*" # Adjunk új értéket a mezőnek i.age = 42 # Kérjük le a mező értékét i.age # => 42 # Töröljük a mezőt del i.age i.age # => AttributeError hibát dob #################################################### # 6. Modulok #################################################### # Modulokat így lehet importálni import math print math.sqrt(16) # => 4.0 # Lehetséges csak bizonyos függvényeket importálni egy modulból from math import ceil, floor print ceil(3.7) # => 4.0 print floor(3.7) # => 3.0 # Egy modul összes függvénye is importálható # Vigyázat: ez nem ajánlott. from math import * # A modulok nevei lerövidíthetőek import math as m math.sqrt(16) == m.sqrt(16) # => True # Meggyőződhetünk róla, hogy a függvények valóban azonosak from math import sqrt math.sqrt == m.sqrt == sqrt # => True # A Python modulok egyszerű fájlok. # Írhatsz sajátot és importálhatod is. # A modul neve azonos a tartalmazó fájl nevével. # Így lehet megtekinteni, milyen mezőket és függvényeket definiál egy modul. import math dir(math) # Ha van egy math.py nevű Python scripted a jelenleg futó scripttel azonos # mappában, a math.py fájl lesz betöltve a beépített Python modul helyett. # A lokális mappa prioritást élvez a beépített könyvtárak felett. #################################################### # 7. Haladóknak #################################################### # Generátorok # Egy generátor értékeket "generál" amikor kérik, a helyett, hogy előre eltárolná őket. # A következő metódus (ez még NEM egy generátor) megduplázza a kapott iterable elemeit, # és eltárolja őket. Nagy méretű iterable esetén ez nagyon sok helyet foglalhat! def double_numbers(iterable): double_arr = [] for i in iterable: double_arr.append(i + i) return double_arr # A következő kód futtatásakor az összes szám kétszeresét kiszámítanánk, és visszaadnánk # ezt a nagy listát a ciklus vezérléséhez. for value in double_numbers(range(1000000)): # `test_non_generator` print value if value > 5: break # Használjunk inkább egy generátort, ami "legenerálja" a soron következő elemet, # amikor azt kérik tőle def double_numbers_generator(iterable): for i in iterable: yield i + i # A lenti kód mindig csak a soron következő számot generálja a logikai vizsgálat előtt. # Így amikor az érték eléri a > 5 határt, megszakítjuk a ciklust, és a lista számainak # nagy részénél megspóroltuk a duplázás műveletet (ez sokkal gyorsabb így!). for value in double_numbers_generator(xrange(1000000)): # `test_generator` print value if value > 5: break # Feltűnt, hogy a `test_non_generator` esetén `range`, a `test_generator` esetén # pedig `xrange` volt a segédfüggvény neve? Ahogy `double_numbers_generator` a # generátor változata a `double_numbers` függvénynek, úgy az `xrange` a `range` # generátor megfelelője, csak akkor generálja le a következő számot, amikor kérjük # - esetünkben a ciklus következő iterációjakor # A lista képzéshez hasonlóan generátor képzőket is használhatunk # ("generator comprehensions"). values = (-x for x in [1, 2, 3, 4, 5]) for x in values: print(x) # kimenet: -1 -2 -3 -4 -5 # Egy generátor összes generált elemét listaként is elkérhetjük: values = (-x for x in [1, 2, 3, 4, 5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] # Dekorátorok # A dekorátor egy magasabb rendű függvény, aminek bemenete és kimenete is egy függvény. # A lenti egyszerű példában az add_apples dekorátor a dekorált get_fruits függvény # kimenetébe beszúrja az 'Apple' elemet. def add_apples(func): def get_fruits(): fruits = func() fruits.append('Apple') return fruits return get_fruits @add_apples def get_fruits(): return ['Banana', 'Mango', 'Orange'] # A kimenet tartalmazza az 'Apple' elemet: # Banana, Mango, Orange, Apple print ', '.join(get_fruits()) # Ebben a példában a beg dekorátorral látjuk el a say függvényt. # Beg meghívja say-t. Ha a say_please paraméter igaz, akkor # megváltoztatja az eredmény mondatot. from functools import wraps def beg(target_function): @wraps(target_function) def wrapper(*args, **kwargs): msg, say_please = target_function(*args, **kwargs) if say_please: return "{} {}".format(msg, "Please! I am poor :(") return msg return wrapper @beg def say(say_please=False): msg = "Can you buy me a beer?" return msg, say_please print say() # Can you buy me a beer? print say(say_please=True) # Can you buy me a beer? Please! I am poor :( ``` ## Még több érdekel? ### Ingyenes online tartalmak * [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) * [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) * [Dive Into Python](http://www.diveintopython.net/) * [The Official Docs](http://docs.python.org/2/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) * [Python Module of the Week](http://pymotw.com/2/) * [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182) * [First Steps With Python](https://realpython.com/learn/python-first-steps/) * [LearnPython](http://www.learnpython.org/) * [Fullstack Python](https://www.fullstackpython.com/) ### Könyvek * [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20) * [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20) * [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20) ================================================ FILE: hu/ruby.md ================================================ --- contributors: - ["David Underwood", "http://theflyingdeveloper.com"] - ["Joel Walden", "http://joelwalden.net"] - ["Luke Holder", "http://twitter.com/lukeholder"] - ["Tristan Hume", "http://thume.ca/"] - ["Nick LaMuro", "https://github.com/NickLaMuro"] - ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"] - ["Ariel Krakowski", "http://www.learneroo.com"] - ["Dzianis Dashkevich", "https://github.com/dskecse"] - ["Levi Bostian", "https://github.com/levibostian"] - ["Rahil Momin", "https://github.com/iamrahil"] translators: - ["Zsolt Prontvai", "https://github.com/prozsolt"] --- ```ruby # Ez egy komment =begin Ez egy többsoros komment Senki sem használja Neked sem kellene =end # Először is: Minden objektum # A számok objektumok 3.class #=> Fixnum 3.to_s #=> "3" # Néhány alapvető számtani művelet 1 + 1 #=> 2 8 - 1 #=> 7 10 * 2 #=> 20 35 / 5 #=> 7 2**5 #=> 32 # A számtani művelet csak szintaktikus cukor # az objektumon történő függvény hívásra 1.+(3) #=> 4 10.* 5 #=> 50 # A speciális értékek objektumok nil # Nincs itt semmi látnivaló true # igaz false # hamis nil.class #=> NilClass true.class #=> TrueClass false.class #=> FalseClass # Egyenlőség 1 == 1 #=> true 2 == 1 #=> false # Egyenlőtlenség 1 != 1 #=> false 2 != 1 #=> true # A false-on kívül, nil az egyetlen hamis érték !nil #=> true !false #=> true !0 #=> false # Még több összehasonlítás 1 < 10 #=> true 1 > 10 #=> false 2 <= 2 #=> true 2 >= 2 #=> true # Logikai operátorok true && false #=> false true || false #=> true !true #=> false # A logikai operátoroknak alternatív verziójuk is van sokkal kisebb # precedenciával. Ezeket arra szánták, hogy több állítást összeláncoljanak # amíg egyikük igaz vagy hamis értékkel nem tér vissza. # `csinalj_valami_mast` csak akkor fut le, ha `csinalj_valamit` igaz értékkel # tért vissza. csinalj_valamit() and csinalj_valami_mast() # `log_error` csak akkor fut le, ha `csinalj_valamit` hamis értékkel # tért vissza. csinalj_valamit() or log_error() # A sztringek objektumok 'Én egy sztring vagyok'.class #=> String "Én is egy sztring vagyok".class #=> String helykitolto = 'interpolációt használhatok' "Sztring #{helykitolto}, ha dupla időzőjelben van a sztringem" #=> "Sztring interpolációt használhatok, ha dupla időzőjelben van a sztringem" # A szimpla idézőjelet preferáljuk, ahol csak lehet, # mert a dupla idézőjel extra számításokat végez. # Kombinálhatunk sztringeket, de nem számokkal 'hello ' + 'world' #=> "hello world" 'hello ' + 3 #=> TypeError: can't convert Fixnum into String 'hello ' + 3.to_s #=> "hello 3" # kiírás a kimenetre puts "Írok" # Változók x = 25 #=> 25 x #=> 25 # Értékadás az adott értékkel tér vissza # Ez azt jelenti, hogy használhatunk többszörös értékadást: x = y = 10 #=> 10 x #=> 10 y #=> 10 # Konvencióból, snake_case változó neveket használj snake_case = true # Leíró változó neveket használj ut_a_projekt_gyokerehez = '/jo/nev/' ut = '/rossz/nev/' # A szimbólumok (objektumok) # A szimbólumok megváltoztathatatlan, újra felhasználható konstans, # mely belsőleg egész számként reprezentált. Sokszor sztring helyett használják, # hogy effektíven közvetítsünk konkrét, értelmes értékeket :fuggoben.class #=> Symbol statusz = :fuggoben statusz == :fuggoben #=> true statusz == 'fuggoben' #=> false statusz == :jovahagyott #=> false # Tömbök # Ez egy tömb tomb = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] # A tömmbök különböző tipusú dolgokat tartalmazhat [1, 'hello', false] #=> [1, "hello", false] # Tömbök indexelhetőek # Az elejéről tomb[0] #=> 1 tomb[12] #=> nil # Akárcsak a számtani műveletek [var] hozzáférés # is csak szintaktikus cukor # a [] függvény hívására az objektumon tomb.[] 0 #=> 1 tomb.[] 12 #=> nil # A végéről tomb[-1] #=> 5 # Kezdőértékkel és hosszal tomb[2, 3] #=> [3, 4, 5] # Tömb megfordítása a=[1,2,3] a.reverse! #=> [3,2,1] # Vagy tartománnyal tomb[1..3] #=> [2, 3, 4] # Így adhatunk a tömbhöz tomb << 6 #=> [1, 2, 3, 4, 5, 6] # Vagy így tomb.push(6) #=> [1, 2, 3, 4, 5, 6] # Ellenőrízük, hogy a tömb tartalmaz egy elemet tomb.include?(1) #=> true # Hash-ek a ruby elsődleges szótárjai kulcs/érték párokkal # Hash-eket kapcsos zárójellel jelöljük hash = { 'szin' => 'zold', 'szam' => 5 } hash.keys #=> ['szin', 'szam'] # Hash-ekben könnyen kreshetünk a kulcs segítségével: hash['szin'] #=> 'zold' hash['szam'] #=> 5 # Nem létező kulcsra keresve nil-t kapunk: hash['nincs itt semmi'] #=> nil # Ruby 1.9-től, egy külnleges szintaxist is használhatunk a szimbólumot # használunk kulcsnak uj_hash = { defcon: 3, action: true } uj_hash.keys #=> [:defcon, :action] # Ellenőrizzük, hogy az adott kulcs és érték bene-e van a hash-ben uj_hash.has_key?(:defcon) #=> true uj_hash.has_value?(3) #=> true # Tip: A tömbök és hash-ek is felsorolhatóak # Sok közös függvényük van, akár az each, map, count, és több # Kontroll Struktúrák if true 'ha állítás' elsif false 'különben ha, opcionális' else 'különben, szintén opcionális' end for szamlalo in 1..5 puts "iteracio #{szamlalo}" end #=> iteracio 1 #=> iteracio 2 #=> iteracio 3 #=> iteracio 4 #=> iteracio 5 # HOWEVER, No-one uses for loops. # Instead you should use the "each" method and pass it a block. # A block is a bunch of code that you can pass to a method like "each". # It is analogous to lambdas, anonymous functions or closures in other # programming languages. # # The "each" method of a range runs the block once for each element of the range. # The block is passed a counter as a parameter. # Calling the "each" method with a block looks like this: (1..5).each do |counter| puts "iteration #{counter}" end #=> iteration 1 #=> iteration 2 #=> iteration 3 #=> iteration 4 #=> iteration 5 # You can also surround blocks in curly brackets: (1..5).each { |counter| puts "iteration #{counter}" } # The contents of data structures can also be iterated using each. array.each do |element| puts "#{element} is part of the array" end hash.each do |key, value| puts "#{key} is #{value}" end counter = 1 while counter <= 5 do puts "iteration #{counter}" counter += 1 end #=> iteration 1 #=> iteration 2 #=> iteration 3 #=> iteration 4 #=> iteration 5 jegy = '4' case jegy when '5' puts 'Kitünő' when '4' puts 'Jó' when '3' puts 'Közepes' when '2' puts 'Elégsége' when '1' puts 'Elégtelen' else puts 'Alternatív értékelés, hm?' end #=> "Jó" # case-ek tartományokat is használhatnak jegy = 82 case jegy when 90..100 puts 'Hurrá!' when 80...90 puts 'Jó munka' else puts 'Megbuktál!' end #=> "Jó munka" # kivétel kezelés: begin # kód ami kivételt dobhat raise NoMemoryError, 'Megtelt a memória' rescue NoMemoryError => kivetel_valtozo puts 'NoMemoryError-t dobott', kivetel_valtozo rescue RuntimeError => mas_kivetel_valtozo puts 'RuntimeError dobott most' else puts 'Ez akkor fut ha nem dob kivételt' ensure puts 'Ez a kód mindenképpen lefut' end # Függvények def ketszeres(x) x * 2 end # Függvények (és egyébb blokkok) implicit viszatértnek az utolsó értékkel ketszeres(2) #=> 4 # Zárójelezés opcionális, ha az eredmény félreérthetetlen ketszeres 3 #=> 6 ketszeres ketszeres 3 #=> 12 def osszeg(x, y) x + y end # Függvény argumentumait vesszővel választjuk el. osszeg 3, 4 #=> 7 osszeg osszeg(3, 4), 5 #=> 12 # yield # Minden függvénynek van egy implicit, opcionális block paramétere # 'yield' kulcsszóval hívhatjuk def korulvesz puts '{' yield puts '}' end korulvesz { puts 'hello world' } # { # hello world # } # Fuggvénynek átadhatunk blokkot # "&" jelöli az átadott blokk referenciáját def vendegek(&block) block.call 'valami_argumentum' end # Argumentum lisát is átadhatunk, ami tömbé lesz konvertálva # Erre való a splat operátor ("*") def vendegek(*array) array.each { |vendeg| puts vendeg } end # Osztályt a class kulcsszóval definiálhatunk class Ember # Az osztály változó. Az osztály minden példánnyával megvan osztva @@faj = 'H. sapiens' # Alap inicializáló def initialize(nev, kor = 0) # Hozzárendeli az argumentumot a "nev" példány változóhoz @nev = nev # Ha nem adtunk meg kort akkor az alapértemezet értéket fogja használni @kor = kor end # Alap setter függvény def nev=(nev) @nev = nev end # Alap getter függvény def nev @nev end # A fönti funkcionalítást az attr_accessor függvénnyel is elérhetjük attr_accessor :nev # Getter/setter függvények egyenként is kreálhatóak attr_reader :nev attr_writer :nev # Az osztály függvények "self"-et hasznalnak, hogy megkülönböztessék magukat a # példány függvényektől # Az osztályn hívhatóak, nem a példányon def self.mond(uzenet) puts uzenet end def faj @@faj end end # Példányosítsuk az osztályt jim = Ember.new('Jim Halpert') dwight = Ember.new('Dwight K. Schrute') # Hívjunk meg pár függvényt jim.faj #=> "H. sapiens" jim.nev #=> "Jim Halpert" jim.nev = "Jim Halpert II" #=> "Jim Halpert II" jim.nev #=> "Jim Halpert II" dwight.faj #=> "H. sapiens" dwight.nev #=> "Dwight K. Schrute" # Hívjuk meg az osztály függvényt Ember.mond('Hi') #=> "Hi" # Változók szókjait az elnevezésük definiálja # $ kezdetű változók globálisak $var = "Én egy globális változó vagyok" defined? $var #=> "global-variable" # Változók amik @-al kezdődnek példány szkópjuk van @var = "Én egy példány változó vagyok" defined? @var #=> "instance-variable" # Változók amik @@-al kezdődnek példány szkópjuk van @@var = "Én egy osztály változó vagyok" defined? @@var #=> "class variable" # Változók amik nagy betűvel kezdődnek a konstansok Var = "Konstans vagyok" defined? Var #=> "constant" # Az osztály is objetum. Tehát az osztálynak lehet példány változója # Az osztályváltozón osztozik minden pédány és leszármazott # Ős osztály class Ember @@foo = 0 def self.foo @@foo end def self.foo=(ertek) @@foo = ertek end end # Leszarmazott osztály class Dolgozo < Ember end Ember.foo # 0 Dolgozo.foo # 0 Ember.foo = 2 # 2 Dolgozo.foo # 2 # Az osztálynak példány változóját nem látja az osztály leszármazottja. class Ember @bar = 0 def self.bar @bar end def self.bar=(ertek) @bar = ertek end end class Doctor < Ember end Ember.bar # 0 Doctor.bar # nil module ModulePelda def foo 'foo' end end # Modulok include-olása a fügvényeiket az osztály példányaihoz köti. # Modulok extend-elésa a fügvényeiket magához az osztályhoz köti. class Szemely include ModulePelda end class Konyv extend ModulePelda end Szemely.foo # => NoMethodError: undefined method `foo' for Szemely:Class Szemely.new.foo # => 'foo' Konyv.foo # => 'foo' Konyv.new.foo # => NoMethodError: undefined method `foo' # Callback-ek végrehajtódnak amikor include-olunk és extend-elünk egy modult module ConcernPelda def self.included(base) base.extend(ClassMethods) base.send(:include, InstanceMethods) end module ClassMethods def bar 'bar' end end module InstanceMethods def qux 'qux' end end end class Valami include ConcernPelda end Valami.bar # => 'bar' Valami.qux # => NoMethodError: undefined method `qux' Valami.new.bar # => NoMethodError: undefined method `bar' Valami.new.qux # => 'qux' ``` ## Egyéb források - [Official Documentation](http://www.ruby-doc.org/core-2.1.1/) - [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/) - [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - A régebbi [ingyenes változat](http://ruby-doc.com/docs/ProgrammingRuby/) elérhető online. - [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) ================================================ FILE: hu/typescript.md ================================================ --- contributors: - ["Philippe Vlérick", "https://github.com/pvlerick"] translators: - ["Tamás Diószegi", "https://github.com/ditam"] --- A TypeScript nyelv a JavaScript nyelven írt nagy méretű alkalmazások fejlesztését kívánja megkönnyíteni. A TypeScript olyan, más nyelvekből ismert gyakori fogalmakat ad hozzá a JavaScripthez, mint például osztályok, interfészek, generikusság, és (opcionális) statikus típusosság. A JavaScript egy befoglaló halmazát képzi: minden JavaScript kód érvényes TypeScript kód, így könnyen hozzáadható meglévő projektekhez. A TypeScript fordító kimenetként JavaScript kódot állít elő. Ez a dokumentum a TypeScript által hozzáadott új szintaxissal foglalkozik, nem pedig a [JavaScripttel](../javascript/). Hogy kipróbáld a TypeScript fordítót, látogass el a [Játszótérre avagy Playground-ra](https://www.typescriptlang.org/Playground) ahol kódot írhatsz automatikus kódkiegészítéssel, és közvetlenül láthatod az előállított JavaScript kódot. ```ts // 3 alapvető típus létezik TypeScriptben var isDone: boolean = false; var lines: number = 42; var name: string = "Anders"; // Amikor nem lehet a típust előre tudni, használható az "Any" típus var notSure: any = 4; notSure = "talán mégis sztring lesz"; notSure = false; // tévedtem, mégis boolean // Kollekciókból létezik típusos és generikus tömb var list: number[] = [1, 2, 3]; // ugyanez a generikus típus használatával var list: Array = [1, 2, 3]; // Enumerált típusok: enum Color {Red, Green, Blue}; var c: Color = Color.Green; // Végül, "void" használható a visszatérési értékkel nem bíró függvényeknél function bigHorribleAlert(): void { alert("Kis idegesítő doboz vagyok!"); } // A függvények elsőrangú (first-class) típusok, használható a vastag nyilas // lambda szintaxis, // a compiler pedig kikövetkezteti a típusokat (inferred types) // A következők egyenértékűek, ugyanaz a szignatúra kerül kikövetkeztetésre, és // így ugyanaz a JavaScript kód lesz előállítva var f1 = function(i: number): number { return i * i; } // Következtetett visszatérési értékkel var f2 = function(i: number) { return i * i; } var f3 = (i: number): number => { return i * i; } // Következtetett visszatérési értékkel var f4 = (i: number) => { return i * i; } // Következtetett visszatérési értékkel, // ebben az egysoros formában nem szükséges a return kulcsszó var f5 = (i: number) => i * i; // Az interfészek szerkezeti alapon működnek, vagyis minden objektum, ahol // jelen vannak a megfelelő mezők kompatibilis az interfésszel interface Person { name: string; // Az opcionális tagokat "?" jelöli age?: number; // És persze függvények is: move(): void; } // Egy objektum, ami megvalósítja a "Person" interfészt // Tekinthető Personnek, hiszen van name és move mezője var p: Person = { name: "Bobby", move: () => {} }; // Egy objektum, ahol az opcionális mező is jelen van: var validPerson: Person = { name: "Bobby", age: 42, move: () => {} }; // Ez viszont nem Person, mert az age mező típusa nem szám! var invalidPerson: Person = { name: "Bobby", age: true }; // Az interfészekkel függvény típusok is leírhatóak: interface SearchFunc { (source: string, subString: string): boolean; } // Csak a paraméterek típusai számítanak, a neveik nem. var mySearch: SearchFunc; mySearch = function(src: string, sub: string) { return src.search(sub) != -1; } // Osztályok - a mezők alapértelmezésben publikusak class Point { // Mezők x: number; // Konstruktor - a public/private kulcsszavak ebben a kontextusban // legenerálják a mezőkhöz szükséges kódot a konstruktorban. // Ebben a példában az "y" ugyanúgy definiálva lesz, mint az "x", csak // kevesebb kóddal. // Alapértelmezett (default) értékek is megadhatóak. constructor(x: number, public y: number = 0) { this.x = x; } // Metódusok dist() { return Math.sqrt(this.x * this.x + this.y * this.y); } // Statikus mezők static origin = new Point(0, 0); } var p1 = new Point(10 ,20); var p2 = new Point(25); //y itt 0 lesz // Öröklés class Point3D extends Point { constructor(x: number, y: number, public z: number = 0) { super(x, y); // Szükséges az ősosztály konstruktorának explicit hívása } // Felülírás dist() { var d = super.dist(); return Math.sqrt(d * d + this.z * this.z); } } // Modulok // ("." használható az almodulok számára) module Geometry { export class Square { constructor(public sideLength: number = 0) { } area() { return Math.pow(this.sideLength, 2); } } } var s1 = new Geometry.Square(5); // Új lokális név definiálása a module számára import G = Geometry; var s2 = new G.Square(10); // Generikus típusok // Osztályok class Tuple { constructor(public item1: T1, public item2: T2) { } } // Interfészek interface Pair { item1: T; item2: T; } // és függvények var pairToTuple = function(p: Pair) { return new Tuple(p.item1, p.item2); }; var tuple = pairToTuple({ item1:"hello", item2:"world"}); // definíciós fájl hivatkozása: /// ``` ## További források * [TypeScript hivatalos weboldala](https://www.typescriptlang.org/) * [Forráskód GitHubon](https://github.com/microsoft/TypeScript) ================================================ FILE: hu/yaml.md ================================================ --- contributors: - ["Leigh Brenecki", "https://github.com/adambrenecki"] translators: - ["Tamás Diószegi", "https://github.com/ditam"] --- A YAML egy adat sorosító nyelv, amit úgy terveztek, hogy közvetlenül is olvasható és írható legyen emberi szemmel. A JSON formátum egy szigorú befoglaló halmazát alkotja, kiegészítve azt szintaktikai jelentéssel bíró sortörésekkel és indentációval, a Pythonhoz hasonlóan. A Pythonnal ellentétben azonban a YAML nem engedélyezi a közvetlen tab karakterek jelenlétét. Megjegyzés: UTF-8 ékezetes betűk használhatóak, ha a fájl kódlása megfelelő, a kódolást a tartalomban explicit nem kell (és nem is lehet) feltüntetni. ```yaml # A kommentek YAML-ban így néznek ki. ################## # Skalár típusok # ################## # A gyökér objektumunk (az egész dokumentumra értve) egy map, # ami a más nyelvekből ismert dictionary, hash vagy object típusokkal egyenértékű. kulcs: érték masik_kulcs: Másik érték jön ide. egy_szam: 100 tudomanyos_jelolessel: 1e+12 boolean: true null_value: null kulcs benne szóközökkel: érték # Látható, hogy a sztringeket nem szükséges idézőjelek közé zárni, bár szabad. Továbbá: "Idézőjelekkel megadott sztring." "A kulcs is lehet idézőjeles.": "Hasznos lehet, ha ':'-ot akarsz a kulcsban." # Többsoros sztringek írhatóak 'literal block'-ként ('|' jelet használva) # vagy 'folded block'-ként is ('>' jelet használva). literal_block: | Ez az egész szöveg-blokk lesz az értéke a literal_block kulcsnak, a sortöréseket megtartva. Az ilyen sztringet az indentáció visszahúzása zárja le, a behúzás pedig eltávolításra kerül. A 'még jobban' behúzott részek megtartják a behúzásukat - ezeknek a soroknak 4 szóköz behúzása lesz. folded_style: > Az az egész szöveg-blokk lesz az értéke a 'folded_style' kulcsnak, de ezúttal minden sortörés egy szóközre lesz cserélve. Az üres sorok, mint a fenti, új sor karakterre cserélődnek. A 'még jobban' behúzott sorok megtartják a sortöréseiket, - ez a szöveg két sorban jelenik meg. ###################### # Gyűjtemény típusok # ###################### # Egymásba ágyazás a behúzás változtatásával érhető el. beagyazott_map: key: value another_key: Another Value masik_beagyazott_map: hello: hello # A mapeknek nem csak sztring kulcsaik lehetnek. 0.25: lebegőpontos kulcs # A kulcsok lehetnek többsoros objektumok is, ? jellel jelezve a kulcs kezdetét ? | Ez itt egy többsoros kulcs : és ez az értéke # Szintén engedélyezett a kollekció típusok használata kulcsként, de egyéb # nyelvekben ez gyakran problémákat fog okozni. # Szekvenciák (listákkal vagy tömbökkel egyenértékűek) így néznek ki: egy_szekvencia: - Item 1 - Item 2 - 0.5 # Többféle típust is tartalmazhat - Item 4 - key: value another_key: another_value - - Ez egy szekvencia - egy másik szekvenciába ágyazva # Mivel a YAML a JSON befoglaló halmazát alkotja, JSON szintaxisú # mapek és szekvenciák is használhatóak: json_map: {"key": "value"} json_seq: [3, 2, 1, "takeoff"] ######################### # EXTRA YAML KÉPESSÉGEK # ######################### # A YAML-ben ún. 'anchor'-ök segítségével könnyen lehet duplikálni # tartalmakat a dokumentumon belül. A következő kulcsok azonos értékkel bírnak: anchored_tartalom: &anchor_neve Ez a sztring két kulcs értéke is lesz. másik_anchor: *anchor_neve # Vannak a YAML-ben tagek is, amivel explicit lehet típusokat jelölni. explicit_string: !!str 0.5 # Bizonyos implementációk nyelv-specifikus tageket tartalmaznak, mint # például ez a Python komplex szám típusának jelölésére: python_complex_number: !!python/complex 1+2j ###################### # EXTRA YAML TÍPUSOK # ###################### # Nem a sztringek és a számok az egyedüli skalár típusok YAML-ben. # ISO-formátumú dátumok és dátumot jelölő literal kifejezések is értelmezettek. datetime: 2001-12-15T02:59:43.1Z datetime_with_spaces: 2001-12-14 21:59:43.10 -5 date: 2002-12-14 # A !!binary tag jelöli, hogy egy sztring valójában base64-kódolású # reprezentációja egy bináris blob-nak gif_file: !!binary | R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= # Létezik a YAML-ban egy halmaz típus (set) is, ami így néz ki: set: ? elem1 ? elem2 ? elem3 # Mint Pythonban, a halmazok null értékekkel feltöltött mapek, vagyis a fenti # halmaz egyenértékű a következővel: set2: elem1: null elem2: null elem3: null ``` ================================================ FILE: hy.md ================================================ --- name: Hy filename: learnhy.hy contributors: - ["Abhishek L", "http://twitter.com/abhishekl"] - ["Zirak", "http://zirak.me"] --- Hy is a Lisp dialect built on top of Python. This is achieved by converting Hy code to Python's abstract syntax tree (AST). This allows Hy to call native Python code or Python to call native Hy code as well ```hylang ; Semicolon comments, like other Lisps ;; S-expression basics ; Lisp programs are made of symbolic expressions or sexps which ; resemble (some-function args) ; now the quintessential hello world (print "hello world") ;; Simple data types ; All simple data types are the same as their Python counterparts 42 ; => 42 3.14 ; => 3.14 True ; => True 4+10j ; => (4+10j) a complex number ; lets start with some simple arithmetic (+ 4 1) ;=> 5 ; the operator is applied to all arguments, like other Lisps (+ 4 1 2 3) ;=> 10 (- 2 1) ;=> 1 (* 4 2) ;=> 8 (/ 4 1) ;=> 4 (% 4 2) ;=> 0 the modulo operator ; power is represented by the ** operator, like Python (** 3 2) ;=> 9 ; nesting forms will do the expected thing (+ 2 (* 4 2)) ;=> 10 ; also logical operators and or not and equal to etc. work as expected (= 5 4) ;=> False (not (= 5 4)) ;=> True ;; Variables ; variables are set using setv, variable names can use utf-8 except ; for ()[]{}",'`;#| (setv a 42) (setv π 3.14159) (def *foo* 42) ;; Other container data types ; strings, lists, tuples & dicts ; these are exactly same as Python's container types "hello world" ;=> "hello world" ; string operations work similar to Python (+ "hello " "world") ;=> "hello world" ; lists are created using [], indexing starts at 0 (setv mylist [1 2 3 4]) ; tuples are immutable data structures (setv mytuple (, 1 2)) ; dictionaries are key value pairs (setv dict1 {"key1" 42 "key2" 21}) ; :name can be used to define keywords in Hy which can be used for keys (setv dict2 {:key1 41 :key2 20}) ; use `get' to get the element at an index/key (get mylist 1) ;=> 2 (get dict1 "key1") ;=> 42 ; Alternatively if keywords were used they can be called directly (:key1 dict2) ;=> 41 ;; Functions and other program constructs ; functions are defined using defn, the last sexp is returned by default (defn greet [name] "A simple greeting" ; an optional docstring (print "hello " name)) (greet "bilbo") ;=> "hello bilbo" ; functions can take optional arguments as well as keyword arguments (defn foolists [arg1 &optional [arg2 2]] [arg1 arg2]) (foolists 3) ;=> [3 2] (foolists 10 3) ;=> [10 3] ; you can use rest arguments and kwargs too: (defn something-fancy [wow &rest descriptions &kwargs props] (print "Look at" wow) (print "It's" descriptions) (print "And it also has:" props)) (something-fancy "My horse" "amazing" :mane "spectacular") ; you use apply instead of the splat operators: (apply something-fancy ["My horse" "amazing"] { "mane" "spectacular" }) ; anonymous functions are created using `fn' or `lambda' constructs ; which are similar to `defn' (map (fn [x] (* x x)) [1 2 3 4]) ;=> [1 4 9 16] ;; Sequence operations ; Hy has some builtin utils for sequence operations etc. ; retrieve the first element using `first' or `car' (setv mylist [1 2 3 4]) (setv mydict {"a" 1 "b" 2}) (first mylist) ;=> 1 ; slice lists using cut (cut mylist 1 3) ;=> [2 3] ; get elements from a list or dict using `get' (get mylist 1) ;=> 2 (get mydict "b") ;=> 2 ; list indexing starts from 0, same as Python ; assoc can set elements at keys/indexes (assoc mylist 2 10) ; makes mylist [1 2 10 4] (assoc mydict "c" 3) ; makes mydict {"a" 1 "b" 2 "c" 3} ; there are a whole lot of other core functions which makes working with ; sequences fun ;; Python interop ;; import works just like in Python (import datetime) (import functools [partial reduce]) ; imports partial and reduce from functools (import matplotlib.pyplot :as plt) ; imports foo as bar ; all builtin Python methods etc. are accessible from Hy ; a.foo(arg) is called as (.foo a arg) (.split (.strip "hello world ")) ;=> ["hello" "world"] ; there is a shortcut for executing multiple functions on a value called the ; "threading macro", denoted by an arrow: (-> "hello world " (.strip) (.split)) ;=> ["hello" "world] ; the arrow passes the value along the calls as the first argument, for instance: (-> 4 (* 3) (+ 2)) ; is the same as: (+ (* 4 3) 2) ; there is also a "threading tail macro", which instead passes the value as the ; second argument. compare: (-> 4 (- 2) (+ 1)) ;=> 3 (+ (- 4 2) 1) ;=> 3 ; to: (->> 4 (- 2) (+ 1)) ;=> -1 (+ 1 (- 2 4)) ;=> -1 ;; Conditionals ; (if condition (body-if-true) (body-if-false) (if (= passcode "moria") (print "welcome") (print "Speak friend, and Enter!")) ; nest multiple if else if clauses with cond (cond (= someval 42) (print "Life, universe and everything else!") (> someval 42) (print "val too large") (< someval 42) (print "val too small")) ; group statements with do, these are executed sequentially ; forms like defn have an implicit do (do (setv someval 10) (print "someval is set to " someval)) ;=> 10 ; create lexical bindings with `let', all variables defined thusly ; have local scope (let [nemesis {"superman" "lex luther" "sherlock" "moriarty" "seinfeld" "newman"}] (for [[h v] (.items nemesis)] (print (.format "{0}'s nemesis was {1}" h v)))) ;; Classes ; classes are defined in the following way (defclass Wizard [object] (defn __init__ [self spell] (setv self.spell spell)) (defn get-spell [self] self.spell)) ``` ### Further Reading This tutorial is just a basic introduction to Hy/Lisp/Python. Hy docs are here: [https://hylang.org/hy/doc](https://hylang.org/hy/doc) Hy's GitHub repo: [https://github.com/hylang/hy](https://github.com/hylang/hy) On freenode IRC `#hy`, twitter hashtag #hylang ================================================ FILE: id/asciidoc.md ================================================ --- contributors: - ["Ryan Mavilia", "http://unoriginality.rocks/"] translators: - ["Rizky Luthfianto", "http://github.com/rilut"] --- AsciiDoc adalah bahasa markup yang mirip dengan Markdown dan dapat digunakan untuk apa saja, untuk menulis buku maupun blog. Dibuat pada tahun 2002 oleh Stuart Rackham, bahasa ini sederhana tetapi memungkinkan sejumlah besar kustomisasi. Kepala Dokumen Kepala Dokumen adalah opsional dan tidak dapat berisi baris kosong. Harus diimbangi konten, setidaknya satu baris kosong. Hanya Judul ``` = Judul Dokumen Kalimat pertama dokumen. ``` Judul dan Penulis ``` = Judul Dokumen Pertama terakhir Awal dokumen ini. ``` Banyak Penulis ``` = Judul Dokumen John Doe ; Jane Doe ; Black Beard Memulai dokumen dengan banyak penulis. ``` Garis Revisi (membutuhkan garis penulis) ``` = Judul Dokumen V1 Manusia Kentang v1.0, 2016/01/13 Artikel tentang keripik ini akan menjadi menyenangkan. ``` Paragraf ``` Anda tidak perlu sesuatu yang istimewa untuk paragraf. Tambahkan baris kosong antara paragraf untuk memisahkan mereka. Untuk membuat baris kosong, tambahkan: + dan Anda akan mendapat satu baris kosong! ``` Memformat Teks ``` _underscore menciptakan miring_ *Tanda bintang untuk tebal* *_Gabungkan biar makin asyik_* `Penggunaan tanda petik untuk menandakan monospace` `*Monospace tebal*` ``` Judul bagian ``` = Level 0 (hanya dapat digunakan dalam header dokumen) == Level 1

=== Level 2

==== Level 3

===== Level 4

``` Daftar Untuk membuat daftar bullet, gunakan tanda bintang. ``` * foo * bar * baz ``` Untuk membuat daftar bernomor, gunakan titik. ``` . Item 1 . item 2 . Item 3 ``` Anda bisa membuat daftar bersarang dengan menambahkan tanda bintang atau titik tambahan hingga lima kali. ``` * Foo 1 ** Foo 2 *** Foo 3 **** Foo 4 ***** Foo 5 . foo 1 .. Foo 2 ... Foo 3 .... Foo 4 ..... Foo 5 ``` ================================================ FILE: id/bf.md ================================================ --- filename: brainfuck.bf contributors: - ["Prajit Ramachandran", "http://prajitr.github.io/"] - ["Mathias Bynens", "http://mathiasbynens.be/"] translators: - ["Muhammad Rifqi Fatchurrahman", "http://muhrifqii.github.io/"] --- Brainfuck (tidak dalam huruf kapital kecuali pada awal kalimat) adalah sebuah bahasa pemrograman Turing-complete yang sangat minim yang hanya memiliki 8 perintah. Anda bisa mencoba brainfuck pada browser dengan menggunakan [brainfuck-visualizer](http://fatiherikli.github.io/brainfuck-visualizer/). ```bf Karakter apapun selain "><+-.,[]" (tanda kutip tidak termasuk) diabaikan. Brainfuck direpresentasikan dengan sebuah array yang memiliki 30,000 cell yang diinisialisasi dengan nol dan pointer data yang menunjuk ke current cell. Terdapat delapan perintah: + : Menaikkan nilai pada current cell sebesar satu. - : Menurunkan nilai pada current cell sebesar satu. > : Menggeser pointer data ke cell selanjutnya (cell sebelah kanan). < : Menggeser pointer data ke cell sebelumnya (cell sebelah kiri). . : Mencetak nilai ASCII pada current cell (misal 65 = 'A'). , : Membaca sebuah karakter masukan tunggal ke dalam current cell. [ : Jika nilai pada current cell bernilai nol, lewati hingga mencapai ] yang sesuai. Jika tidak, pindah ke instruksi berikutnya. ] : Jika nilai pada current cell bernilai nol, pindah ke instruksi berikutnya. Jika tidak, mundur pada instruksi hingga mencapai [ yang sesuai. [ dan ] membentuk sebuah rekursi while. Tentu saja mereka harus seimbang. Mari kita lihat beberapa program brainfuck dasar. ++++++ [ > ++++++++++ < - ] > +++++ . Program ini mencetak huruf 'A'. Mula-mula, cell #1 dinaikkan ke 6. Cell #1 akan digunakan untuk rekursi. Lalu, masuk ke rekursi ([) dan pindah ke cell #2. Cell #2 dinaikkan 10 kali, mundur ke cell #1, dan menurunkan cell #1. Rekursi ini berlangsung 6 kali (melakukan 6 penurunan nilai untuk cell #1 hingga mencapai 0, di titik mana dia melewati hingga mencapai ] dan terus berlanjut). Pada titik ini, kita berada pada cell #1, yang memiliki nilai 0, sedangkan cell #2 memiliki sebuah nilai 60. Kita berpindah ke cell #2, menaikkan nilai 5 kali, memunculkan nilai 65, lalu cetak nilai pada cell #2. 65 adalah 'A' pada ASCII, jadi 'A' dicetak ke terminal. , [ > + < - ] > . Program ini membaca sebuah karakter dari masukan user dan menyalin karakternya ke cell #1. Setelah itu rekursi dimulai. Geser ke cell #2, menaikkan nilai pada cell #2, mundur ke cell #1, dan menurunkan nilai pada cell #1. Hal ini berlanjut sampai cell #1 bernilai 0, dan cell #2 menyimpan nilai lama dari cell #1. Karena kita berada di cell #1 saat ujung rekursi, geser ke cell #2, lalu cetak nilai dalam bentuk ASCII. Perlu diingat bahwa spasi itu murni untuk memudahkan membaca. Anda bisa menuliskannya dengan mudah seperti: ,[>+<-]>. Coba dan cari tahu apa yang program ini lakukan: ,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> Program ini menerima dua buah angka sebagai input, lalu mengalikannya. Intinya adalah membaca dua masukan. Lalu mulai pada rekursi terluar yang kondisinya pada cell #1. Lalu pindah ke cell #2, dan mulai rekursi terdalam yang kondisinya ada pada cell #2, menaikkan nilai pada cell #3. Namun, ada suatu masalah: Pada akhir dari rekursi terdalam, cell #2 bernilai nol. Pada kasus tersebut, rekursi terdalam tidak dapat bekerja lagi mulai setelah ini. Untuk menyelesaikan masalah tersebut, kita juga menaikkan cell #4, dan menyalin ulang cell #4 ke cell #2. Maka cell #3 adalah hasilnya. ``` Dan itulah brainfuck. Tidak terlalu sulit kan? Hanya untuk iseng-iseng, anda bisa menuliskan porgram brainfuck anda sendiri, atau anda bisa menuliskan interpreter brainfuck pada bahasa lain. Interpreternya tidak begitu sulit untuk diimplementasikan, tapi jika anda seorang masokis, cobalah menulis sebuah interpreter brainfuck... dalam brainfuck. ================================================ FILE: id/coffeescript.md ================================================ --- contributors: - ["Tenor Biel", "http://github.com/L8D"] - ["Xavier Yao", "http://github.com/xavieryao"] translators: - ["Rizky Luthfianto", "http://github.com/rilut"] --- CoffeeScript adalah bahasa sederhana yang diterjemahkan saat kompilasi ke dalam JavaScript, dan bukan diterjemahkan pada saat *runtime*. CoffeeScript mencoba agar kode JavaScript yang dihasilkan tetap mudah dibaca dan kompatibel dengan semua *runtime* JavaScript. Lihat juga [website CoffeeScript](http://coffeescript.org/) yang memiliki tutorial lengkap tentang CoffeeScript. ```coffeescript # CoffeeScript adalah bahasa hipster. # Mengikuti tren bahasa modern lainnya. # Sehingga, seperti Ruby dan Python, untuk komentar digunakan tanda pagar. ### Ini adalah contoh blok komentar, yang nanti diterjemahkan langsung ke '/ *' dan '* /' pada kode JavaScript yang dihasilkan. Anda diharapkan sedikit memahami semantik JavaScript sebelum melanjutkan tutorial ini. ### # Pengisian nilai variabel: angka = 42 #=> var angka = 42; kebalikan = true #=> var kebalikan = true; # Kondisi: angka = -42 if kebalikan #=> if(kebalikan) { angka = -42; } # Fungsi: kuadrat = (x) -> x * x #=> var kuadrat = function(x) { return x * x; } isi = (wadah, cairan = "kopi") -> "Mengisi #{wadah} dengan #{cairan}..." #=>var isi; # #isi = function(wadah, cairan) { # if (cairan == null) { # cairan = "kopi"; # } # return "Mengisi " + wadah + " dengan " + cairan + "..."; #}; # Rentang: list = [1..5] # => var list = [1, 2, 3, 4, 5]; # Objek: fungsi_matematika = akar: Math.sqrt kuadrat: kuadrat kubik: (x) -> x * kuadrat x #=> var fungsi_matematika = { # "akar": Math.sqrt, # "kuadrat": kuadrat, # "kubik": function(x) { return x * kuadrat(x); } # }; # *Splat*: balapan = (pemenang, pelari...) -> print pemenang, pelari #=>balapan = function() { # var pelari, pemenang; # pemenang = arguments[0], pelari = 2 <= arguments.length ? __slice.call(arguments, 1) : []; # return print(pemenang, pelari); # }; # Cek keberadaan: alert "Elvis ada!" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("Elvis ada!"); } # Komprehensi *array*: kubik_kubik = (fungsi_matematika.kubik angka for angka in list) #=>kubik_kubik = (function() { # var _i, _len, _hasil; # _hasil = []; # for (_i = 0, _len = list.length; _i < _len; _i++) { # angka = list[_i]; # _hasil.push(fungsi_matematika.kubik(angka)); # } # return _hasil; #})(); sayur_sayuran = ['brokoli', 'bayam', 'kemangi'] makan sayuran for sayuran in sayur_sayuran when sayuran isnt 'kemangi' #=>sayur_sayuran = ['brokoli', 'bayam', 'kemangi']; # #for (_k = 0, _len2 = sayur_sayuran.length; _k < _len2; _k++) { # sayuran = sayur_sayuran[_k]; # if (sayuran !== 'kemangi') { # makan(sayuran); # } #} ``` ## Referensi Tambahan - [Smooth CoffeeScript (EN)](http://autotelicum.github.io/Smooth-CoffeeScript/) - [CoffeeScript Ristretto (EN)](https://leanpub.com/coffeescript-ristretto/read) ================================================ FILE: id/css.md ================================================ --- contributors: - ["Mohammad Valipour", "https://github.com/mvalipour"] translators: - ["Eka Y Saputra", "http://github.com/ekajogja"] --- Pada mulanya, web tidak memiliki elemen visual, murni teks saja. Tapi seiring perkembangan peramban, laman web dengan elemen visual menjadi umum. CSS adalah bahasa standar yang ada untuk menjaga keterpisahan antara konten (HTML) serta tampilan-dan-kesan laman web. Singkatnya, fungsi CSS ialah menyajikan sintaks yang memampukan kita untuk memilih elemen tertentu dalam sebuah laman HTML dan menerapkan berbagai properti visual bagi elemen tersebut. Seperti bahasa lainnya, CSS memiliki banyak versi. Di artikel ini, kita fokus pada CSS2.0 - yang meskipun bukan versi termutakhir namun paling kompatibel dan didukung secara luas. **CATATAN:** Lantaran keluaran dari CSS berwujud efek-efek visual, maka untuk mempelajarinya, kita perlu mencoba berbagai hal dalam dunia olah CSS semisal [dabblet](http://dabblet.com/). Fokus utama artikel ini ialah pada sintaks dan sejumlah tips umum. ```css /* komentar terletak diantara sepasang tanda garis miring dan bintang, persis seperti larik ini! */ /* #################### ## SELEKTOR ####################*/ /* Secara garis besar, statemen utama dalam CSS sangat sederhana */ selektor { properti: nilai; /* properti lainnya */ } /* selektor berfungsi untuk memilih suatu elemen dalam sebuah laman. Kita juga bisa memilih semua elemen di sebuah halaman! */ * { color:red; } /* Dengan menentukan sebuah elemen seperti ini pada sebuah laman:
*/ /* kita bisa memilih elemen berdasarkan nama class-nya */ .suatu-class { } /*atau dengan dua class sekaligus! */ .suatu-class.class2 { } /* atau dengan nama tag-nya */ div { } /* atau id-nya */ #suatuId { } /* atau - jika ada - dengan attribute-nya! */ [attr] { font-size:smaller; } /* atau jika attribute tersebut memiliki nilai spesifik */ [attr='nilai'] { font-size:smaller; } /* dibuka dengan sebuah nilai*/ [attr^='nil'] { font-size:smaller; } /* atau ditutup dengan nilai */ [attr$='ai'] { font-size:smaller; } /* atau bahkan disisipi nilai */ [attr~='la'] { font-size:smaller; } /* dan yang lebih penting lagi, kita bisa mengombinasikannya sekaligus dengan syarat tidak ada spasi diantara selektor-selektor. sebab adanya spasi akan membuat selektor itu memiliki makna yang berbeda.*/ div.suatu-class[attr$='ai'] { } /* kita juga bisa memilih sebuah elemen berdasarkan posisi elemen induknya.*/ /*sebuah elemen yang merupakan anak langsung dari elemen induk (diseleksi dng cara yang sama) */ div.suatu-induk > .-suatu-class {} /* atau salah satu induk elemennya dalam hirarki elemen */ /* berikut ini dimaksudkan pada elemen manapun dengan class "class-entah" dan merupakan anak elemen dari suatu div dengan class "induk-entah" PADA LEVEL HIRARKI MANAPUN */ div.suatu-induk .suatu-class {} /* peringatan: selektor yang sama jika tanpa ada spasi akan bermakna lain. misalnya? */ div.suatu-induk.suatu-class {} /* kita juga bisa memilih sebuah elemen berdasarkan saudara elemen yang muncul tepat sebelumnya */ .aku-muncul-tepat-sebelum + .elemen-ini { } /*atau saudara elemen manapun yang pernah muncul selang beberapa elemen sebelumnya */ .aku-pernah-muncul-sebelum ~ .elemen-ini {} /* Ada beberapa pseudo-class yang memampukan kita memilih suatu elemen berdasarkan perilaku lamannya (bukan struktur lamannya) */ /* semisal ketika sebuah elemen ditimpa hover (pointer mouse) */ :hover {} /* atau link yang sudah pernah diklik*/ :visited {} /* atau link yang belum pernah diklik*/ :link {} /* atau elemen input yang menjadi fokus */ :focus {} /* #################### ## PROPERTI ####################*/ selektor { /* Unit */ width: 50%; /* dalam persen */ font-size: 2em; /* angka kali jumlah font-size saat ini */ width: 200px; /* dalam pixel */ font-size: 20pt; /* dalam point */ width: 5cm; /* dalam centimeter */ width: 50mm; /* dalam milimeter */ width: 5in; /* dalam inci */ /* Warna */ background-color: #F6E; /* dalam short hex */ background-color: #F262E2; /* dalam format long hex */ background-color: tomato; /* warna yang sudah punya konvensi nama */ background-color: rgb(255, 255, 255); /* dalam rgb */ background-color: rgb(10%, 20%, 50%); /* dalam persen rgb */ background-color: rgba(255, 0, 0, 0.3); /* dalam rgb semi-transparan*/ /* Gambar */ background-image: url(/folder-gambar/image.jpg); /* Font */ font-family: Arial; font-family: "Courier New"; /* jika nama font memiliki spasi, ia diketik dalam tanda petik ganda */ font-family: "Courier New", Trebuchet, Arial; /* jika font pertama tidak ditemukan, peramban menggunakan font berikutnya, demikian secara berturut-turut */ } ``` ## Penggunaan Simpan semua CSS yang hendak kita pakai dengan ekstensi `.css`. ```xml
``` ## Prioritas Kita tahu bahwa sebuah elemen bisa dipilih dengan lebih dari satu selektor, serta bisa diberi lebih dari satu properti. Dalam kasus seperti ini, hanya salah satu properti saja yang akan diterapkan pada elemen dengan prioritas tertentu. Dengan susunan CSS: ```css /*A*/ p.class1[attr='nilai'] /*B*/ p.class1 {} /*C*/ p.class2 {} /*D*/ p {} /*E*/ p { properti: nilai !important; } ``` dan susunan markup: ```xml

``` Maka prioritas penerapan style-nya ialah sbb.: Ingat, penerapan ini untuk masing-masing **properti**, bukan keseluruhan larik. * `E` prioritas pertama sebab ada kata `!important`. Dianjurkan untuk menghindari kata ini jika tidak benar-benar perlu. * `F` prioritas kedua sebab ia diketik secara inline. * `A` prioritas ketiga sebab selektor ini lebih spesifik dibanding yang lain. lebih spesifik = lebih banyak unsur selektor. contoh ini punya 3 unsur: 1 tagname `p` + 1 nama class `class1` + 1 attribute `attr='nilai'` * `C` prioritas berikutnya sebab meski sama spesifik dengan `B` namun ia muncul lebih akhir. * Lalu `B` * dan terakhir baru `D`. ## Kompatibilitas Sebagian besar fitur dalam CSS2 (dan lambat laun juga CSS3) kompatibel dengan semua peramban dan perangkat. Namun selalu vital untuk memastikan kompatibilitas unsur dan nilai yang kita ketikkan dalam CSS dengan peramban yang ditargetkan. [QuirksMode CSS](http://www.quirksmode.org/css/) ialah salah satu sumber terbaik untuk memeriksa kompatibilitas CSS dan peramban. ## Referensi Lanjut * [Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade](http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/) * [QuirksMode CSS](http://www.quirksmode.org/css/) * [Z-Index - The stacking context](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context) ================================================ FILE: id/hq9+.md ================================================ --- contributors: - ["Alexey Nazaroff", "https://github.com/rogaven"] translators: - ["Haydar Ali Ismail", "http://github.com/haydarai"] --- HQ9+ adalah bahasa pemrograman gurauan yang dibuat oleh Cliff Biffle. Bahasa ini hanya memiliki empat perintah dan tidak memenuhi Turing-complete. ``` Hanya ada 4 perintah, masing-masing direpresentasikan oleh karakter berikut H: mencetak "Hello, world!" Q: mencetak kode sumber dari program ini (Quine) 9: mencetak lirik dari lagu "99 Bottles of Beer" +: menambah nilai satu ke akumulator (nilai dari akumulator tidak dapat diakses) Karakter lain akan dihiraukan. Ok. Mari kita menulis beberapa program: HQ9 Hasil: Hello world! HQ9 HQ9+ sangat sederhana, tetapi membuat anda bisa melakukan hal yang sangat sulit dilakukan di bahasa lain. Sebagai contoh, berikut sebuah program yang menciptakan tiga salinan dirinya sendiri ke layar: QQQ Ini menghasilakn: QQQ QQQ QQQ ``` Dan itu semuanya. Ada banyak interpreters untuk HQ9+. Kamu bisa menemukannya di bawah + [Salah satu interpreter online](https://almnet.de/esolang/hq9plus.php) + [Website resmi HQ9+](http://cliffle.com/esoterica/hq9plus.html) ================================================ FILE: id/java.md ================================================ --- contributors: - ["Jake Prather", "http://github.com/JakeHP"] - ["Jakukyo Friel", "http://weakish.github.io"] - ["Madison Dickson", "http://github.com/mix3d"] - ["Simon Morgan", "http://sjm.io/"] - ["Zachary Ferguson", "http://github.com/zfergus2"] - ["Cameron Schermerhorn", "http://github.com/cschermerhorn"] - ["Rachel Stiyer", "https://github.com/rstiyer"] translators: - ["Ahmad Zafrullah", "https://github.com/23Pstars"] --- Java adalah bahasa pemrograman yang memiliki tujuan umum dan berorientasi kelas dan objek. [Baca lebih lanjut.](http://docs.oracle.com/javase/tutorial/java/) ```java // Komentar satu baris diawali dengan // (dua garis miring) /* Ini adalah contoh komentar banyak-baris. */ /** Ini adalah contoh komentar JavaDoc. Digunakan untuk mendeskripsikan sebuah kelas, atau beberapa sifat dari kelas tersebut. */ // Menyertakan kelas ArrayList dalam paket java.util import java.util.ArrayList; // Menyertakan semua kelas yang ada dalam paket java.security import java.security.*; // Setiap dokumen .java sebuah kelas publik dengan nama yang sama dengan nama kelas. public class BelajarJava { // Untuk menjalankan program java, program harus memiliki sebuah method utama (main) sebagai awalan. public static void main (String[] args) { // System.out.println() digunakan untuk menampilkan satu baris teks. System.out.println("Halo Dunia!"); System.out.println( "Integer: " + 10 + " Double: " + 3.14 + " Boolean: " + true); // System.out.print() hanya menampilkan teks tanpa baris baru. System.out.print("Halo "); System.out.print("Dunia"); // System.out.printf() memudahkan dalam mengatur format penampilan. System.out.printf("pi = %.5f", Math.PI); // => pi = 3.14159 /////////////////////////////////////// // Variabel /////////////////////////////////////// /* * Deklarasi Variabel */ // Deklarasi variabel menggunakan format int nilai; // Deklarasi banyak variabel menggunakan format yang sama , , int nilai1, nilai2, nilai3; /* * Inisialisasi Variabel */ // Inisialisasi sebuah variabel menggunakan = int nilai = 1; // Inisialisasi banyak variabel menggunakan format yang sama , , = int nilai1, nilai2, nilai3; nilai1 = nilai2 = nilai3 = 1; /* * Tipe Variabel */ // Byte - 8 bit signed untuk bilangan bulat komplemen 2 // (-128 <= byte <= 127) byte nilaiByte = 100; // Short - 8 bit signed untuk bilangan bulat komplemen 2 // (-32,768 <= short <= 32,767) short nilaiShort = 10000; // Integer - 32 bit signed untuk bilangan bulat komplemen 2 // (-2,147,483,648 <= int <= 2,147,483,647) int nilaiInt = 1; // Long - 64 bit signed untuk bilangan bulat komplemen 2 // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) long nilaiLong = 100000L; // Karakter "L" pada akhir nilai menyatakan tipe Long; // selainnya akan dianggap sebagai nilai bilangan bulat. // Catatan: Java tidak memiliki tipe unsigned. // Float - Presisi-satu 32-bit standar IEEE 754 untuk Floating Point // 2^-149 <= float <= (2-2^-23) * 2^127 float nilaiFloat = 234.5f; // Karakter "f" atau "F" pada akhir nilai menyatakan tipe Float; // selainnya akan dianggap sebagai nilai double. // Double - Presisi-dua 64-bit standar IEEE 754 untuk Floating Point // 2^-1074 <= x <= (2-2^-52) * 2^1023 double nilaiDouble = 123.4; // Boolean - true & false boolean nilaiBoolean = true; boolean nilaiBoolean = false; // Char - Sebuah karakter Unicode 16-bit char nilaiChar = 'A'; // Variabel "final" tidak dapat di-set kembali nilainya pada objek lain, final int WAKTU_SAYA_BEKERJA_TIAP_MINGGU = 9001; // tapi dapat dilakukan inisialisasi diwaktu yang lain. final double E; E = 2.71828; // BigInteger - Bilangan bulat yang memiliki presisi dinamis // // BigInteger adalah tipe data yang memungkinkan pembuat program untuk memanipulasi // bilangan bulat lebih panjang dari 64-bit. Bilangan bulat tersebut tersimpan dalam // bentuk kumpulan byte (array) dan dimanipulasi menggunakan fungsi yang sudah tersedia // pada BigInteger // // BigInteger dapat diinisialisasi menggunakan kumpulan byte atau teks. BigInteger nilaiBigInteger = new BigInteger(kumpulanByte); // BigDecimal - Bilangan signed desimal yang memiliki presisi dinamis // // Tipe BigDecimal memiliki dua bagian: sebuah bilangan bulat dengan nilai presisi // dinamis tanpa skala dan sebuah bilangan bulat skala 32-bit. // BigDecimal memungkinkan pembuat program untuk memegang kontrol penuh // terhadap batas desimal. BigDecimal baik digunakan untuk nilai tukar mata uang // dimana sangat mementingkan presisi nilai desimal. // // BigDecimal dapat diinisialisasi dengan int, long, double, String, // atau dengan melakukan inisialisasi nilai tanpa skala (BigInteger) // dan nilai dengan skala (int). BigDecimal nilaiBigDecimal = new BigDecimal(nilaiBigInteger, nilaiInt); // Perlu diperhatikan konstruktor yang digunakan apakah float atau double // karena dapat mengakibatkan ketidak-akurasian float/double yang akan digunakan // dalam BigDecimal. Sebaiknya gunakan nilai String pada konstruktor // jika membutuhkan nilai pasti. BigDecimal sepuluhSen = new BigDecimal("0.1"); // Strings String nilaiString1 = "Ini adalah contoh String!"; // Karakter \n berfungsi untuk membuat baris baru String nilaiString2 = "Menampilkan baris baru?\nTidak masalah!"; // Karakter \t berfungsi untuk membuat tab antar karakter String nilaiString3 = "Ingin menambahkan sebuah tab?\tTidak masalah!"; System.out.println(nilaiString1); System.out.println(nilaiString2); System.out.println(nilaiString3); // Larik (array) // Ukuran array harus ditentukan ketika instansiasi // Format berikut adalah beberapa cara deklarasi array // [] = new []; // [] = new []; int[] barisAngka = new int[10]; String[] barisString = new String[1]; boolean barisBoolean[] = new boolean[100]; // Cara lain untuk mendeklarasikan dan menginisialisasi sebuah array int[] y = {9000, 1000, 1337}; String nama[] = {"Andi", "Budi", "Agus"}; boolean bools[] = new boolean[] {true, false, false}; // Indeks sebuah array - Mengakses sebuah elemen System.out.println("barisAngka @ 0: " + barisAngka[0]); // Array menggunakan indeks 0 yang tetap. barisAngka[1] = 1; System.out.println("barisAngka @ 1: " + barisAngka[1]); // => 1 // Lainnya yang perlu diketahui // ArrayLists - Sama seperti array biasa, namum penggunaannya sudah ditentukan, // dan ukurannya dapat berubah-ubah. // LinkedLists - Implementasi dari doubly-linked list. Semua operasi yang digunakan // hampir sama dengan operasi yang dimiliki oleh sebuah doubly-linked list. // Maps - Sebuah kumpulan objek yang menyatakan hubungan antara kunci dan nilai. Map merupakan // sebuah interface sehingga tidak dapat diinstansiasi. Jenis kunci dan nilai yang digunakan // pada Map harus spesifik pada saat instansiasi ketika diimplementasikan pada sebuah kelas. // Setiap kunci hanya memiliki sebuah nilai, dan hanya muncul sekali. // HashMaps - Kelas ini menggunakan tabel-hash untuk mengimplementasikan interface Map. // Hal ini memungkinkan waktu eksekusi ketika melakukan operasi dasar (mengakses // dan menambahkan elemen) menjadi konstan, meskipun memiliki banyak set data. /////////////////////////////////////// // Operator /////////////////////////////////////// System.out.println("\n->Operator"); int i1 = 1, i2 = 2; // Cara singkat untuk deklarasi banyak nilai // Kemudahan dalam artimatika System.out.println("1+2 = " + (i1 + i2)); // => 3 System.out.println("2-1 = " + (i2 - i1)); // => 1 System.out.println("2*1 = " + (i2 * i1)); // => 2 System.out.println("1/2 = " + (i1 / i2)); // => 0 (int/int menghasilkan int juga) System.out.println("1/2 = " + (i1 / (double)i2)); // => 0.5 // Modulus System.out.println("11%3 = "+(11 % 3)); // => 2 // Operator Perbandingan System.out.println("3 == 2? " + (3 == 2)); // => false System.out.println("3 != 2? " + (3 != 2)); // => true System.out.println("3 > 2? " + (3 > 2)); // => true System.out.println("3 < 2? " + (3 < 2)); // => false System.out.println("2 <= 2? " + (2 <= 2)); // => true System.out.println("2 >= 2? " + (2 >= 2)); // => true // Operator Boolean System.out.println("3 > 2 && 2 > 3? " + ((3 > 2) && (2 > 3))); // => false System.out.println("3 > 2 || 2 > 3? " + ((3 > 2) || (2 > 3))); // => true System.out.println("!(3 == 2)? " + (!(3 == 2))); // => true // Operator Bitwise /* ~ Unary bitwise complement << Signed left shift >> Signed/Arithmetic right shift >>> Unsigned/Logical right shift & Bitwise AND ^ Bitwise exclusive OR | Bitwise inclusive OR */ // Peningkatan int i = 0; System.out.println("\n->Pengurangan/Peningkatan"); // Operator ++ dan -- masing-masing melakukan peningkatan dan penurunan 1 nilai. // Jika diletakkan sebelum variabel, maka akan di tambah/kurang 1 sebelum dilakukan perintah lainnya; // jika setelah variabel, maka akan ditambah/kurang 1 setelah dilakukan perintah lainnya; System.out.println(i++); // i = 1, prints 0 (peningkatan setelahnya) System.out.println(++i); // i = 2, prints 2 (peningkatan sebelumnya) System.out.println(i--); // i = 1, prints 2 (pengurangan setelahnya) System.out.println(--i); // i = 0, prints 0 (pengurangan sebelumnya) /////////////////////////////////////// // Struktur Kontrol /////////////////////////////////////// System.out.println("\n->Struktur Kontrol"); // Perintah "if" hampir sama dengan bahasa C int j = 10; if (j == 10) { System.out.println("Saya ditampilkan"); } else if (j > 10) { System.out.println("Saya tidak ditampilkan"); } else { System.out.println("Saya juga tidak ditampilkan"); } // Perulangan "while" int fooWhile = 0; while(fooWhile < 100) { System.out.println(fooWhile); // Tingkatkan penghitung // 100 kali iterasi, fooWhile 0,1,3,...,99 fooWhile++; } System.out.println("Nilai fooWhile: " + fooWhile); // Perulangan "do...while" int fooDoWhile = 0; do { System.out.println(fooDoWhile); // Tingkatkan penghitung // 99 kali iterasi, fooDoWhile 0->99 fooDoWhile++; } while(fooDoWhile < 100); System.out.println("Nilai fooDoWhile: " + fooDoWhile); // Perulangan "for" // Struktur perulangan "for" => for(; ; ) for (int fooFor = 0; fooFor < 10; fooFor++) { System.out.println(fooFor); // 10 kali iterasi, foofor 0-9 } System.out.println("Nilai fooFor: " + fooFor); // Perulangan "for" bertingkat dengan label "exit" outer: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; // Menghentikan semua perulangan, tidak hanya perulangan bagian dalam saja } } } // Perulangan "for each" // Perulangan "for" juga dapat melakukan iterasi terhadap larik (array) dari objek // yang mana mengimplementasikan interface Ieterable. int[] fooList = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // Struktur perulangan "for each" => for ( : ) // dibaca: setiap elemen dalam iterable // catatan: tipe objek harus sama dengan tipe iterable for (int bar : fooList) { System.out.println(bar); // Melakukan interasi sebanyak 9 kali dan menampilkan 1-9 tiap baris } // "switch case" // "switch" dapat digunakan pada byte, short, char, dan tipe data bilangan bulat (int). // "switch" juga dapat digunakan pada tipe "enum" (dijelaskan nanti), kelas String, // dan beberapa kelas khusus yang mengandung tipe data primitif: // Character, Byte, Short, dan Integer. int bulan = 3; String bulanString; switch (bulan) { case 1: bulanString = "Januari"; break; case 2: bulanString = "Februari"; break; case 3: bulanString = "Maret"; break; default: bulanString = "Bulan lainnya"; break; } System.out.println("Hasil switch case: " + bulanString); // Mulai dari Java 7 keatas, "switch" memiliki format: String jawabanSaya = "mungkin"; switch(jawabanSaya) { case "ya": System.out.println("Anda menjawab ya."); break; case "tidak": System.out.println("Anda menjawab tidak."); break; case "mungkin": System.out.println("Anda menjawab mungkin."); break; default: System.out.println("Anda menjawab " + jawabanSaya); break; } // Pengkondisian dengan cara singkat // Karakter '?' dapat digunakan untuk penilaian atau logika secara cepat antara dua pernyataan. // Dibaca "Jika (pernyataan) adalah benar, gunakan , sisanya gunakan int foo = 5; String bar = (foo < 10) ? "A" : "B"; System.out.println(bar); // Menampilkan A, karena pernyataannya benar //////////////////////////////////////// // Konversi Data dan Tipe Data (Typecasting) //////////////////////////////////////// // Konversi Data // Konversi String ke Integer Integer.parseInt("123"); // menghasilkan nilai versi Integer dari "123" // Konversi Integer ke String Integer.toString(123); // menghasilkan nilai versi String dari 123 // Untuk konversi lainnya silakan coba kelas berikut: // Double // Long // String // Typecasting // Objek dalam Java juga dapat dikonversi, banyak penjelasan dan aturan // dengan beberapa konsep sederhana. Silakan cek di alamat berikut: // http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html /////////////////////////////////////// // Kelas dan Fungsi /////////////////////////////////////// System.out.println("\n->Kelas & Fungsi"); // (penjelasan mengenai kelas "Sepeda" ada dibawah) // Gunakan "new" untuk melakukan instansiasi pada kelas Sepeda laju = new Sepeda(); // Memanggil method objek laju.tambahKecepatan(3); // Dapat juga digunakan "setter" dan "getter" method laju.setIrama(100); // Method "toString()" menghasilkan representasi string dari objek. System.out.println("informasi jalur: " + laju.toString()); // Dua Pasang Inisialisasi // Bahasa Java tidak memiliki sintaks untuk membuat koleksi dari "static" sekaligus // dengan mudah, kecuali dengan cara berikut: private static final Set NEGARA = new HashSet(); static { validCodes.add("INDONESIA"); validCodes.add("MALAYSIA"); validCodes.add("SINGAPURA"); } // Terdapat cara yang baik untuk menulis skrip dengan mudah, // dengan menggunakan Dua-Kurung Kurawal Inisialisasi (Double Brace Initialization) private static final Set NEGARA = new HashSet() {{ add("INDONESIA"); add("MALAYSIA"); add("SINGAPURA"); }} // Kurung kurawal pertama membuat AnonymousInnerClass dan yang kedua // mendeklarasikan instance initializer block. Blok ini dipanggil saat // kelas anonim dibuat. Namun, ini dianggap sebagai "anti-pattern": // setiap penggunaan membuat file kelas baru yang menambah beban memori // (Metaspace) dan berisiko menyebabkan kebocoran memori (memory leak). // Gunakan Set.of() untuk Java 9+. } // Akhir dari method utama } // Akhir dari kelas BelajarJava // Kelas bukan-"public" lainnya dapat dimasukkan kedalam satu dokumen .java, // namun tidak dianjurkan, sebaiknya memisahkan menjadi beberapa dokumen terpisah. // Sintaks pendeklarasian kelas: // class { // // isi data, konstruktor, dan fungsi. // // dalam Java, fungsi biasa disebut juga "method" // } class Sepeda { // Variabel dari kelas Sepeda public int irama; // Public: dapat diakses dari manapun private int kecepatan; // Private: hanya dapat diakses dari dalam kelas protected int rodaGigi; // Protected: dapat diakses dari dalam kelas dan turunan kelas String nama; // Default: hanya dapat diakses kelas yang berada dalam paket yang sama static String namaKelas; // Variabel "static" // Blok Static // Java tidak memiliki implementasi untuk konstruktor "static", namun // memiliki blok status yang dapat digunakan untuk inisialisasi variabel // dalam kelas (variabel "static"). // Blok ini akan dipanggil secara otomatis ketika kelas dijalankan. static { namaKelas = "Sepeda"; } // Konstruktor adalah salah satu cara untuk membuat kelas // Ini adalah bagian konstruktor public Sepeda() { // Dapat juga dipanggil konstruktor lainnya: // this(1, 50, 5, "Bontrager"); rodaGigi = 1; irama = 50; kecepatan = 5; nama = "Bontrager"; } // Ini adalah bagian konstruktor yang menggunakan argumen (parameter) public Sepeda(int iramaAwal, int kecepatanAwal, int rodaGigiAwal, String nama) { this.rodaGigi = rodaGigiAwal; this.irama = iramaAwal; this.kecepatan = kecepatanAwal; this.nama = nama; } // Sintaks untuk method: // () // Kelas Java terkadang mengimplementasikan "getters" dan "setters" untuk data. // Sintaks untuk deklarasi method: // () public int getIrama() { return irama; } // Tipe "void" tidak memiliki kembalian (return) nilai public void setIrama(int nilaiBaru) { irama = nilaiBaru; } public void setRodaGigi(int nilaiBaru) { rodaGigi = nilaiBaru; } public void tambahKecepatan(int nilaiTambahan) { kecepatan += nilaiTambahan; } public void kurangiKecepatan(int nilaiPengurangan) { kecepatan -= nilaiPengurangan; } public void setNama(String namaBaru) { nama = namaBaru; } public String getNama() { return nama; } // Method untuk menampilkan nilai dari tiap atribut yang dimiliki objek Sepeda. @Override // Diturunkan dari kelas "Object" (Pustaka Java). public String toString() { return "roda gigi: " + rodaGigi + " irama: " + irama + " kecepatan: " + kecepatan + " nama: " + nama; } } // akhir dari kelas Sepeda // PennyFarthing adalah kelas turunan dari Sepeda class PennyFarthing extends Sepeda { // (Penny Farthings adalah sepeda dengan roda depan yang besar, // dan tidak memiliki roda gigi.) // (Penny Farthings are those bicycles with the big front wheel. // They have no gears.) public PennyFarthing(int startCadence, int startSpeed) { // Call the parent constructor with super super(startCadence, startSpeed, 0, "PennyFarthing"); } // You should mark a method you're overriding with an @annotation. // To learn more about what annotations are and their purpose check this // out: http://docs.oracle.com/javase/tutorial/java/annotations/ @Override public void setRodaGigi(int rodaGigi) { roda rodaGigi = 0; } } // Interfaces // Sintaks untuk deklarasi Interface // interface extends { // // Konstan // // Deklarasi method // } // Contoh - Makanan: public interface dapatDimakan { public void makan(); // Setiap kelas yang menggunakan interface "dapatDimakan", // harus mengimplementasikan method "makan". } public interface dapatDicerna { public void cerna(); } // Membuat kelas dengan mengimplementasikan dua interface dalam satu waktu. public class Buah implements dapatDimakan, dapatDicerna { @Override public void makan() { // ... } @Override public void cerna() { // ... } } // Dalam Java, kelas hanya dapat diturunkan sekali, tapi dapat mengimplementasikan // banyak interface. Contoh: public class ContohKelas extends ContohKelasInduk implements InterfaceSatu, InterfaceDua { @Override public void MethodInterfaceSatu() { } @Override public void MethodInterfaceDua() { } } // Kelas Abstrak (Abstract) // Sintaks untuk deklarasi kelas abstrak // Abstract Class declaration syntax // abstract extends { // // Konstan dan variabel // // Deklarasi method // Menjadikan kelas sebagai abstrak adalah memungkinkan kelas berisi method abstrak // yang harus didefinisikan pada kelas turunannya. Mirip dengan Interface, kelas abstrak // tidak dapat dilakukan instansiasi, namun harus diturunkan pada kelas lain dan method abstrak // harus didefinisikan. Perbedaannya dengan Interface ialah kelas abstrak dapat berisi method // kongkrit dan method abstrak. Pada Interface method tidak dapat memiliki isi, artinya hanya // method statis, dan variabel langsung ditentukan menjadi final, tidak seperti kelas abstrak. // Kelas abstrak juga dapat memiliki method "main". public abstract class Hewan { public abstract void bersuara(); // Method biasa dapat memiliki isi public void makan() { System.out.println("Saya adalah hewan dan Saya makan."); // Catatan: Kita dapat mengakses variabel private yang ada disini. umur = 30; } // Tidak perlu dilakukan inisialisasi, berbeda dengan Interface // sebuah variabel adalah final dan harus dilakukan inisialisasi. protected int umur; public void tampilkanUmur() { System.out.println(umur); } // Kelas abstrak dapat memiliki fungsi utama (main). public static void main(String[] args) { System.out.println("Saya adalah kelas abstrak!"); } } class Kucing extends Hewan { // Catatan: kelas ini harus melakukan override method abstrak // yang ada pada kelas abstrak (induk). @Override public void bersuara() { System.out.println("Moe"); // umur = 30; ==> ERROR! umur merupakan variabel private pada abstrak Hewan } // CATATAN: Akan muncul error jika menggunakan // keterangan @Override pada method utama (main), // Java tidak mengizinkan hal tersebut. // Kejadian ini sering disebut sebagai METHOD HIDING. // Pertanyaan-jawaban yang menarik dapat dilihat: http://stackoverflow.com/questions/16313649/ public static void main(String[] args) { Kucing moe = new Kucing(); noe.bersuara(); moe.makan(); moe.tampilkanUmur(); } } // Kelas Final // Sintaks untuk deklarasi kelas Final // final { // // Konstann dan variabel // // Deklarasi method // } // Kelas Final merupakan kelas yang tidak dapat diturunkan sehingga menjadikan // method tersebut turunan method terakhir. Disisi lain, kelas final merupakan // lawan dari kelas abstrak karena kelas abstrak dapat diturunkan lagi, sedangkan // kelas final tidak dapat diturunkan lagi. public final class Serigala extends Hewan { // Catatan: method abstrak harus di-override pada kelas abstrak. @Override public void bersuara() { System.out.println("Auuww"); } } // Method Final public abstract class Mamalia() { // Sintaks untuk method final: // final () // Method final, seperti kelas final tidak dapat di-override oleh kelas turunan, // sehingga menjadikannya implementasi terakhir dari method. public final boolean apakahBerdarahDingin() { return true; } } // Tipe Enum // // Tipe Enum merupakan tipe data spesial yang memungkinkan sebuah nilai dijadikan // konstan awal (predefined). Variabel setidaknya harus memiliki nilai yang sama // dengan salah satu dari enum-enum yang telah ditentukan. Karena nilainya merupakan // konstan, untuk itu penamaannya menggunakan huruf kapital (uppercase). Dalam Java, // Enum didefinisikan dengan kata kunci "enum". Contohnya nama-nama hari dalam semunggu: public enum Hari { SENIN, SELASA, RABU, KAMIS, JUMAT, SABTU, MUNGGU } // Cara menggunakan Enum: public class CobaEnum { // Variabel Enum Hari hari; // Konstruktor public CobaEnum(Hari hari) { this.hari = hari; } public void tampilkanKeterangan() { switch (day) { case SENIN: System.out.println("Senin adalah hari yang menyebalkan."); break; case JUMAT: System.out.println("Jumat adalah hari yang singkat."); break; case SABTU: case MINGGU: System.out.println("Akhir pekan adalah hari yang menyenangkan."); break; default: System.out.println("Hari kerja yang biasa saja."); break; } } public static void main(String[] args) { CobaEnum hariPertama = new CobaEnum(Hari.SENIN); hariPertama.tampilkanKeterangan(); // Senin adalah hari yang menyebalkan. CobaEnum hariKetiga = new CobaEnum(Hari.RABU); hariPertama.tampilkanKeterangan(); // Hari kerja yang biasa saja. } } // Tipe enum memiliki banyak kegunaan selain yang dicontohkan diatas. // Tipe enum dapat memiliki isi seperti method dan variabel. // Penjelasan lebih detail di https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html ``` ## Referensi Lainnya Link-link berikut hanya menyediakan pemahaman lebih lanjut mengenai topik diatas. Tip, trik, dan contoh lainnya dapat melakukan pencarian melalui Google atau mesin pencari yang lain. **Panduan resmi Oracle** * [Java Tutorial Trail from Sun / Oracle](http://docs.oracle.com/javase/tutorial/index.html) * [Java Access level modifiers](http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html) * [Object-Oriented Programming Concepts](http://docs.oracle.com/javase/tutorial/java/concepts/index.html): * [Inheritance](http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html) * [Polymorphism](http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html) * [Abstraction](http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html) * [Exceptions](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) * [Interfaces](http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html) * [Generics](http://docs.oracle.com/javase/tutorial/java/generics/index.html) * [Java Code Conventions](http://www.oracle.com/technetwork/java/codeconvtoc-136057.html) **Tutorial dan Praktik Online** * [Codingbat.com](http://codingbat.com/java) * [Codewars - Java Katas](https://www.codewars.com/?language=java) * [University of Helsinki - Object-Oriented programming with Java](http://moocfi.github.io/courses/2013/programming-part-1/) **Buku**: * [Head First Java](http://www.headfirstlabs.com/books/hfjava/) * [Thinking in Java](https://www.amazon.com/Thinking-Java-4th-Bruce-Eckel/dp/0131872486/) * [Objects First with Java](http://www.amazon.com/Objects-First-Java-Practical-Introduction/dp/0132492660) * [Java The Complete Reference](http://www.amazon.com/gp/product/0071606300) ================================================ FILE: id/json.md ================================================ --- contributors: - ["Anna Harren", "https://github.com/iirelu"] - ["Marco Scannadinari", "https://github.com/marcoms"] translators: - ["Rizky Luthfianto", "https://github.com/rilut"] - ["Ahmad Zafrullah", "https://github.com/23Pstars"] --- JSON adalah format pertukaran data yang sangat sederhana. Sebagaimana dikutip dari [json.org](http://json.org), JSON mudah untuk dibaca atau ditulis oleh manusia, dan mudah diuraikan dan diproses oleh mesin. Sebuah format JSON setidaknya memiliki: * Sebuah pasangan nama atau nilai dinyatakan dengan karakter (`{ }`). Dibeberapa bahasa pemrograman, karakter ini sering digunakan sebagai object, record, struct, dictionary, hash table, keyed list, atau associative array. * Daftar nilai dinyatakan dengan karakter (`[ ]`). Dibeberapa bahasa pemrograman, karakter ini sering digunakan sebagai array, vector, list, atau sequence. Format JSON murni tidak memiliki komentar, namun beberapa pengurai (parser) dapat mengenali komentar seperti yang digunakan oleh bahasa C (`//`, `/**/`). Beberapa pengurai lainnya juga memiliki toleransi terhadap akhiran sisa koma (seperti koma yang terdapat pada akhir elemen dari larik atau properti terakhir dari objek), tapi koma tersebut memang seharusnya diabaikan untuk dukungan yang lebih baik. Dalam tutorial ini, semuanya menggunakan format JSON murni. Tipe data yang didukung oleh JSON: * Teks: `"halo"`, `"\"tanda petik.\""`, `"\u0abe"`, `"baris baru.\n"` * Angka: `23`, `0.11`, `12e10`, `3.141e-10`, `1.23e+4` * Objek: `{ "kunci": "nilai" }` * Larik: `["nilai"]` * Lainnya: `true`, `false`, `null` ```json { "kunci": "nilai", "kunci": "harus selalu diapit tanda kutip", "angka": 0, "strings": "Halø, dunia. Semua karaktor unicode diperbolehkan, terumasuk \"escaping\".", "punya tipe data boolean?": true, "nilai kosong": null, "angka besar": 1.2e+100, "obyek": { "komentar": "Most of your structure will come from objects.", "array": [0, 1, 2, 3, "Array bisa berisi apapun.", 5], "obyek lainnya": { "komentar": "Obyek-obyek JSON dapat dibuat bersarang, sangat berguna." } }, "iseng-iseng": [ { "sumber potassium": ["pisang"] }, [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, "neo"], [0, 0, 0, 1] ] ], "gaya alternatif": { "komentar": "lihat ini!" , "posisi tanda koma": "tak masalah. selama sebelum nilai berikutnya, valid-valid saja" , "komentar lainnya": "betapa asyiknya" }, "singkat": "Dan Anda selesai! Sekarang Anda tahu apa saja yang disediakan oleh JSON." } ``` ## Referensi lebih labjut * [JSON.org](http://json.org/json-id.html) semua keindahan JSON dijelaskan dalam bentuk alur-grafis (bahasa indonesia). ================================================ FILE: id/markdown.md ================================================ --- contributors: - ["Dan Turkel", "http://danturkel.com/"] translators: - ["Tasya Aditya Rukmana", "http://github.com/tadityar"] --- Markdown dibuat oleh John Gruber pada tahun 2004. Tujuannya untuk menjadi syntax yang mudah dibaca dan ditulis yang dapat berubah menjadi HTML (dan sekarang berbagai format lainnya) dengan mudah. Beri masukan sebanyak-banyaknya! / Jangan sungkan untuk melakukan fork dan pull request! ```md # Ini adalah

## Ini adalah

### Ini adalah

#### Ini adalah

##### Ini adalah

###### Ini adalah
Ini adalah h1 ============= Ini adalah h2 ------------- *Ini adalah teks miring.* _Dan juga teks ini._ **Ini adalah teks tebal.** __Dan juga teks ini.__ ***Ini adalah teks dengan keduanya.*** **_Dan juga ini!_** *__Dan ini!__* ~~Teks ini dirender dengan coretan.~~ Ini adalah paragraf. Saya mengetik dalam paragraf, bukankah ini menyenangkan? Sekarang saya ada di paragraf 2. Saya juga masih ada dalam paragraf 2! Saya ada di paragraf 3! Aku diakhiri dua spasi (soroti aku untuk melihatnya). Ada sebuah
diatasku! > Ini adalah kutipan. Anda dapat > membungkusnya secara manual dan meletakkan `>` sebelum tiap baris atau Anda dapat membuat baris yang sangat panjang dan membuatnya membungkus secara otomatis. > Tidak ada masalah selama ia diawali dengan `>`. > Anda juga dapat menggunakan lebih dari satu level >> indentasi! > Sangat rapi bukan? * Item * Item * Item lainnya atau + Item + Item + Satu lagi item or - Item - Item - Item terakhir 1. Item satu 2. Item dua 3. Item tiga 1. Item satu 1. Item dua 1. Item tida 1. Item satu 2. Item dua 3. Item tiga * Sub-item * Sub-item 4. Item empat Kotak di bawah tanpa 'x' adalah kotak centang HTML yang belum diisi. - [ ] Tugas pertama selesai. - [ ] Tugas kedua yang harus diselesaikan Kotak centang HTML berikut telah diisi. - [x] Tugas ini telah diselesaikan Ini adalah kode Dan ini juga array_ku.each do |item| puts item end John bahkan tidak tahu apa fungsi dari `go_to()` ! \`\`\`ruby def foobar puts "Halo Dunia!" end \`\`\` *** --- - - - **************** [Klik aku!](http://test.com/) [Klik aku!](http://test.com/ "Link to Test.com") [Pergi ke musik](/music/). [Klik link ini][link1] untuk info lebih banyak! [Juga cek link ini][foobar] jika Anda mau. [link1]: http://test.com/ "Keren!" [foobar]: http://foobar.biz/ "OK!" [Ini][] adalah tautan. [ini]: http://thisisalink.com/ ![Ini adalah atribut alt dari gambar saya](http://imgur.com/myimage.jpg "Judul opsional") ![Ini adalah atribut alt.][myimage] [myimage]: relative/urls/cool/image.jpg "jika Anda membutuhkan judul, disini" sama dengan [http://testwebsite.com/](http://testwebsite.com/) Saya ingin mengetik *teks ini dikelilingi tanda bintang* tapi saya tidak mau teksnya menjadi miring, jadi saya melakukan: \*teks ini dikelilingi tanda bintang\*. Komputer Anda hang? Coba kirim sebuah Ctrl+Alt+Del | Kol1 | Kol2 | Kol3 | | :----------- | :------: | ------------: | | Rata-kiri | Tengah | Rata-Kanan | | blah | blah | blah | Kol 1 | Kol2 | Kol3 :-- | :-: | --: Ugh ini sangat jelek | buat ia | berhenti ``` Untuk info lebih lanjut, cek post syntax resmi John Gruber [di sini](http://daringfireball.net/projects/markdown/syntax) dan contekan hebat Adam Pritchard's [di sini](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). ================================================ FILE: id/php.md ================================================ --- contributors: - ["Malcolm Fell", "http://emarref.net/"] - ["Trismegiste", "https://github.com/Trismegiste"] translators: - ["Ahmad Zafrullah", "https://github.com/23Pstars"] - ["Cendy", "https://cendy.co"] --- Dokumen ini menjelaskan tentang PHP5 keatas. ```php Halo Dunia, lagi! 12 $int2 = -12; // => -12 $int3 = 012; // => 10 (awalan 0 menandakan bilangan Oktal) $int4 = 0x0F; // => 15 (awalan 0x menandakan bilangan Heksadesimal) // Bilangan Biner Integer tersedia mulai dari PHP 5.4.0. $int5 = 0b11111111; // 255 (awalan 0b menandakan bilangan Biner) // Nilai Floats (dikenal juga sebagai Doubles) $float = 1.234; $float = 1.2e3; $float = 7E-10; // Menghapus variable unset($int1); // Aritmatika $jumlah = 1 + 1; // 2 $selisih = 2 - 1; // 1 $perkalian = 2 * 2; // 4 $pembagian = 2 / 1; // 2 // Aritmatika singkat $angka = 0; $angka += 1; // Menjumlahkan $angka dengan 1 echo $angka++; // Menampilkan 1 (dijumlahkan dengan 1 setelah dievaluasi) echo ++$angka; // Menampilkan 3 (dijumlahkan dengan 1 sebelum dievaluasi) $angka /= $float; // Membagi dan menyimpan hasil pembagian pada $angka; // String biasanya diawali dan ditutup dengan petik satu. $sgl_quotes = '$String'; // => '$String' // Hindari menggunakan petik dua kecuali untuk menyertakan variabel lain $dbl_quotes = "Ini adalah $sgl_quotes."; // => 'Ini adalah $String.' // Karakter khusus hanya berlaku pada petik dua $berfungsi = "Ini mengandung \t karakter tab."; $tidak_berfungsi = 'Ini hanya mengandung garis miring dan huruf t: \t'; // Batasi variabel dengan kurung kurawal jika diperlukan $uang = "Saya memiliki $${angka} di Bank."; // Sejak PHP 5.3, nowdocs dapat digunakan untuk tak-terinterpolasi banyak-baris $nowdoc = <<<'END' Banyak baris string END; // Heredocs akan melakukan interpolasi $heredoc = << 1, 'Dua' => 2, 'Tiga' => 3); // Pada PHP 5.4 diperkenalkan cara penulisan (sintaks) baru $asosiatif = ['Satu' => 1, 'Dua' => 2, 'Tiga' => 3]; echo $asosiatif['Satu']; // menampilkan 1 // Daftar literal secara tidak langsung ditentukan oleh kunci integer $larik = ['Satu', 'Dua', 'Tiga']; echo $larik[0]; // => "Satu" // Menambahkan sebuah elemen pada akhir larik $larik[] = 'Empat'; // atau array_push($larik, 'Lima'); // Menghapus elemen dari larik unset($larik[3]); /******************************** * Keluaran */ echo('Halo Dunia!'); // Menampilkan Halo Dunia! ke "stdout". // "stdout" adalah sebuah halaman web ketika dijalankan dalam peramban (browser). print('Halo Dunia!'); // Sama seperti "echo" // "echo" dan "print" merupakan bahasa konstruksi, jadi tanda kurung dapat dihilangkan echo 'Halo Dunia!'; print 'Halo Dunia!'; $paragraf = 'paragraf'; echo 100; // Menampilkan variabel skalar secara langsung echo $paragraf; // atau sebuat variabel // Jika PHP tag-singkat telah dikonfigurasi, atau versi PHP yang digunakan // adalah 5.4.0 keatas, dapat digunakan sintaks "echo" singkat ?>

2 echo $z; // => 2 $y = 0; echo $x; // => 2 echo $z; // => 0 // Menampilkan tipe dan nilai dari variabel ke "stdout" var_dump($z); // prints int(0) // Menampilkan variabel ke "stdout" dalam format yang mudah dibaca print_r($larik); // menampilkan: Array ( [0] => Satu [1] => Dua [2] => Tiga ) /******************************** * Logika */ $a = 0; $b = '0'; $c = '1'; $d = '1'; // assert akan melempar sebuah peringatan jika pernyataan tidak benar // Perbandingan berikut akan selalu benar, meskipun memiliki tipe yang berbeda. assert($a == $b); // kesamaan assert($c != $a); // ketidak-samaan assert($c <> $a); // versi lain dari ketidak-samaan assert($a < $c); assert($c > $b); assert($a <= $b); assert($c >= $d); // Dibawah ini hanya akan bernilai benar jika nilainya memiliki tipe yang sama. assert($c === $d); assert($a !== $d); assert(1 === '1'); assert(1 !== '1'); // Operator 'Spaceship' (sejak PHP 7) // Mengembalikan 0 jika nilai pada kedua sisi adalah sama // Mengembalikan 1 jika nilai pada sisi kiri lebih besar // Mengembalikan -1 jika nilai pada sisi kanan lebih besar $a = 100; $b = 1000; echo $a <=> $a; // 0 karena keduanya sama echo $a <=> $b; // -1 karena $a < $b echo $b <=> $a; // 1 karena $b > $a // Variabel dapat dikonversi menjadi tipe lain, sesuai penggunaannya. $integer = 1; echo $integer + $integer; // => 2 $string = '1'; echo $string + $string; // => 2 (string dipaksa menjadi integer) $string = 'satu'; echo $string + $string; // => 0 // Menghasilkan 0 karena operator (+) tidak dapat memaksa string 'satu' menjadi sebuah integer // Perubahan tipe dapat dimanfaatkan untuk diperlakukan sebagai tipe lainnya $boolean = (boolean) 1; // => true $nol = 0; $boolean = (boolean) $nol; // => false // Terdapat juga fungsi khusus untuk melakukan perubahan terhadap beberapa tipe $integer = 5; $string = strval($integer); $var = null; // Nilai Null /******************************** * Struktur Kontrol */ if (true) { print 'Saya tampil'; } if (false) { print 'Saya tidak tampil'; } else { print 'Saya tampil'; } if (false) { print 'Tidak tampil'; } elseif(true) { print 'Tampil'; } // operator ternary print (false ? 'Tidak tampil' : 'Tampil'); // cara pintas operator ternary mulai dirilis sejak PHP 5.3 // persamaan dari "$x ? $x : 'Kerjakan'" $x = false; print($x ?: 'Kerjakan'); // operator null coalesce sejak PHP 7 $a = null; $b = 'Ditampilkan'; echo $a ?? 'a belum di-set'; // menampilkan 'a belum di-set' echo $b ?? 'b belum di-set'; // menampilkan 'Ditampilkan' $x = 0; if ($x === '0') { print 'Tidak ditampilkan'; } elseif($x == '1') { print 'Tidak ditampilkan'; } else { print 'Tampil'; } // Alternatif sintaks untuk kebutuhan templat: ?> Ini ditampilkan jika pengujian benar. Selain tersebut ini yang akan ditampilkan. 2, 'mobil' => 4]; // Perulangan "foreach" dapat melakukan iterasi pada larik (array) foreach ($roda as $jumlah_roda) { echo $jumlah_roda; } // Menampilkan "24" echo "\n"; // Iterasi dapat dilakukan terhadap "key" (kunci) dan "value" (nilai) foreach ($roda as $mesin => $jumlah_roda) { echo "$mesin memiliki $jumlah_roda buah roda"; } echo "\n"; $i = 0; while ($i < 5) { if ($i === 3) { break; // Menghentikan proses perulangan } echo $i++; } // Menampilkan "012" for ($i = 0; $i < 5; $i++) { if ($i === 3) { continue; // Melewati tahapan iterasi saat ini } echo $i; } // Menampilkan "0124" /******************************** * Fungsi */ // Fungsi didefinisikan dengan "function": function fungsi_saya () { return 'Halo'; } echo fungsi_saya(); // => "Halo" // Nama fungsi yang baik dan benar diawali dengan sebuah huruf atau garis-bawah, diikuti oleh // beberapa huruf, angka, atau garis-bawah. function jumlah ($x, $y = 1) { // $y merupakan opsional, jika tidak ditentukan akan bernilai 1 $hasil = $x + $y; return $hasil; } echo jumlah(4); // => 5 echo jumlah(4, 2); // => 6 // $hasil tidak dapat diakses dari luar fungsi // print $hasil; // Akan menghasilkan sebuah "warning". // Sejak PHP 5.3 fungsi dapat dideklarasikan menjadi tanpa-nama (anonymous); $inc = function ($x) { return $x + 1; }; echo $inc(2); // => 3 function foo ($x, $y, $z) { echo "$x - $y - $z"; } // Fungsi dapat mengembalikan fungsi juga function bar ($x, $y) { // Gunakan "use" untuk mengakses variabel diluar fungsi return function ($z) use ($x, $y) { foo($x, $y, $z); }; } $bar = bar('A', 'B'); $bar('C'); // Menampilkan "A - B - C" // Fungsi uang memiliki nama dapat dipanggil berdasarkan string $nama_fungsi = 'jumlah'; echo $nama_fungsi(1, 2); // => 3 // Bermanfaat untuk menentukan fungsi mana yang akan dipanggil secara dinamis. // Atau, dapat juga menggunakan fungsi call_user_func(callable $callback [, $parameter [, ... ]]); // Akses semua parameter yang dikirim ke sebuah fungsi function parameter() { $jumlah_param = func_num_args(); if( $jumlah_param > 0 ) { echo func_get_arg(0) . ' | '; } $daftar_param = func_get_args(); foreach( $daftar_param as $kunci => $param ) { echo $kunci . ' - ' . $param . ' | '; } } parameter('Halo', 'Dunia'); // Halo | 0 - Halo | 1 - Dunia | // Sejak PHP 5.6, mendapatkan jumlah variabel yang ada pada parameter function variabel($kata, ...$daftar) { echo $kata . " || "; foreach ($daftar as $item) { echo $item . ' | '; } } variable("Pemisah", "Halo", "Dunia") // Pemisah || Halo | Dunia | /******************************** * Penyertaan ("include") */ PropertiInstansi = $PropertiInstansi; } // Method dideklarasikan sebagai fungsi didalam kelas public function methodSaya() { print 'KelasSaya'; } // Perintah "final" membuat sebuah fungsi tidak dapat di-override oleh kelas turunannya final function tidakDapatDiOverride() { } // Metode ajaib // apa yang dilakukan jika Objek diperlakukan sebagai String public function __toString() { return $properti; } // Berlawanan dari __construct() // Dipanggil saat objek tidak lagi di referensi public function __destruct() { print "Destroying"; } /* * Deklarasi properti atau method pada kelas sebagai statis membuat properti atau method tersebut * dapat diakses tanpa melakukan instansiasi kelas. Properti statis tidak dapat diakses melalui * objek kelas yang hasil instansiasi, sedangkan method statis bisa. */ public static function methodStatisSaya() { print 'Saya adalah statis'; } } // Konstan pada kelas dapat diakses secara statis echo KelasSaya::NILAI_KONSTAN; // Menampilkan 'nilai' echo KelasSaya::$nilaiStatis; // Menampilkan 'statis' KelasSaya::methodStatisSaya(); // Menampilkan 'Saya adalah statis' // Instansi kelas menggunakan perintah "new" $kelas_saya = new KelasSaya('Sebuah properti instansiasi'); // Tanda kurung adalah opsional jika tidak ingin menggunakan argumen. // Akses anggota kelas menggunakan -> echo $kelas_saya->properti; // => "publik" echo $kelas_saya->propertiInstansi; // => "Sebuah properti instansi" $kelas_saya->methodSaya(); // => "KelasSaya" // Operasi Nullsafe semenjak PHP 8 // Kamu bisa menggunakan ini jika kamu tidak yakin apakah $kelas_saya memiliki sebuah properti/metode // Ini bisa digunakan bersamaan dengan operator nullish coalesce untuk memastikan value echo $kelas_saya->properti_invalid // Akan muncul sebuah error echo $kelas_saya?->properti_invalid // => NULL echo $kelas_saya?->properti_invalid ?? "publik" // => "publik" // Menurunkan kelas menggunakan kata kunci "extends" class KelasSayaLainnya extends KelasSaya { function tampilkanPropertiTerlindungi() { echo $this->terlindungi; } // "override" terhadap sebuah method function methodSaya() { parent::methodSaya(); print ' > KelasSayaLainnya'; } } $kelas_saya_lainnya = new KelasSayaLainnya('Instansiasi properti'); $kelas_saya_lainnya->tampilkanPropertiTerlindung(); // => Menampilkan "terlindungi" $kelas_saya_lainnya->methodSaya(); // Menampilkan "KelasSaya > KelasSayaLainnya" final class SayaTidakBisaDiturunkan { } // Gunakan method ajaib (magic method) untuk membuat fungsi "getters" dan "setters" class PetaKelasSaya { private $properti; public function __get($key) { return $this->$key; } public function __set($key, $value) { $this->$key = $value; } } $x = new PetaKelasSaya(); echo $x->properti; // akan memanggil method __get() $x->properti = 'Sesuatu'; // akan memanggil method __set(); // Kelas dapat dijadikan abstrak (menggunakan kata kunci "abstract"), atau // meng-implementasikan interfaces (menggunakan kata kunci "implements"). // Sebuah interface dideklarasikan dengan perintah "interface". interface InterfaceSatu { public function kerjakanSesuatu(); } interface InterfaceDua { public function kerjakanYangLain(); } // interface dapat diturunkan interface InterfaceTiga extends InterfaceDua { public function kerjakanYangBerbeda(); } abstract class KelasAbstrakSaya implements InterfaceSatu { public $x = 'kerjakanSesuatu'; } class KelasKongkritSaya extends KelasAbstrakSaya implements InterfaceTwo { public function kerjakanSesuatu() { echo $x; } public function kerjakanYangLain() { echo 'kerjakanYangLain'; } } // Kelas dapat diimplementasikan pada banyak interface class KelasLainnya implements InterfaceSatu, InterfaceDua { public function kerjakanSesuatu() { echo 'kerjakanSesuatu'; } public function kerjakanYangLain() { echo 'kerjakanYangLain'; } } /******************************** * Sifat (Traits) */ // Traits mulai tersedia sejak PHP 5.4.0 dan dideklarasikan menggunakan kata kunci "trait" trait TraitSaya { public function methodTraitSaya() { print 'Saya menggunakan Trait'; } } class KelasTraitSaya { use TraitSaya; } $kls = new KelasTraitSaya(); $kls->methodTraitSaya(); // menampilkan "Saya menggunakan Trait" /******************************** * Namespaces */ // Bagian ini telah dibatasi, karena deklarasi "namespace" // karena harus ditempatkan diawal dokumen. `_ . .. _GitHub https://github.com/ ``` ## Bagaimana Cara Menggunakannya RST hadir dengan docutils di mana anda mempunyai `rst2html`, sebagai contoh: ```bash $ rst2html fileku.rst hasil.html ``` *Catatan : Di beberapa sistem, perintah tersebut bisa menjadi rst2html.py* Tetapi ada beberapa aplikasi kompleks yang menggunakan format RST: - [Pelican](http://blog.getpelican.com/), Generator web statik - [Sphinx](http://sphinx-doc.org/), Generator dokumnetasi - dan masih banyak lainnya ## Bacaan - [Referensi singkat resmi](http://docutils.sourceforge.net/docs/user/rst/quickref.html) ================================================ FILE: id/ruby.md ================================================ --- contributors: - ["David Underwood", "http://theflyingdeveloper.com"] - ["Joel Walden", "http://joelwalden.net"] - ["Luke Holder", "http://twitter.com/lukeholder"] - ["Tristan Hume", "http://thume.ca/"] - ["Nick LaMuro", "https://github.com/NickLaMuro"] - ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"] - ["Ariel Krakowski", "http://www.learneroo.com"] - ["Dzianis Dashkevich", "https://github.com/dskecse"] - ["Levi Bostian", "https://github.com/levibostian"] - ["Rahil Momin", "https://github.com/iamrahil"] - ["Gabriel Halley", "https://github.com/ghalley"] - ["Persa Zula", "http://persazula.com"] - ["Jake Faris", "https://github.com/farisj"] translators: - ["Ukaza Perdana", "https://github.com/ukazap"] --- ```ruby # Ini adalah sebuah komentar =begin Ini adalah komentar multibaris Tak seorang pun menggunakannya Kamu juga tidak perlu =end # Pertama-tama dan yang terpenting: Semuanya adalah objek. # Angka adalah objek 3.class #=> Fixnum 3.to_s #=> "3" # Beberapa aritmetika dasar 1 + 1 #=> 2 8 - 1 #=> 7 10 * 2 #=> 20 35 / 5 #=> 7 2**5 #=> 32 5 % 3 #=> 2 # Operator-operator bitwise 3 & 5 #=> 1 3 | 5 #=> 7 3 ^ 5 #=> 6 # Aritmetika tidak lain adalah pemanis sintaks (syntactic sugar) # untuk memanggil sebuah metode pada suatu objek 1.+(3) #=> 4 10.* 5 #=> 50 # Nilai-nilai khusus adalah objek nil # setara dengan "null" di bahasa-bahasa lain true # kebenaran false # ketidakbenaran nil.class #=> NilClass true.class #=> TrueClass false.class #=> FalseClass # Kesamaan 1 == 1 #=> true 2 == 1 #=> false # Ketidaksamaan 1 != 1 #=> false 2 != 1 #=> true # selain false itu sendiri, nil adalah nilai lain yang "salah" !nil #=> true !false #=> true !0 #=> false # Perbandingan lain 1 < 10 #=> true 1 > 10 #=> false 2 <= 2 #=> true 2 >= 2 #=> true # Operator pembanding yang dikombinasikan ("spaceship operator") 1 <=> 10 #=> -1 10 <=> 1 #=> 1 1 <=> 1 #=> 0 # Operator-operator logika true && false #=> false true || false #=> true !true #=> false # Terdapat versi-versi operator logika yang berbeda dengan lebih sedikit awalan. # Mereka digunakan sebagai kendali alur untuk merangkai beberapa pernyataan # hingga salah satunya mengembalikan (return) nilai true atau false. # `lakukan_suatu_lainnya` hanya dipanggil jika `lakukan_sesuatu` berhasil. lakukan_sesuatu() and lakukan_suatu_lainnya() # `catat_error` hanya dipanggil jika `lakukan_sesuatu` gagal. lakukan_sesuatu() or catat_error() # String adalah objek 'Aku adalah string'.class #=> String "Aku juga adalah string".class #=> String wadah = 'menggunakan string interpolation' "Aku bisa #{wadah} ketika memakai tanda kutip ganda" #=> "Aku bisa menggunakan string interpolation ketika memakai tanda kutip ganda" # Gunakan tanda kutip tunggal daripada tanda kutip ganda jika memungkinkan # String bertanda kutip ganda melakukan kalkulasi tambahan di dalam # Kombinasikan string, tapi tidak dengan angka 'halo ' + 'dunia' #=> "halo dunia" 'halo ' + 3 #=> TypeError: can't convert Fixnum into String 'halo ' + 3.to_s #=> "halo 3" # Kombinasikan string dengan operator 'halo ' * 3 #=> "halo halo halo " # Membubuhkan ke string 'halo' << ' dunia' #=> "halo dunia" # cetak ke output dan buat baris baru (newline) di akhir puts "Aku mencetak!" #=> Aku mencetak! #=> nil # cetak ke output tanpa baris baru print "Aku mencetak!" #=> Aku mencetak! => nil # Variabel x = 25 #=> 25 x #=> 25 # Catat bahwa pemberian nilai mengembalikan nilai yang diberikan # Artinya kamu bisa melakukan pemberian nilai secara jamak: x = y = 10 #=> 10 x #=> 10 y #=> 10 # Berdasarkan adat, gunakan gaya snake_case untuk menulis nama variabel snake_case = true # Gunakan nama variabel yang deskriptif path_to_project_root = '/good/name/' path = '/bad/name/' # Simbol (adalah objek) # Simbol adalah konstanta yang dapat didaur ulang yang tidak dapat diubah # (immutable), secara internal diwakili oleh nilai integer. Seringkali # digunakan sebagai pengganti string untuk menyampaikan nilai yang mengandung # makna spesifik secara efisien. :menunggu.class #=> Symbol status = :menunggu status == :menunggu #=> true status == 'menunggu' #=> false status == :diterima #=> false # Array # Ini adalah sebuah array array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] # Array bisa menampung item dengan beragam tipe [1, 'halo', false] #=> [1, "halo", false] # Array bisa di-indeks-kan # Dari depan array[0] #=> 1 array.first #=> 1 array[12] #=> nil # Sama dengan aritmetika, pengaksesan [var] # hanyalah pemanis sintaks # untuk memanggil metode [] pada suatu objek array.[] 0 #=> 1 array.[] 12 #=> nil # Dari belakang array[-1] #=> 5 array.last #=> 5 # Dengan indeks awal dan panjang (jumlah item) array[2, 3] #=> [3, 4, 5] # Membalik sebuah Array a=[1,2,3] a.reverse! #=> [3,2,1] # Atau menggunakan jangkauan (range) array[1..3] #=> [2, 3, 4] # Tambahkan ke array seperti ini array << 6 #=> [1, 2, 3, 4, 5, 6] # Atau seperti ini array.push(6) #=> [1, 2, 3, 4, 5, 6] # Periksa apakah suatu item ada dalam sebuah array array.include?(1) #=> true # Hash adalah kamus utama Ruby berupa pasangan kunci/nilai (key/value pair). # Hash ditandai dengan kurung kurawal: hash = { 'warna' => 'hijau', 'angka' => 5 } hash.keys #=> ['warna', 'angka'] # Nilai dalam Hash bisa diperoleh menggunakan kunci: hash['warna'] #=> 'hijau' hash['angka'] #=> 5 # Meminta hash untuk kunci yang tidak ada akan mengembalikan nil: hash['tidak ada di sini'] #=> nil # Sejak Ruby 1.9, ada sintaks khusus ketika menggunakan simbol sebagai kunci: hash_baru = { defcon: 3, action: true } hash_baru.keys #=> [:defcon, :action] # Periksa ada/atau tidaknya kunci dan nilai dalam hash hash_baru.key?(:defcon) #=> true hash_baru.value?(3) #=> true # Tip: Baik array maupun hash adalah Enumerable # Mereka berbagi banyak metode yang berguna diantaranya each, map, count, dll. # Struktur-struktur kendali if true 'pernyataan if' elsif false 'else if, opsional' else 'else, opsional juga' end for penghitung in 1..5 puts "iterasi #{penghitung}" end #=> iterasi 1 #=> iterasi 2 #=> iterasi 3 #=> iterasi 4 #=> iterasi 5 # NAMUN, tidak ada orang yang menggunakan pengulangan for. # Sebagai ganti, gunakan metode "each" dan memberinya sebuah blok (block). # Blok adalah serangkaian kode yang bisa dimasukkan ke metode seperti "each". # Ia serupa dengan lambda, fungsi anonim atau closure di bahasa lainnya. # # Metode "each" dari range menjalankan blok untuk setiap elemen dari range. # Bloknya diberikan penghitung sebagai parameter. # Memanggil metode "each" dengan blok terlihat seperti ini: (1..5).each do |penghitung| puts "iterasi #{penghitung}" end #=> iterasi 1 #=> iterasi 2 #=> iterasi 3 #=> iterasi 4 #=> iterasi 5 # Kamu juga bisa mengurung blok dalam kurung kurawal: (1..5).each { |penghitung| puts "iterasi #{penghitung}" } # Isi dari struktur-struktur data juga bisa di-iterasi menggunakan each. array.each do |elemen| puts "#{elemen} adalah bagian dari array" end hash.each do |kunci, nilai| puts "#{kunci} adalah #{nilai}" end # Jika kamu masih membutuhkan indeks, bisa menggunakan "each_with_index" # dan definisikan variabel indeks array.each_with_index do |elemen, indeks| puts "#{elemen} adalah nomor #{indeks} dalam array" end penghitung = 1 while penghitung <= 5 do puts "iterasi #{penghitung}" penghitung += 1 end #=> iterasi 1 #=> iterasi 2 #=> iterasi 3 #=> iterasi 4 #=> iterasi 5 # Ada kumpulan fungsi pengulangan lainnya yang berguna di Ruby, # contohnya "map", "reduce", "inject", daftarnya sangat panjang. Map, # misalnya, mengambil array yang di-iterasi-nya, melakukan sesuatu pada # setiap elemen sesuai definisi pada blok, dan mengembalikan array baru. array = [1,2,3,4,5] berganda = array.map do |elemen| elemen * 2 end puts berganda #=> [2,4,6,8,10] puts array #=> [1,2,3,4,5] nilai = 'B' case nilai when 'A' puts 'Pertahankan, nak' when 'B' puts 'Semoga lebih beruntung di lain waktu' when 'C' puts 'Kamu bisa lebih baik' when 'D' puts 'Susah payah' when 'F' puts 'Kamu gagal!' else puts 'Sistem penilaian lainnya, heh?' end #=> "Semoga lebih beruntung di lain waktu" # case juga bisa menggunakan range nilai = 82 case nilai when 90..100 puts 'Hore!' when 80...90 puts 'Cukup bagus' else puts 'Kamu gagal!' end #=> "Cukup bagus" # penanganan kesalahan (exception handling): begin # kode di sini yang mungkin membangkitkan exception raise NoMemoryError, 'Kamu kehabisan memori.' rescue NoMemoryError => variabel_exception puts 'NoMemoryError dibangkitkan', variabel_exception rescue RuntimeError => variabel_exception_lainnya puts 'RuntimeError dibangkitkan sekarang' else puts 'Ini dijalankan bila tidak ada exceptions sama sekali' ensure puts 'Kode ini akan berjalan bagaimanapun juga' end # Fungsi (atau metode) def gandakan(x) x * 2 end # Fungsi dan semua blok secara tersirat mengembalikan nilai pernyataan terakhir gandakan(2) #=> 4 # Tanda kurung bersifat optional, boleh ditiadakan jika tidak ambigu gandakan 3 #=> 6 gandakan gandakan 3 #=> 12 def jumlah(x, y) x + y end # Argumen-argumen dari metode dipisahkan dengan koma sum 3, 4 #=> 7 sum sum(3, 4), 5 #=> 12 # yield # Semua metode secara tersirat mempunyai parameter blok opsional # yang bisa dipanggil dengan kata kunci 'yield' def kurung puts '{' yield puts '}' end kurung { puts 'halo dunia' } # { # halo dunia # } # Kamu bisa memasukkan blok ke sebuah fungsi # "&" adalah penanda blok yang masuk def tamu_tamu(&blok) blok.call 'beberapa_argumen' end # Kamu bisa memasukkan daftar argumen yang akan dikonversi menjadi array # Itulah gunanya operator splat ("*") def tamu_tamu(*array) array.each { |tamu| puts tamu } end # Bila metode mengembalikan array, bisa memberi nilai dengan destrukturisasi # (destructuring assignment): def makanan ['tempe penyet', 'sayur asam', 'nasi goreng'] end sarapan, makan_siang, makan_malam = makanan sarapan #=> 'tempe penyet' makan_malam #=> 'nasi goreng' # Menurut adat, nama metode yang mengembalikan boolean diakhiri tanda tanya 5.even? # false 5.odd? # true # Dan jika suatu metode berakhiran tanda seru, ia melakukan sesuatu yang merusak # seperti mengubah penerimanya. Banyak metode mempunyai versi ! untuk melakukan # perubahan dan versi non-! untuk sekedar mengembalikan perubahannya nama_perusahaan = "Putra Sejahtera" nama_perusahaan.upcase #=> "PUTRA SEJAHTERA" nama_perusahaan #=> "Putra Sejahtera" nama_perusahaan.upcase! # kali ini kita benar-benar mengubah nama_perusahaan! nama_perusahaan #=> "PUTRA SEJAHTERA" # Definisikan kelas menggunakan kata kunci class class Manusia # Variabel kelas. Ini dibagi oleh semua instans (instance) dari kelas ini. @@spesies = 'H. sapiens' # Inisialisasi dasar def initialize(nama, usia = 0) # Berikan argumen ke variabel instans "nama" dalam instans ini @nama = nama # Jika tidak diberi usia, nilai default dalam daftar argumen digunakan. @usia = usia end # Metode setter dasar def nama=(nama) @nama = nama end # Metode getter dasar def nama @nama end # Fungsi di atas bisa disingkat dengan metode attr_accessor sebagai berikut attr_accessor :nama # Metode getter/setter juga bisa dibuat secara terpisah seperti ini attr_reader :nama attr_writer :nama # Metode kelas menggunakan self untuk membedakannya dari metode instans. # Ia hanya bisa dipanggil pada kelas, bukan pada instans-nya. def self.katakan(pesan) puts pesan end def spesies @@spesies end end # Membuat instans kelas jim = Manusia.new('Jim Halpert') dwight = Manusia.new('Dwight K. Schrute') # Mari panggil beberapa metode jim.spesies #=> "H. sapiens" jim.nama #=> "Jim Halpert" jim.nama = "Jim Halpert II" #=> "Jim Halpert II" jim.nama #=> "Jim Halpert II" dwight.spesies #=> "H. sapiens" dwight.nama #=> "Dwight K. Schrute" # Panggil metode kelas Manusia.katakan('Hai') #=> "Hai" # Lingkup variabel didefinisikan berdasarkan bagaimana kita memberikannya nama # Variabel yang berawalan $ memiliki lingkup global $var = "Aku adalah variabel global" defined? $var #=> "global-variable" # Variabel yang berawalan @ memiliki lingkup instans @var = "Aku adalah variabel instans" defined? @var #=> "instance-variable" # Variabel yang berawalan @@ memiliki lingkup kelas @@var = "Aku adalah variabel kelas" defined? @@var #=> "class variable" # Variabel yang berawalan huruf kapital adalah konstanta Var = "Aku adalah konstanta" defined? Var #=> "constant" # Kelas juga adalah objek sehingga kelas bisa memiliki variabel instans. # Variabel kelas dibagi diantara kelas dan semua pewarisnya. # kelas dasar class Manusia @@foo = 0 def self.foo @@foo end def self.foo=(nilai) @@foo = nilai end end # kelas turunan class Buruh < Manusia end Manusia.foo # 0 Buruh.foo # 0 Manusia.foo = 2 # 2 Buruh.foo # 2 # Variabel instans milik kelas tidak dibagikan dengan pewaris kelas tersebut. class Manusia @bar = 0 def self.bar @bar end def self.bar=(nilai) @bar = nilai end end class Dokter < Manusia end Manusia.bar # 0 Dokter.bar # nil module ContohModul def foo 'foo' end end # Include modul mengikat metode-metodenya pada instans-instans kelas # Extend modul mengikat metode-metodenya pada kelas class Orang include ContohModul end class Buku extend ContohModul end Orang.foo # => NoMethodError: undefined method `foo' for Orang:Class Orang.new.foo # => 'foo' Buku.foo # => 'foo' Buku.new.foo # => NoMethodError: undefined method `foo' # Callbacks dijalankan ketika meng-include dan meng-extend sebuah modul module ContohUrusan def self.included(base) base.extend(MetodeKelas) base.send(:include, MetodeInstans) end module MetodeKelas def bar 'bar' end end module MetodeInstans def qux 'qux' end end end class Sesuatu include ContohUrusan end Sesuatu.bar # => 'bar' Sesuatu.qux # => NoMethodError: undefined method `qux' Sesuatu.new.bar # => NoMethodError: undefined method `bar' Sesuatu.new.qux # => 'qux' ``` ## Sumber tambahan - [An Interactive Tutorial for Ruby](https://rubymonk.com/) - Belajar Ruby melalui serangkaian tutorial interaktif. - [Dokumentasi resmi](http://www.ruby-doc.org/core-2.1.1/) - [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/) - [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - Edisi lama yang [gratis](http://ruby-doc.com/docs/ProgrammingRuby/) tersedia online. - [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) - Panduan penulisan kode Ruby oleh komunitas. - [Try Ruby](https://try.ruby-lang.org/) - Pelajari dasar bahasa pemrograman Ruby, secara interaktif di browser. ================================================ FILE: id/smallbasic.md ================================================ --- contributors: - ["Chris Warren-Smith", "http://smallbasic.sourceforge.net"] translators: - ["Rizky Luthfianto", "http://github.com/rilut"] --- ## Tentang SmallBASIC adalah *interpreter* bahasa BASIC yang mudah dan cepat dipelajari yang ideal untuk perhitungan sehari-hari, skrip dan prototipe. Fitur SmallBASIC termasuk trigonometri, matriks dan fungsi aljabar, yang dibangun di IDE, *library* string yang canggih, sistem, suara, dan perintah grafis bersama dengan sintaks pemrograman terstruktur. ## Pengembangan SmallBASIC pada awalnya dikembangkan oleh Nicholas Christopoulos pada akhir tahun 1999 untuk Palm Pilot. pengembangan proyek telah dilanjutkan oleh Chris Warren-Smith sejak sekitar tahun 2005. Versi SmallBASIC telah dibuat untuk sejumlah perangkat genggam termasuk Franklin eBookman dan Nokia 770. Juga berbagai versi desktop yang telah dirilis berdasarkan berbagai GUI. Platform yang didukung saat ini adalah Linux dan Windows berbasis SDL2 dan Android berbasis NDK. Sebuah versi baris perintah pada desktop juga tersedia, meskipun tidak biasanya dirilis dalam bentuk biner. Sekitar tahun 2008, sebuah perusahaan merilis lingkungan pemrograman BASIC dengan nama yang mirip. SmallBASIC tidak berhubungan dengan itu. ``` REM ini adalah komentar 'dan ini juga komentar REM mencetak kalimat print "halo" ? "Tanda ? adalah singkatan dari PRINT" REM Struktur kontrol FOR index = 0 TO 10 STEP 2 ? "Ini adalah nomor baris"; indeks NEXT J=0 REPEAT J++ UNTIL J=10 WHILE J>0 J-- WEND REM Pernyataan "Select case" Select Case "Cool" Case "null", 1,2,3,4,5,6,7,8,"Cool","blah" Case "Not cool" PRINT "Epic fail" Case Else PRINT "Fail" End Select REM menangkap kesalahan dengan TRY / CATCH Try fn = Freefile Open filename For Input As #fn Catch err Print "gagal membuka file" End Try REM Fungsi dan subrutin buatan pengguna func add2(x, y) 'Variabel dapat dinyatakan sebagai lokal dalam lingkup/scope dari SUB atau FUNC local k k = "k akan lenyap ketika FUNC ini mengembalikan nilai" add2 = x + y akhir Print add2(5,5) sub cetak_ini(ini) print ini end cetak_ini "INI" REM Menampilkan garis dan piksel At 0,ymax/2+txth("Q") Color 1: ? "sin(x)": Color 8: ? "cos(x)": Color 12: ? "tan(x)" Line 0,ymax/2,xmax,ymax/2 For i=0 to xmax Pset i,ymax/2-sin(i*2*pi/ymax)*ymax/4 color 1 Pset i,ymax/2-cos(i*2*pi/ymax)*ymax/4 color 8 Pset i,ymax/2-tan(i*2*pi/ymax)*ymax/4 color 12 Next showpage REM SmallBASIC cocok untuk bereksperimen dengan fraktal dan efek menarik lainnya Delay 3000 Randomize ff = 440.03 For j = 0 to 20 r = rnd * 1000 % 255 b = rnd * 1000 % 255 g = rnd * 1000 % 255 c = rgb(r,b,g) ff += 9.444 for i=0 to 25000 f += ff x = min(xmax, -x + cos(f*i)) y = min(ymax, -y + sin(f*i)) pset x, y color c if (i%1000==0) then showpage fi next Next j REM Untuk sejarawan komputer, SmallBASIC dapat menjalankan program REM dari buku dan majalah komputer lama, misalnya: 10 LET A=9 20 LET B=7 30 PRINT A*B 40 PRINT A/B REM SmallBASIC juga memiliki dukungan untuk beberapa konsep modern seperti JSON aa = array("{\"kucing\":{\"nama\":\"harry\"},\"peliharaan\":\"true\"}") If (ismap(aa) == false) Then throw "bukan tipe data map" End If Print aa PAUSE ``` ## Artikel * [Persiapan](http://smallbasic.sourceforge.net/?q=node/1573) * [Selamat Datang di SmallBASIC](http://smallbasic.sourceforge.net/?q=node/838) ## GitHub * [Source code](https://github.com/smallbasic/SmallBASIC) * [Referensi snapshot](http://smallbasic.github.io/) ================================================ FILE: id/xml.md ================================================ --- contributors: - ["João Farias", "https://github.com/JoaoGFarias"] translators: - ["Rizky Luthfianto", "https://github.com/rilut"] - ["Ahmad Zafrullah", "https://github.com/23Pstars"] --- XML adalah bahasa markup yang dirancang untuk menyimpan dan mengirim data. XML mudah dibaca oleh manusia dan mesin. Tidak seperti HTML, XML tidak menentukan bagaimana menampilkan atau format data, hanya membawanya. Terdapat perbedaan antara **konten** dan **markup**. Singkatnya, konten dapat berupa apapun dan markup adalah sebagai penentu. ## Definisi dan Pendahuluan Dokumen XML pada dasarnya disusun oleh *elemen* yang dapat memiliki *atribut* untuk menjelaskan elemen tersebut dan dapat memiliki beberapa konten tekstual atau beberapa elemen sebagai anak-nya. Setiap dokumen XML hendaknya memiliki satu elemen akar, yang menjadi induk dari semua elemen dalam dokumen XML. Pengurai XML dirancang menjadi sangat ketat, dan akan berhenti melakukan penguraian terhadap dokumen yang cacat. Oleh karena itu semua dokumen XML harus mengikuti [Aturan Sintaks XML](http://www.w3schools.com/xml/xml_syntax.asp). ```xml Konten Teks Teks Teks ``` ## Dokumen XML ```xml Everyday Italian Giada De Laurentiis 2005 30.00 Harry Potter J K. Rowling 2005 29.99 Learning XML Erik T. Ray 2003 39.95 komputer.gif ``` ## Dokumen yang well-formated & Validasi Sebuah dokumen XML disebut well-formated jika sintaksisnya benar. Namun, juga mungkin untuk mendefinisikan lebih banyak batasan dalam dokumen, menggunakan definisi dokumen, seperti DTD dan XML Schema. Sebuah dokumen XML yang mengikuti definisi dokumen disebut valid, jika sesuai dokumen itu. Dengan alat ini, Anda dapat memeriksa data XML di luar logika aplikasi. ```xml Everyday Italian 30.00 ]> ]> Everyday Italian 30.00 ``` ## Kompatibilitas DTD dan Definisi Skema XML Dukungan untuk DTD dapat ditemukan dimana-mana karena sudah sangat lama. Namun sayangnya, fitur XML terkini seperti *namespaces* tidak didukung oleh DTD. XML Xchema Definitions (XSDs) bertujuan untuk mengganti DTD dalam mendefinisikan tatabahasa dokumen XML. ## Sumber * [Validasi dokumen XML](http://www.xmlvalidation.com) ## Bacaan lainnya * [XML Schema Definitions Tutorial](http://www.w3schools.com/schema/) * [DTD Tutorial](http://www.w3schools.com/xml/xml_dtd_intro.asp) * [XML Tutorial](http://www.w3schools.com/xml/default.asp) * [Using XPath queries to parse XML](http://www.w3schools.com/xml/xml_xpath.asp) ================================================ FILE: inform7.md ================================================ --- name: Inform7 contributors: - ["Hyphz", "http://github.com/hyphz/"] filename: LearnInform.Inform --- Inform 7 is a natural language based language created by Graham Nelson and Emily Short for writing text adventures, but also potentially usable for other text based applications, especially data backed ones. ```inform7 [This is a comment.] [Inform 7 is a language designed for building text adventures. It can be used for other purposes too, although the default library builds a text adventure. Inform 7 is object oriented.] [This creates a class by subclassing. "Value" is the universal subclass, but "object" is the most basic that behaves like an OO object.] A datablock is a kind of object. [Classes can have properties.] A datablock can be broken. [This creates a boolean property.] A datablock is usually not broken. [This sets its default value.] A datablock can be big or small. [This creates an enumerated property.] A datablock is usually small. [This sets its default value.] A datablock has a number called the sequence number. [This creates a typed property.] A datablock has some text called the name. ["Some text" means a string.] A datablock has a datablock called the chain. [Declared classes become types.] [This creates a global named instance.] Block1 is a datablock. The sequence number of Block1 is 1. The name of Block1 is "Block One." [Functions and procedures are defined as "phrases".] To do the thing everyone does with their first program: say "Hello World.". [Full stop indicates the end, indent indicates the scope.] To dump (the block - a datablock): [That's how we create a parameter.] say the sequence number of the block; say the name of the block; if the block is broken, say "(Broken)". To toggle (the block - a datablock): if the block is broken: [Conditional.] now the block is not broken; [Updating a property.] else: now the block is broken. [Multiple parameters.] To fix (the broken block - a datablock) using (the repair block - a datablock): if the broken block is not broken, stop; [Comma for a non indented single command.] if the repair block is broken, stop; now the sequence number of the broken block is the sequence number of the repair block; now the broken block is not broken. [Because of its text adventure origins, Inform 7 doesn't generally allow objects to be created dynamically, although there's a language extension that enables it.] Block2 is a datablock. Block2 is broken. The sequence number of Block2 is 2. The name of Block2 is "Block two." To demonstrate calling a phrase with two parameters: Let the second block be block2; [Local pointer variable.] fix the second block using Block1; say the sequence number of the second block. [1.] [Lists.] To show how to use list types: let the list be a list of datablocks; add Block1 to the list; add Block2 to the list; say the list; ["Block1 and Block2"] [Membership.] if Block1 is listed in the list: say "Block1 is there."; [Loop.] repeat with the block running through the list: dump the block; [1 Block One. 1 Block Two.] [Remember block two's sequence number was changed above.] let X be entry 2 of the list; [Counting starts at 1.] dump X; ["1 Block two."] remove X from the list; say the list. [Block1] [Here's how we define a function and do arithmetic.] To decide which number is the sum of all numbers up to (X - a number) (this is summing up): let the total so far be a number; repeat with the current number running from 1 to X: now the total so far is the total so far + the current number; decide on the total so far. [This is the return statement.] [ We have higher order functions too. ] To demonstrate a higher order function: say summing up applied to {1, 2, 3, 4}. To decide which number is the result of applying (phrase - phrase A -> A) twice to (B - a value of kind A): let b1 be phrase applied to B; let b2 be phrase applied to b1; decide on b2. To demonstrate defining a higher order function: let X be 5; say the result of applying summing up twice to X. [ Rulebooks allow a number of functions which apply to the same type under different conditions to be stacked. ] Datablock validation rules is a datablock based rulebook. A datablock validation rule for a broken datablock: rule fails. A datablock validation rule for a datablock (called the block): dump the block; rule succeeds. To demonstrate invoking a rulebook: follow datablock validation rules for Block1; follow datablock validation rules for Block2. [ Objects can also have relations, which resemble those in a relational database. ] A dog is a kind of thing. Rover is a dog. The kennel is a container. [This is a built in base class.] Rover is in the kennel. [This creates an inbuilt relation called "containment".] [We can create relations by declaring their type.] Guide dog ownership relates one dog to one person. [One-to-one.] Property ownership relates various things to one person. [Many-to-one.] Friendship relates various people to various people. [Many-to-many.] [To actually use them we must assign verbs or prepositions to them.] The verb to own means the property ownership relation. The verb to be the guide dog of means the guide dog ownership relation. The verb to be guided by means the reversed guide dog ownership relation. The verb to be friends with means the friendship relation. Edward is a person. A person can be blind. Edward is blind. Edward is guided by Rover. Benny is a person. Edward is friends with Benny. To demonstrate looking something up with a relation: repeat with the dog running through things that are the guide dog of Edward: say the dog; repeat with the friend running through things that are friends with Edward: say the friend. [We can also define relations that exist procedurally.] Helpfulness relates a person (called the helper) to a person (called the helpee) when the helpee is blind and the helper is not blind. The verb to be helpful to means the helpfulness relation. To demonstrate using a procedural relation: repeat with the helper running through people that are helpful to Edward: say the helper. [ Interface to the text adventure harness to allow the above code to be run. ] Tutorial room is a room. "A rather strange room full of buttons. Push them to run the exercises, or turn on the robot to run them all." A button is a kind of thing. A button is fixed in place. The red button is a button in tutorial room. Instead of pushing the red button, do the thing everyone does with their first program. The green button is a button in tutorial room. Instead of pushing the green button, demonstrate calling a phrase with two parameters. The blue button is a button in tutorial room. Instead of pushing the blue button, show how to use list types. The cyan button is a button in tutorial room. Instead of pushing the cyan button, say the sum of all numbers up to 5. The purple button is a button in tutorial room. Instead of pushing the purple button, demonstrate a higher order function. The black button is a button in tutorial room. Instead of pushing the black button, demonstrate defining a higher order function. The white button is a button in tutorial room. Instead of pushing the white button, demonstrate invoking a rulebook. The puce button is a button in tutorial room. Instead of pushing the puce button, demonstrate looking something up with a relation. The orange button is a button in tutorial room. Instead of pushing the orange button, demonstrate using a procedural relation. The robot is an object in tutorial room. Instead of switching on the robot: say "The robot begins to frantically flail its arms about."; repeat with button running through buttons in the tutorial room: say "The robot randomly hits [the button]."; try pushing button. ``` ## Ready For More? * [Inform 7](http://www.inform7.com/) ================================================ FILE: it/asciidoc.md ================================================ --- contributors: - ["Ryan Mavilia", "http://unoriginality.rocks/"] - ["Abel Salgado Romero", "https://twitter.com/abelsromero"] translators: - ["Ale46", "https://github.com/ale46"] --- AsciiDoc è un linguaggio di markup simile a Markdown e può essere usato per qualsiasi cosa, dai libri ai blog. Creato nel 2002 da Stuart Rackman, questo linguaggio è semplice ma permette un buon numero di personalizzazioni. Intestazione Documento Le intestazioni sono opzionali e possono contenere linee vuote. Deve avere almeno una linea vuota rispetto al contenuto. Solo titolo ``` = Titolo documento Prima frase del documento. ``` Titolo ed Autore ``` = Titolo documento Primo Ultimo Inizio del documento ``` Autori multipli ``` = Titolo Documento John Doe ; Jane Doe; Black Beard Inizio di un documento con autori multipli. ``` Linea di revisione (richiede una linea autore) ``` = Titolo documento V1 Potato Man v1.0, 2016-01-13 Questo articolo sulle patatine sarà divertente. ``` Paragrafi ``` Non hai bisogno di nulla di speciale per i paragrafi. Aggiungi una riga vuota tra i paragrafi per separarli. Per creare una riga vuota aggiungi un + e riceverai una interruzione di linea! ``` Formattazione Testo ``` _underscore crea corsivo_ *asterischi per il grassetto* *_combinali per maggiore divertimento_* `usa i ticks per indicare il monospazio` `*spaziatura fissa in grassetto*` ``` Titoli di sezione ``` = Livello 0 (può essere utilizzato solo nell'intestazione del documento) == Livello 1

=== Livello 2

==== Livello 3

===== Livello 4

``` Liste Per creare un elenco puntato, utilizzare gli asterischi. ``` * foo * bar * baz ``` Per creare un elenco numerato usa i periodi. ``` . item 1 . item 2 . item 3 ``` È possibile nidificare elenchi aggiungendo asterischi o periodi aggiuntivi fino a cinque volte. ``` * foo 1 ** foo 2 *** foo 3 **** foo 4 ***** foo 5 . foo 1 .. foo 2 ... foo 3 .... foo 4 ..... foo 5 ``` ## Ulteriori letture Esistono due strumenti per elaborare i documenti AsciiDoc: 1. [AsciiDoc](http://asciidoc.org/): implementazione Python originale, disponibile nelle principali distribuzioni Linux. Stabile e attualmente in modalità di manutenzione. 2. [Asciidoctor](http://asciidoctor.org/): implementazione alternativa di Ruby, utilizzabile anche da Java e JavaScript. In fase di sviluppo attivo, mira ad estendere la sintassi AsciiDoc con nuove funzionalità e formati di output. I seguenti collegamenti sono relativi all'implementazione di `Asciidoctor`: * [Markdown - AsciiDoc comparazione sintassi](http://asciidoctor.org/docs/user-manual/#comparison-by-example): confronto affiancato di elementi di Markdown e AsciiDoc comuni. * [Per iniziare](http://asciidoctor.org/docs/#get-started-with-asciidoctor): installazione e guide rapide per il rendering di documenti semplici. * [Asciidoctor Manuale Utente](http://asciidoctor.org/docs/user-manual/): manuale completo con riferimento alla sintassi, esempi, strumenti di rendering, tra gli altri. ================================================ FILE: it/bash.md ================================================ --- contributors: - ["Max Yankov", "https://github.com/golergka"] - ["Darren Lin", "https://github.com/CogBear"] - ["Alexandre Medeiros", "http://alemedeiros.sdf.org"] - ["Denis Arh", "https://github.com/darh"] - ["akirahirose", "https://twitter.com/akirahirose"] - ["Anton Strömkvist", "http://lutic.org/"] - ["Rahil Momin", "https://github.com/iamrahil"] - ["Gregrory Kielian", "https://github.com/gskielian"] - ["Etan Reisner", "https://github.com/deryni"] - ["Jonathan Wang", "https://github.com/Jonathansw"] - ["Leo Rudberg", "https://github.com/LOZORD"] - ["Betsy Lorton", "https://github.com/schbetsy"] - ["John Detter", "https://github.com/jdetter"] translators: - ["Robert Margelli", "http://github.com/sinkswim/"] - ["Tommaso Pifferi", "http://github.com/neslinesli93/"] --- Bash è il nome della shell di unix, la quale è stata distribuita anche come shell del sistema oprativo GNU e la shell di default su Linux e macOS. Quasi tutti gli esempi sottostanti possono fare parte di uno shell script o eseguiti direttamente nella shell. ```bash #!/bin/bash # La prima riga dello script è lo shebang il quale dice al sistema come eseguire # lo script: http://it.wikipedia.org/wiki/Shabang # Come avrai già immaginato, i commenti iniziano con #. Lo shebang stesso è un commento. # Semplice esempio ciao mondo: echo Ciao mondo! # Ogni comando inizia su una nuova riga, o dopo un punto e virgola: echo 'Questa è la prima riga'; echo 'Questa è la seconda riga' # Per dichiarare una variabile: Variabile="Una stringa" # Ma non così: Variabile = "Una stringa" # Bash stabilirà che Variabile è un comando da eseguire e darà un errore # perchè non esiste. # Usare la variabile: echo $Variabile echo "$Variabile" echo '$Variabile' # Quando usi la variabile stessa - assegnala, esportala, oppure — scrivi # il suo nome senza $. Se vuoi usare il valore della variabile, devi usare $. # Nota che ' (singolo apice) non espande le variabili! # Espansione dei parametri ${ }: echo ${Variabile} # Questo è un esempio semplice dell'espansione dei parametri. # L'espansione dei parametri prende il valore di una variabile, ed appunto lo "espande" o lo stampa. # Durante l'espansione il valore o il parametro passato possono essere modificati. # Sotto ci sono altri esempi che analizzano l'uso dell'espansione dei parametri. # Sostituzione di stringhe nelle variabili echo ${Variabile/Una/La} # Questo sostituirà la prima occorrenza di "Una" con "La" # Sottostringa di una variabile Lunghezza=7 echo ${Variabile:0:Lunghezza} # Questo ritornerà solamente i primi 7 caratteri # Valore di default per la variabile echo ${Foo:-"ValoreDiDefaultSeFooMancaOppureÈVuoto"} # Questo funziona per null (Foo=), stringa vuota (Foo=""), zero (Foo=0) ritorna 0 # Nota: viene ritornato il valore di default, il contenuto della variabile pero' non cambia. # Espansione delle graffe { } # Viene usata per generare stringe in modo arbitrario echo {1..10} echo {a..z} # Con questi comandi viene stampato l'intervallo dal valore iniziale al valore finale (i numeri da 1 a 10, le lettere dell'alfabeto) # Variabili builtin: # Ci sono delle variabili builtin molto utili, come echo "Valore di ritorno dell'ultimo programma eseguito: $?" echo "PID dello script: $$" echo "Numero di argomenti: $#" echo "Argomenti dello script: $@" echo "Argomenti dello script separati in variabili distinte: $1 $2..." # Adesso che sappiamo come stampare a schermo, e come usare le variabili, possiamo andare avanti con le basi di bash! # Per conoscere la directory su cui siamo posizionati, è sufficiente usare `pwd`. # `pwd` è l'acronimo di "print working directory", ovvero "stampa la directory corrente". # Possiamo anche usare la variabile builtin `$PWD`. # Prova questi due esempi, e vedi che il risultato è lo stesso: echo "Sono dentro $(pwd)" # esegue `pwd` ed interpola l'output echo "Sono dentro $PWD" # interpola direttamente la variabile builtin # Se c'è troppo testo nel terminale, ottenuto scrivendo comandi oppure eseguendo uno script, il comando `clear` pulisce lo schermo clear # Puoi utilizzare anche Ctrl-L al posto di clear # Leggere un valore di input: echo "Come ti chiami?" read Nome # Nota che non abbiamo dovuto dichiarare una nuova variabile echo Ciao, $Nome! # Classica struttura if: # usa 'man test' per maggiori informazioni sulle condizionali if [ $Nome -ne $USER ] then echo "Il tuo nome non è lo username" else echo "Il tuo nome è lo username" fi # Nota: se $Name è vuoto, la condizione precedente viene interpretata come: if [ -ne $USER ] # che genera un errore di sintassi. Quindi il metodo sicuro per usare # variabili che possono contenere stringhe vuote è il seguente: if [ "$Name" -ne $USER ] ... # che viene interpretato come: if [ "" -ne $USER ] ... # e dunque funziona correttamente. # C'è anche l'esecuzione condizionale echo "Sempre eseguito" || echo "Eseguito solo se la prima condizione fallisce" echo "Sempre eseguito" && echo "Eseguito solo se la prima condizione NON fallisce" # Per usare && e || con l'if, c'è bisogno di piu' paia di parentesi quadre: if [ "$Nome" == "Steve" ] && [ "$Eta" -eq 15 ] then echo "Questo verrà eseguito se $Nome è Steve E $Eta è 15." fi if [ "$Nome" == "Daniya" ] || [ "$Nome" == "Zach" ] then echo "Questo verrà eseguito se $Nome è Daniya O Zach." fi # C'è anche l'operatore `=~`, che serve per confrontare una stringa con un'espressione regolare: Email=me@example.com if [[ "$Email" =~ [a-z]+@[a-z]{2,}\.(com|net|org) ]] then echo "Email valida!" fi # L'operatore =~ funziona solo dentro alle doppie parentesi quadre [[ ]], # che hanno un comportamento leggermente diverso rispetto alle singole [ ]. # Se vuoi approfondire, visita questo link (in inglese): # https://www.gnu.org/software/bash/manual/bashref.html#Conditional-Constructs # Usando `alias`, puoi definire nuovi comandi o modificare quelli già esistenti. # Ad esempio, così puoi ridefinire il comando ping per inviare solo 5 pacchetti alias ping='ping -c 5' # "Scavalca" l'alias e usa il comando vero, utilizzando il backslash \ping 192.168.1.1 # Stampa la lista di tutti gli alias alias -p # Le espressioni sono nel seguente formato: echo $(( 10 + 5 )) # A differenza di altri linguaggi di programmazione, bash è una shell - quindi lavora nel contesto # della cartella corrente. Puoi elencare i file e le cartelle nella cartella # corrente con il comando ls: ls # Questi comandi hanno opzioni che controllano la loro esecuzione: ls -l # Elenca tutti i file e le cartelle su una riga separata ls -t # Ordina i contenuti della cartella in base all'ultima data di modifica (ordine decrescente) ls -R # Esegue `ls` in modo ricorsivo all'interno di questa cartella e tutte le sottocartelle # I risultati del comando precedente possono essere passati al comando successivo come input. # Il comando grep filtra l'input con il pattern passato. Ecco come possiamo elencare i # file .txt nella cartella corrente: ls -l | grep "\.txt" # Usa `cat` per stampare il contenuto dei file a schermo: cat file.txt # Possiamo leggere il contenuto di un file e memorizzarlo in una variabile, sempre usando `cat`: Contenuti=$(cat file.txt) echo "INIZIO DEL FILE\n$Contenuti\nFINE DEL FILE" # Usa `cp` per copiare file o cartelle da un punto all'altro del sistema. # `cp` crea NUOVE versioni dei file, quindi le modifiche della copia non hanno effetto sull'originale, e viceversa. # Nota che il file (o la cartella) di destinazione vengono sovrascritte se già esistono! cp fileSorgente.txt copia.txt cp -r cartellaSorgente/ destinazione/ # copia ricorsiva # Se hai bisogno di trasferire file tra computer, puoi usare `scp` o `sftp`. # `scp` ha una sintassi simile a `cp`. # `sftp` invece è più interattivo. # Usa `mv` per spostare file o cartella da un punto all'altro del sistema. # `mv` è simile a `cp`, ma cancella il file(o la cartella) sorgente. # `mv` è molto utile anche per rinominare i file! mv s0rg3nt3.txt dst.txt # mi spiace anonymous... # Dal momento che bash lavora nel contesto della cartella corrente, potresti voler eseguire il comando dentro a qualche altra cartella. Per fare questo si usa `cd`: cd ~ # va nella cartella Home cd .. # va nella cartella "padre" # (ad esempio da /home/user/Download a /home/user) cd /home/user/Documenti # entra nella cartella specificata cd ~/Documenti/.. # siamo sempre nella cartella home... vero? # Usa le subshell per lavorare in cartelle diverse contemporaneamente (echo "All'inizio sono qua: $PWD") && (cd cartella; echo "Adesso invece sono qua: $PWD") pwd # siamo sempre nella prima cartella # Usa `mkdir` per creare nuove cartelle mkdir nuovaCartella # Il flag `-p` indica la creazione delle cartelle intermedie, se non esistono. mkdir nuovaCartella/con/tante/cartelle/intermedie # Puoi redirezionare l'input e l'output del comando (stdin, stdout, e stderr). # Leggi da stdin finchè ^EOF$ e sovrascrivi hello.py con le righe # comprese tra "EOF": cat > hello.py << EOF #!/usr/bin/env python from __future__ import print_function import sys print("#stdout", file=sys.stdout) print("#stderr", file=sys.stderr) for line in sys.stdin: print(line, file=sys.stdout) EOF # Esegui hello.py con diverse redirezioni stdin, stdout, e stderr: python hello.py < "input.in" python hello.py > "output.out" python hello.py 2> "error.err" python hello.py > "output-and-error.log" 2>&1 python hello.py > /dev/null 2>&1 # Lo output error sovrascriverà il file se esiste, # se invece vuoi appendere usa ">>": python hello.py >> "output.out" 2>> "error.err" # Sovrascrivi output.out, appendi a error.err, e conta le righe: info bash 'Basic Shell Features' 'Redirections' > output.out 2>> error.err wc -l output.out error.err # Esegui un comando e stampa il suo file descriptor (esempio: /dev/fd/123) # vedi: man fd echo <(echo "#ciaomondo") # Sovrascrivi output.out con "#helloworld": cat > output.out <(echo "#helloworld") echo "#helloworld" > output.out echo "#helloworld" | cat > output.out echo "#helloworld" | tee output.out >/dev/null # Pulisci i file temporanei verbosamente (aggiungi '-i' per la modalità interattiva) # Attenzione: il comando `rm` non può essere annullato! rm -v output.out error.err output-and-error.log rm -r cartellaTemporanea/ # cancella ricorsivamente # I comandi possono essere sostituiti con altri comandi usando $( ): # Il comando seguente mostra il numero di file e cartelle nella # cartella corrente. echo "Ci sono $(ls | wc -l) oggetti qui." # Lo stesso puo' essere usato usando backticks `` ma non possono essere innestati - il modo migliore # è usando $( ). echo "Ci sono `ls | wc -l` oggetti qui." # Bash utilizza uno statemente case che funziona in maniera simile allo switch in Java e C++: case "$Variabile" in #Lista di pattern per le condizioni che vuoi soddisfare 0) echo "C'è uno zero.";; 1) echo "C'è un uno.";; *) echo "Non è null.";; esac # I cicli for iterano per ogni argomento fornito: # I contenuti di $Variabile sono stampati tre volte. for Variabile in {1..3} do echo "$Variabile" done # O scrivilo con il "ciclo for tradizionale": for ((a=1; a <= 3; a++)) do echo $a done # Possono essere usati anche per agire su file.. # Questo eseguirà il comando 'cat' su file1 e file2 for Variabile in file1 file2 do cat "$Variabile" done # ..o dall'output di un comando # Questo eseguirà cat sull'output di ls. for Output in $(ls) do cat "$Output" done # while loop: while [ true ] do echo "corpo del loop..." break done # Puoi anche definire funzioni # Definizione: function foo () { echo "Gli argomenti funzionano come gli argomenti dello script: $@" echo "E: $1 $2..." echo "Questa è una funzione" return 0 } # o semplicemente bar () { echo "Un altro modo per dichiarare funzioni!" return 0 } # Per chiamare la funzione foo "Il mio nome è" $Nome # Ci sono un sacco di comandi utili che dovresti imparare: # stampa le ultime 10 righe di file.txt tail -n 10 file.txt # stampa le prime 10 righe di file.txt head -n 10 file.txt # ordina le righe di file.txt sort file.txt # riporta o ometti le righe ripetute, con -d le riporta uniq -d file.txt # stampa solamente la prima colonna prima del carattere ',' cut -d ',' -f 1 file.txt # sostituisce ogni occorrenza di 'okay' con 'great' in file.txt (compatible con le regex) sed -i 's/okay/great/g' file.txt # stampa su stdout tutte le righe di file.txt che soddisfano una certa regex # L'esempio stampa le righe che iniziano con "foo" e che finiscono con "bar" grep "^foo.*bar$" file.txt # passa l'opzione "-c" per stampare invece il numero delle righe che soddisfano la regex grep -c "^foo.*bar$" file.txt # Altre opzioni utili possono essere: grep -r "^foo.*bar$" someDir/ # esegue `grep` ricorsivamente nella cartella grep -n "^foo.*bar$" file.txt # stampa il numero delle righe del file grep -rI "^foo.*bar$" someDir/ # esegue `grep` ricorsivamente nella cartella, ignorando i file non testuali # Esegue la stessa ricerca iniziale, ma filtrando solo le righe che contengono la stringa "baz" grep "^foo.*bar$" file.txt | grep -v "baz" # se vuoi letteralmente cercare la stringa, # e non la regex, usa fgrep (o grep -F) fgrep "foobar" file.txt # Il comando trap permette di eseguire un comando quando un segnale viene ricevuto dal tuo script. # In questo esempio, trap eseguirà rm se uno dei tre segnali (SIGHUP, SIGINT o SIGTERM) viene ricevuto. trap "rm $TEMP_FILE; exit" SIGHUP SIGINT SIGTERM # `sudo` viene usato per eseguire comandi come superuser, ovvero come utente che ha maggiori privilegi all'interno del sistema $NOME1=$(whoami) $NOME2=$(sudo whoami) echo "Ero $NOME1, poi sono diventato più potente: $NOME2" # Leggi la documentazione dei builtin di bash con il builtin 'help' di bash: help help help help for help return help source help . # Leggi la manpage di bash con man apropos bash man 1 bash man bash # Leggi la documentazione con info (? per help) apropos info | grep '^info.*(' man info info info info 5 info # Leggi la documentazione di bash: info bash info bash 'Bash Features' info bash 6 info --apropos bash ``` [Per saperne di più.](https://www.gnu.org/software/bash/manual/bashref.html) ================================================ FILE: it/bf.md ================================================ --- filename: learnbf.bf contributors: - ["Prajit Ramachandran", "http://prajitr.github.io/"] - ["Mathias Bynens", "http://mathiasbynens.be/"] translators: - ["Ivan Sala", "http://slavni96.github.io/"] - ["Christian Grasso", "http://chris54721.net"] --- Brainfuck è un linguaggio di programmazione [Turing equivalente](https://it.wikipedia.org/wiki/Turing_equivalenza) estremamente minimale, composto da solo 8 comandi. Puoi provarlo nel tuo browser utilizzando [brainfuck-visualizer](http://fatiherikli.github.io/brainfuck-visualizer/). ```bf Qualsiasi carattere diverso da "><+-.,[]" (escludendo gli apici) viene ignorato. Branfuck è caratterizzato da un array di 30,000 celle inizializzate a zero e da un puntatore che punta alla cella corrente. Vi sono otto comandi: + : Incrementa il valore della cella attuale di uno. - : Decrementa il valore della cella attuale di uno. > : Sposta il puntatore sulla cella seguente (sulla destra). < : Sposta il puntatore sulla cella precendete (sulla sinistra). . : Stampa il valore ASCII della cella corrente. (es. 65 = 'A') , : Legge un singolo carattere come input e lo salva nella cella corrente. [ : Se il valore della cella corrente è zero, prosegue fino alla ] corrispondente. Altrimenti, passa alla prossima istruzione. ] : Se il valore della cella corrente è zero, passa alla prossima istruzione. Altrimenti, torna indietro fino alla [ corrispondente. [ e ] formano un ciclo while. Ovviamente dovranno essere bilanciati. (Ad ogni [ dovrà corrispondere una ]) Ecco alcuni semplici esempi di programmi scritti in Brainfuck: ++++++ [ > ++++++++++ < - ] > +++++ . Questo programma stampa in output la lettera 'A'. Prima di tutto, incrementa la cella #1 fino al valore 6. La cella #1 verrà utilizzata per il ciclo. Poi, entra nel ciclo ([) e si sposta alla cella #2. Incrementa la cella #2 10 volte, torna alla cella #1, e decrementa quest'ultima. Il ciclo si ripete 6 volte (la cella #1 viene decrementata 6 volte prima di raggiungere lo 0, quindi prosegue oltre la corrispondente ]). A questo punto, siamo sulla cella #1, che ha valore 0, mentre la cella #2 ha valore 60. Ci spostiamo sulla cella #2, la incrementiamo per 5 volte, ottenendo il valore 65, quindi stampiamo il valore della cella #2. Il valore 65 equivale ad 'A' in ASCII, per cui viene stampato 'A' nel terminale. , [ > + < - ] > . Questo programma legge un carattere come input dall'utente, quindi salva il carattere nella cella #1. Dopodichè entra in un ciclo. Si sposta alla cella #2, incrementa quest'ultima, torna alla cella #1, e decrementa quest'ultima. Il ciclo continua fino a quando la cella #1 diventa 0, e quindi la cella #2 avrà il valore iniziale della cella #1. Infine, visto che ci troviamo sulla cella #1 alla fine del ciclo, si sposta sulla cella #2 e stampa il valore in ASCII. Gli spazi nel codice sovrastante sono presenti solo a scopo di ottenere una maggiore leggibilità. Lo stesso programma poteva essere scritto senza spazi: ,[>+<-]>. Proviamo, adesso, a capire cosa fa invece questo programma: ,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> Il programma legge 2 numeri come input dall'utente, e li moltiplica. Innanzitutto, legge in input i due numeri. Poi entra nel ciclo più esterno basandosi sulla cella #1. Quindi si sposta sulla cella #2, e inizia il ciclo più interno basandosi sul valore della cella #2, incrementando la cella #3. Arrivati a questo punto abbiamo un problema: alla fine del ciclo interno la cella #2 avrà valore 0. Ciò impedirà di eseguire nuovamente il ciclo interno. Per ovviare a questo problema, incrementiamo anche la cella #4, e copiamo il valore di quest'ultima nella cella #2. Il risultato sarà infine contenuto nella cella #3. ``` E questo è brainfuck. Non è così difficile, eh? Se vuoi, ora puoi scrivere per divertimento altri programmi in brainfuck, oppure scrivere un interprete brainfuck in un altro linguaggio. L'interprete è abbastanza semplice da implementare, ma se sei veramente masochista, prova ad implementare un interprete brainfuck... in brainfuck. ================================================ FILE: it/c++.md ================================================ --- contributors: - ["Steven Basart", "http://github.com/xksteven"] - ["Matt Kline", "https://github.com/mrkline"] - ["Geoff Liu", "http://geoffliu.me"] - ["Connor Waters", "http://github.com/connorwaters"] translators: - ["Robert Margelli", "http://github.com/sinkswim/"] - ["Tommaso Pifferi", "http://github.com/neslinesli93/"] --- Il C++ è un linguaggio di programmazione il quale, [secondo il suo inventore Bjarne Stroustrup](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote), è stato progettato per - essere un "miglior C" - supportare l'astrazione dei dati - supportare la programmazione orientata agli oggetti - supportare la programmazione generica Nonostante la sintassi possa risultare più difficile o complessa di linguaggi più recenti, è usato in maniera vasta poichè viene compilato in istruzioni macchina che possono essere eseguite direttamente dal processore ed offre un controllo stretto sull'hardware (come il linguaggio C) ed allo stesso tempo offre caratteristiche ad alto livello come i generici, le eccezioni, e le classi. Questa combinazione di velocità e funzionalità rende il C++ uno dei più utilizzati linguaggi di programmazione. ```c++ ////////////////// // Confronto con il C ////////////////// // Il C++ è _quasi_ un superset del C e con esso condivide la sintassi di base per // la dichiarazione di variabili, tipi primitivi, e funzioni. // Proprio come nel C, l'inizio del programma è una funzione chiamata // main con un intero come tipo di ritorno, // Questo valore serve come stato d'uscita del programma. // Vedi http://it.wikipedia.org/wiki/Valore_di_uscita per maggiori informazioni. int main(int argc, char** argv) { // Gli argomenti a linea di comando sono passati tramite argc e argv così come // avviene in C. // argc indica il numero di argomenti, // e argv è un array di stringhe in stile-C (char*) // che rappresenta gli argomenti. // Il primo argomento è il nome che è stato assegnato al programma. // argc e argv possono essere omessi se non hai bisogno di argomenti, // in questa maniera la funzione avrà int main() come firma. // Lo stato di uscita 0 indica successo. return 0; } // Tuttavia, il C++ varia nei seguenti modi: // In C++, i caratteri come letterali sono dei char. sizeof('c') == sizeof(char) == 1 // In C, i caratteri come letterali sono degli interi. sizeof('c') == sizeof(int) // C++ ha prototipizzazione rigida void func(); // funziona che non accetta argomenti // In C void func(); // funzione che può accettare un qualsiasi numero di argomenti // Usa nullptr invece di NULL in C++ int* ip = nullptr; // Gli header C standard sono disponibili in C++, // ma sono prefissati con "c" e non hanno il suffisso ".h". #include int main() { printf("Ciao, mondo!\n"); return 0; } /////////////////////////////// // Overloading per le funzioni ////////////////////////////// // Il C++ supporta l'overloading per le funzioni // sia dato che ogni funzione accetta parametri diversi. void print(char const* myString) { printf("Stringa %s\n", myString); } void print(int myInt) { printf("Il mio int è %d", myInt); } int main() { print("Ciao"); // Viene chiamata void print(const char*) print(15); // Viene chiamata void print(int) } //////////////////////// // Argomenti di default /////////////////////// // Puoi fornire argomenti di default per una funzione // se non sono forniti dal chiamante. void faiQualcosaConInteri(int a = 1, int b = 4) { // fai qualcosa con gli interi qui } int main() { faiQualcosaConInteri(); // a = 1, b = 4 faiQualcosaConInteri(20); // a = 20, b = 4 faiQualcosaConInteri(20, 5); // a = 20, b = 5 } // Gli argomenti di default devono essere alla fine della lista degli argomenti. void dichiarazioneInvalida(int a = 1, int b) // Errore! { } ///////////// // Namespaces ///////////// // I namespaces forniscono visibilità separata per dichiarazioni di variabili, funzioni, // ed altro. // I namespaces possono essere annidati. namespace Primo { namespace Annidato { void foo() { printf("Questa è Primo::Annidato::foo\n"); } } // fine di namespace Annidato } // fine di namespace Primo namespace Secondo { void foo() { printf("Questa è Secondo::foo\n"); } } void foo() { printf("Questa è foo globale\n"); } int main() { // Include tutti i simboli del namespace Secondo nello scope attuale. // Osserva che chiamare semplicemente foo() non va più bene perché è ambiguo: // bisogna specificare se vogliamo chiamare foo definita nel namespace Secondo // o foo definita nel livello principale del programma. using namespace Secondo; Secondo::foo(); // stampa "Questa è Secondo::foo" Primo::Annidato::foo(); // stampa "Questa è Primo::Annidato::foo" ::foo(); // stampa "Questa è foo globale" } /////////////// // Input/Output /////////////// // L'input e l'output in C++ utilizza gli streams // cin, cout, e cerr i quali rappresentano stdin, stdout, e stderr. // << è l'operatore di inserzione >> è l'operatore di estrazione. #include // Include gli streams di I/O using namespace std; // Gli streams sono nel namespace std (libreria standard) int main() { int myInt; // Stampa su stdout (o terminalee/schermo) cout << "Inserisci il tuo numero preferito:\n"; // Prende l'input cin >> myInt; // cout può anche essere formattato cout << "Il tuo numero preferito è " << myInt << "\n"; // stampa "Il tuo numero preferito è " cerr << "Usato per messaggi di errore"; } //////////// // Stringhe /////////// // Le stringhe in C++ sono oggetti ed hanno molte funzioni membro #include using namespace std; // Anche le stringhe sono contenute nel namespace std (libreria standard) string myString = "Ciao"; string myOtherString = " Mondo"; // + è usato per la concatenazione. cout << myString + myOtherString; // "Ciao Mondo" cout << myString + " Bella"; // "Ciao Bella" // le stringhe in C++ possono essere modificate. myString.append(" Mario"); cout << myString; // "Ciao Mario" /////////////// // Riferimenti ////////////// // Oltre ai puntatori come quelli in C, // il C++ ha i _riferimenti_. // Questi non sono tipi puntatori che non possono essere riassegnati una volta settati // e non possono essere null. // Inoltre, essi hanno la stessa sintassi della variabile stessa: // * non è necessario per la dereferenziazione e // & ("indirizzo di") non è usato per l'assegnamento. using namespace std; string foo = "Io sono foo"; string bar = "Io sono bar"; string& fooRef = foo; // Questo crea un riferimento a foo. fooRef += ". Ciao!"; // Modifica foo attraverso il riferimento cout << fooRef; // Stampa "Io sono foo. Ciao!" // Non riassegna "fooRef". Questo è come scrivere "foo = bar", e // foo == "Io sono bar" // dopo questa riga. cout << &fooRef << endl; // Stampa l'indirizzo di foo fooRef = bar; cout << &fooRef << endl; // Stampa lo stesso l'indirizzo di foo cout << fooRef; // Stampa "Io sono bar" // L'indirizzo di fooRef rimane lo stesso, ovvero si riferisce ancora a foo. const string& barRef = bar; // Crea un riferimento const a bar. // Come in C, i valori const (i puntatori e i riferimenti) non possono essere modificati. barRef += ". Ciao!"; // Errore, i riferimenti const non possono essere modificati. // Facciamo un piccolo excursus: prima di approfondire ancora i riferimenti, è necessario // introdurre il concetto di oggetto temporaneo. Supponiamo di avere il seguente codice: string tempObjectFun() { ... } string retVal = tempObjectFun(); // Nella seconda riga si ha che: // - un oggetto di tipo stringa viene ritornato da tempObjectFun // - viene costruita una nuova stringa, utilizzando l'oggetto ritornato come // argomento per il costruttore // - l'oggetto ritornato da tempObjectFun viene distrutto // L'oggetto ritornato da tempObjectFun viene detto oggetto temporaneo. // Un oggetto temporaneo viene creato quando una funzione ritorna un oggetto, e viene // distrutto quando l'espressione che lo racchiude termina la sua esecuzione - questo // comportamento viene definito dallo standard, ma i compilatori possono modificarlo // a piacere. Cerca su google "return value optimization" se vuoi approfondire. // Dunque nel seguente codice: foo(bar(tempObjectFun())) // dando per scontato che foo e bar esistano, l'oggetto ritornato da tempObjectFun // è passato a bar ed è distrutto prima dell'invocazione di foo. // Tornando ai riferimenti, c'è un'eccezione a quanto appena detto. // Infatti un oggetto temporaneo "viene distrutto quando l'espressione // che lo racchiude termina la sua esecuzione", tranne quando è legato ad un // riferimento di tipo const. In tal caso la sua vita viene estesa per tutto // lo scope attuale: void constReferenceTempObjectFun() { // constRef riceve l'oggetto temporaneo, che non viene distrutto fino // alla fine di questa funzione. const string& constRef = tempObjectFun(); ... } // Un altro tipo di riferimento introdotto nel C++11 è specifico per gli // oggetti temporanei. Non puoi dichiarare una variabile di quel tipo, ma // ha la precedenza nella risoluzione degli overload: void someFun(string& s) { ... } // Riferimento normale void someFun(string&& s) { ... } // Riferimento ad un oggetto temporaneo string foo; someFun(foo); // Chiama la versione con il riferimento normale someFun(tempObjectFun()); // Chiama la versione con il riferimento temporaneo // Ad esempio potrai vedere questi due costruttori per std::basic_string: basic_string(const basic_string& other); basic_string(basic_string&& other); // L'idea è che se noi costruiamo una nuova stringa a partire da un oggetto temporaneo // (che in ogni caso verrà distrutto), possiamo avere un costruttore più efficiente // che in un certo senso "recupera" parti di quella stringa temporanea. // Ci si riferisce a questo concetto come "move semantics". ///////////////////// // Enum ///////////////////// // Gli enum sono un modo per assegnare un valore ad una costante, e sono // principalmente usati per rendere il codice più leggibile. enum ETipiMacchine { AlfaRomeo, Ferrari, SUV, Panda }; ETipiMacchine GetPreferredCarType() { return ETipiMacchine::Ferrari; } // Dal C++11 in poi c'è un modo molto semplice per assegnare un tipo ad un enum, // che può essere utile per la serializzazione dei dati o per convertire gli enum // tra il tipo desiderato e le rispettive costanti. enum ETipiMacchine : uint8_t { AlfaRomeo, // 0 Ferrari, // 1 SUV = 254, // 254 Ibrida // 255 }; void WriteByteToFile(uint8_t InputValue) { // Serializza InputValue in un file } void WritePreferredCarTypeToFile(ETipiMacchine InputCarType) { // L'enum viene implicitamente convertito ad un uint8_t poiché // è stato dichiarato come tale WriteByteToFile(InputCarType); } // D'altro canto potresti voler evitare che un enum venga accidentalmente convertito // in un intero o in un altro tipo, quindi è possibile create una classe enum che // impedisce la conversione implicita. enum class ETipiMacchine : uint8_t { AlfaRomeo, // 0 Ferrari, // 1 SUV = 254, // 254 Ibrida // 255 }; void WriteByteToFile(uint8_t InputValue) { // Serializza InputValue in un file } void WritePreferredCarTypeToFile(ETipiMacchine InputCarType) { // Il compilatore darà errore anche se ETipiMacchine è un uint8_t: questo // perchè abbiamo dichiarato l'enum come "enum class"! WriteByteToFile(InputCarType); } ////////////////////////////////////////////////// // Classi e programmazione orientata agli oggetti ///////////////////////////////////////////////// // Primo esempio delle classi #include // Dichiara una classe. // Le classi sono in genere dichiara in un header file (.h o .hpp). class Cane { // Variabili e funzioni membro sono private di default. std::string nome; int peso; // Tutti i membri dopo questo sono pubblici (public) // finchè "private:" o "protected:" non compaiono. public: // Costruttore di default Cane(); // Dichiarazioni di funzioni membro (le implentazioni sono a seguito) // Nota che stiamo usando std::string invece di porre // using namespace std; // sopra. // Mai usare uno statement "using namespace" in uno header. void impostaNome(const std::string& nomeCane); void impostaPeso(int pesoCane); // Le funzioni che non modificano lo stato dell'oggetto // dovrebbero essere marcate come const. // Questo permette di chiamarle con un riferimento const all'oggetto. // Inoltre, nota che le funzioni devono essere dichiarate espliciamente come _virtual_ // per essere sovrascritte in classi derivate. // Le funzioni non sono virtual di default per motivi di performance. virtual void print() const; // Le funzioni possono essere definite anche all'interno del corpo della classe. // Le funzioni definite in questo modo sono automaticamente inline. void abbaia() const { std::cout << nome << " abbaia!\n"; } // Assieme con i costruttori, il C++ fornisce i distruttori. // Questi sono chiamati quando un oggetto è rimosso o esce dalla visibilità. // Questo permette paradigmi potenti come il RAII // (vedi sotto) // I distruttori devono essere virtual per permettere a classi di essere // derivate da questa; altrimenti, il distruttore della classe derivata // non viene chiamato se l'oggetto viene distrutto tramite un riferimento alla // classe da cui ha ereditato o tramite un puntatore. virtual ~Dog(); }; // Un punto e virgola deve seguire la definizione della funzione // Le funzioni membro di una classe sono generalmente implementate in files .cpp . Cane::Cane() { std::cout << "Un cane è stato costruito\n"; } // Gli oggetti (ad esempio le stringhe) devono essere passati per riferimento // se li stai modificando o come riferimento const altrimenti. void Cane::impostaNome(const std::string& nomeCane) { nome = nomeCane; } void Cane::impostaPeso(int pesoCane) { peso = pesoCane; } // Notare che "virtual" è solamente necessario nelle dichiarazioni, non nelle definizioni. void Cane::print() const { std::cout << "Il cane è " << nome << " e pesa " << peso << "kg\n"; } Cane::~Cane() { std::cout << "Ciao ciao " << nome << "\n"; } int main() { Cane myDog; // stampa "Un cane è stato costruito" myDog.impostaNome("Barkley"); myDog.impostaPeso(10); myDog.print(); // stampa "Il cane è Barkley e pesa 10 kg" return 0; } // stampa "Ciao ciao Barkley" // Ereditarietà: // Questa classe eredita tutto ciò che è public e protected dalla classe Cane, // ma anche ciò che privato: tuttavia non potrà accedere direttamente a membri/metodi // privati se non c'è un metodo pubblico o privato che permetta di farlo. class MioCane : public Cane { void impostaProprietario(const std::string& proprietarioCane); // Sovrascrivi il comportamento della funzione print per tutti i MioCane. Vedi // http://it.wikipedia.org/wiki/Polimorfismo_%28informatica%29 // per una introduzione più generale se non sei familiare con // il polimorfismo. // La parola chiave override è opzionale ma fa sì che tu stia effettivamente // sovrascrivendo il metodo nella classe base. void print() const override; private: std::string proprietario; }; // Nel frattempo, nel file .cpp corrispondente: void MioCane::impostaProprietario(const std::string& proprietarioCane) { proprietario = proprietarioCane; } void MioCane::print() const { Cane::print(); // Chiama la funzione print nella classe base Cane std::cout << "Il cane è di " << proprietario << "\n"; // stampa "Il cane è e pesa " // "Il cane è di " } /////////////////////////////////////////////////// // Inizializzazione ed Overloading degli Operatori ////////////////////////////////////////////////// // In C++ puoi sovrascrivere il comportamento di operatori come +, -, *, /, ecc... // Questo è possibile definendo una funzione che viene chiamata // ogniqualvolta l'operatore è usato. #include using namespace std; class Punto { public: // Così si assegna alle variabili membro un valore di default. double x = 0; double y = 0; // Definisce un costruttore di default che non fa nulla // ma inizializza il Punto ai valori di default (0, 0) Punto() { }; // La sintassi seguente è nota come lista di inizializzazione // ed è il modo appropriato di inizializzare i valori membro della classe Punto (double a, double b) : x(a), y(b) { /* Non fa nulla eccetto inizializzare i valori */ } // Sovrascrivi l'operatore +. Punto operator+(const Punto& rhs) const; // Sovrascrivi l'operatore += Punto& operator+=(const Punto& rhs); // Avrebbe senso aggiungere gli operatori - e -=, // ma li saltiamo per rendere la guida più breve. }; Punto Punto::operator+(const Punto& rhs) const { // Crea un nuovo punto come somma di questo e di rhs. return Punto(x + rhs.x, y + rhs.y); } Punto& Punto::operator+=(const Punto& rhs) { x += rhs.x; y += rhs.y; return *this; } int main () { Punto su (0,1); Punto destro (1,0); // Questo chiama l'operatore + di Punto // Il Punto su chiama la funzione + con destro come argomento Punto risultato = su + destro; // Stampa "Risultato è spostato in (1,1)" cout << "Risultato è spostato (" << risultato.x << ',' << risultato.y << ")\n"; return 0; } ///////////////// // Templates //////////////// // Generalmente i templates in C++ sono utilizzati per programmazione generica, anche se // sono molto più potenti dei costrutti generici in altri linguaggi. Inoltre, // supportano specializzazione esplicita e parziale, classi in stile funzionale, // e sono anche complete per Turing. // Iniziamo con il tipo di programmazione generica con cui forse sei familiare. Per // definire una classe o una funzione che prende un parametro di un dato tipo: template class Box { public: // In questa classe, T può essere usato come qualsiasi tipo. void inserisci(const T&) { ... } }; // Durante la compilazione, il compilatore in effetti genera copie di ogni template // con i parametri sostituiti, e così la definizione completa della classe deve essere // presente ad ogni invocazione. Questo è il motivo per cui vedrai le classi template definite // interamente in header files. // Per instanziare una classe template sullo stack: Box intBox; // e puoi usarla come aspettato: intBox.inserisci(123); //Puoi, ovviamente, innestare i templates: Box > boxOfBox; boxOfBox.inserisci(intBox); // Fino al C++11, devi porre uno spazio tra le due '>', altrimenti '>>' // viene visto come l'operatore di shift destro. // Qualche volta vedrai // template // invece. La parole chiavi 'class' e 'typename' sono _generalmente_ // intercambiabili in questo caso. Per una spiegazione completa, vedi // http://en.wikipedia.org/wiki/Typename // (si, quella parola chiave ha una sua pagina di Wikipedia propria). // Similmente, una funzione template: template void abbaiaTreVolte(const T& input) { input.abbaia(); input.abbaia(); input.abbaia(); } // Nota che niente è specificato relativamente al tipo di parametri. Il compilatore // genererà e poi verificherà il tipo di ogni invocazione del template, così che // la funzione di cui sopra funzione con ogni tipo 'T' che ha const 'abbaia' come metodo! Cane fluffy; fluffy.impostaNome("Fluffy") abbaiaTreVolte(fluffy); // Stampa "Fluffy abbaia" tre volte. // I parametri template non devono essere classi: template void stampaMessaggio() { cout << "Impara il C++ in " << Y << " minuti!" << endl; } // E poi esplicitamente specializzare i template per avere codice più efficiente. Ovviamente, // la maggior parte delle casistiche reali non sono così triviali. // Notare che avrai comunque bisogna di dichiarare la funzione (o classe) come un template // anche se hai esplicitamente specificato tutti i parametri. template<> void stampaMessaggio<10>() { cout << "Impara il C++ più velocemente in soli 10 minuti!" << endl; } printMessage<20>(); // Stampa "impara il C++ in 20 minuti!" printMessage<10>(); // Stampa "Impara il C++ più velocemente in soli 10 minuti!" //////////////////////////// // Gestione delle eccezioni /////////////////////////// // La libreria standard fornisce un paio di tipi d'eccezioni // (vedi http://en.cppreference.com/w/cpp/error/exception) // ma ogni tipo può essere lanciato come eccezione #include #include // Tutte le eccezioni lanciate all'interno del blocco _try_ possono essere catturate dai successivi // handlers _catch_. try { // Non allocare eccezioni nello heap usando _new_. throw std::runtime_error("C'è stato un problema."); } // Cattura le eccezioni come riferimenti const se sono oggetti catch (const std::exception& ex) { std::cout << ex.what(); } // Cattura ogni eccezioni non catturata dal blocco _catch_ precedente catch (...) { std::cout << "Catturata un'eccezione sconosciuta"; throw; // Rilancia l'eccezione } /////// // RAII /////// // RAII sta per "Resource Allocation Is Initialization". // Spesso viene considerato come il più potente paradigma in C++. // È un concetto semplice: un costruttore di un oggetto // acquisisce le risorse di tale oggetto ed il distruttore le rilascia. // Per comprendere come questo sia vantaggioso, // consideriamo una funzione che usa un gestore di file in C: void faiQualcosaConUnFile(const char* nomefile) { // Per cominciare, assumiamo che niente possa fallire. FILE* fh = fopen(nomefile, "r"); // Apri il file in modalità lettura. faiQualcosaConIlFile(fh); faiQualcosAltroConEsso(fh); fclose(fh); // Chiudi il gestore di file. } // Sfortunatamente, le cose vengono complicate dalla gestione degli errori. // Supponiamo che fopen fallisca, e che faiQualcosaConUnFile e // faiQualcosAltroConEsso ritornano codici d'errore se falliscono. // (Le eccezioni sono la maniera preferita per gestire i fallimenti, // ma alcuni programmatori, specialmente quelli con un passato in C, // non sono d'accordo con l'utilità delle eccezioni). // Adesso dobbiamo verificare che ogni chiamata per eventuali fallimenti e chiudere il gestore di file // se un problema è avvenuto. bool faiQualcosaConUnFile(const char* nomefile) { FILE* fh = fopen(nomefile, "r"); // Apre il file in modalità lettura if (fh == nullptr) // Il puntatore restituito è null in caso di fallimento. return false; // Riporta il fallimento al chiamante. // Assumiamo che ogni funzione ritorni false se ha fallito if (!faiQualcosaConIlFile(fh)) { fclose(fh); // Chiude il gestore di file così che non sprechi memoria. return false; // Propaga l'errore. } if (!faiQualcosAltroConEsso(fh)) { fclose(fh); // Chiude il gestore di file così che non sprechi memoria. return false; // Propaga l'errore. } fclose(fh); // Chiudi il gestore di file così che non sprechi memoria. return true; // Indica successo } // I programmatori C in genere puliscono questa procedura usando goto: bool faiQualcosaConUnFile(const char* nomefile) { FILE* fh = fopen(nomefile, "r"); if (fh == nullptr) return false; if (!faiQualcosaConIlFile(fh)) goto fallimento; if (!faiQualcosAltroConEsso(fh)) goto fallimento; fclose(fh); // Chiude il file return true; // Indica successo fallimento: fclose(fh); return false; // Propaga l'errore } // Se le funzioni indicano errori usando le eccezioni, // le cose sono un pò più pulite, ma sono sempre sub-ottimali. void faiQualcosaConUnFile(const char* nomefile) { FILE* fh = fopen(nomefile, "r"); // Apre il file in modalità lettura if (fh == nullptr) throw std::runtime_error("Errore nell'apertura del file."); try { faiQualcosaConIlFile(fh); faiQualcosAltroConEsso(fh); } catch (...) { fclose(fh); // Fai sì che il file venga chiuso se si ha un errore. throw; // Poi rilancia l'eccezione. } fclose(fh); // Chiudi il file // Tutto è andato bene } // Confronta questo con l'utilizzo della classe C++ file stream (fstream) // fstream usa i distruttori per chiudere il file. // Come detto sopra, i distruttori sono automaticamente chiamati // ogniqualvolta un oggetto esce dalla visibilità. void faiQualcosaConUnFile(const std::string& nomefile) { // ifstream è l'abbreviazione di input file stream std::ifstream fh(nomefile); // Apre il file // Fai qualcosa con il file faiQualcosaConIlFile(fh); faiQualcosAltroConEsso(fh); } // Il file viene chiuso automaticamente chiuso qui dal distruttore // Questo ha vantaggi _enormi_: // 1. Può succedere di tutto ma // la risorsa (in questo caso il file handler) verrà ripulito. // Una volta che scrivi il distruttore correttamente, // È _impossibile_ scordarsi di chiudere l'handler e sprecare memoria. // 2. Nota che il codice è molto più pulito. // Il distruttore gestisce la chiusura del file dietro le scene // senza che tu debba preoccupartene. // 3. Il codice è sicuro da eccezioni. // Una eccezione può essere lanciata in qualunque punto nella funzione e la ripulitura // avverrà lo stesso. // Tutto il codice C++ idiomatico usa RAII in maniera vasta su tutte le risorse. // Esempi aggiuntivi includono // - Utilizzo della memoria con unique_ptr e shared_ptr // - I contenitori - la lista della libreria standard, // vettori (i.e. array auto-aggiustati), mappe hash, e così via // sono tutti automaticamente distrutti con i loro contenuti quando escono dalla visibilità. // - I mutex usano lock_guard e unique_lock // I contenitori che utilizzano chiavi non-primitive (classi personalizzate) // richiedono la funzione di confronto nell'oggetto stesso, o tramite un puntatore a funzione. // Le chiavi primitive hanno funzioni di confronto già definite, ma puoi sovrascriverle. class Foo { public: int j; Foo(int a) : j(a) {} }; struct funzioneDiConfronto { bool operator()(const Foo& a, const Foo& b) const { return a.j < b.j; } }; // Questo non è permesso, anche se qualche compilatore potrebbe non dare problemi //std::map fooMap; std::map fooMap; fooMap[Foo(1)] = 1; fooMap.find(Foo(1)); -- vero /////////////////////////////////////// // Espressioni Lambda (C++11 e superiori) /////////////////////////////////////// // Le espressioni lambda (più semplicemente "lambda") sono utilizzate // per definire una funzione anonima nel punto in cui viene invocata, o // dove viene passata come argomento ad una funzione // Ad esempio, consideriamo l'ordinamento di un vettore costituito da una // coppia di interi, utilizzando il secondo elemento per confrontare vector > tester; tester.push_back(make_pair(3, 6)); tester.push_back(make_pair(1, 9)); tester.push_back(make_pair(5, 0)); // Passiamo una lambda come terzo argomento alla funzione di ordinamento // `sort` è contenuta nell'header sort(tester.begin(), tester.end(), [](const pair& lhs, const pair& rhs) { return lhs.second < rhs.second; }); // Nota bene la sintassi utilizzata nelle lambda: // [] serve per "catturare" le variabili. // La "Lista di Cattura" definisce tutte le variabili esterne che devono essere disponibili // all'interno della funzione, e in che modo. // La lista può contenere: // 1. un valore: [x] // 2. un riferimento: [&x] // 3. qualunque variabile nello scope corrente, per riferimento [&] // 4. qualunque variabile nello scope corrente, per valore [=] // Esempio: vector id_cani; // numero_cani = 3; for(int i = 0; i < 3; i++) { id_cani.push_back(i); } int pesi[3] = {30, 50, 10}; // Mettiamo che vuoi ordinare id_cani in base al peso dei cani // Alla fine, id_cani sarà: [2, 0, 1] // Le lambda vengono in aiuto sort(id_cani.begin(), id_cani.end(), [&pesi](const int &lhs, const int &rhs) { return pesi[lhs] < pesi[rhs]; }); // Nota come abbiamo catturato "pesi" per riferimento nell'esempio. // Altre informazioni sulle lambda in C++: http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11 /////////////////////////////// // Ciclo For semplificato(C++11 e superiori) /////////////////////////////// // Puoi usare un ciclo for per iterare su un tipo di dato contenitore int arr[] = {1, 10, 3}; for(int elem: arr) { cout << elem << endl; } // Puoi usare "auto" senza preoccuparti del tipo degli elementi nel contenitore // Ad esempio: for(auto elem: arr) { // Fai qualcosa con `elem` } /////////////////////// // Roba divertente ////////////////////// // Aspetti del C++ che potrebbero sbalordire i nuovi arrivati (e anche qualche veterano). // Questa sezione è, sfortunatamente, selvaggiamente incompleta; il C++ è uno dei linguaggi // più facili con cui puoi spararti da solo nel piede. // Puoi sovrascrivere metodi privati! class Foo { virtual void bar(); }; class FooSub : public Foo { virtual void bar(); // Sovrascrive Foo::bar! }; // 0 == false == NULL (la maggior parte delle volte)! bool* pt = new bool; *pt = 0; // Setta il valore puntato da 'pt' come falso. pt = 0; // Setta 'pt' al puntatore null. Entrambe le righe vengono compilate senza warnings. // nullptr dovrebbe risolvere alcune di quei problemi: int* pt2 = new int; *pt2 = nullptr; // Non compila pt2 = nullptr; // Setta pt2 a null. // C'è un'eccezione per i bool. // Questo permette di testare un puntatore a null con if(!ptr), ma // come conseguenza non puoi assegnare nullptr a un bool direttamente! *pt = nullptr; // Questo compila, anche se '*pt' è un bool! // '=' != '=' != '='! // Chiama Foo::Foo(const Foo&) o qualche variante (vedi "move semantics") // del costruttore di copia. Foo f2; Foo f1 = f2; // Chiama Foo::Foo(const Foo&) o qualche variante, ma solo copie di 'Foo' che fanno parte di // 'fooSub'. Ogni altro membro di 'fooSub' viene scartato. Questo comportamento // orribile viene chiamato "object slicing." FooSub fooSub; Foo f1 = fooSub; // Chiama Foo::operator=(Foo&) o una sua variante. Foo f1; f1 = f2; /////////////////////////////////////// // Tuple (C++11 e superiori) /////////////////////////////////////// #include // Concettualmente le tuple sono simili alle strutture del C, ma invece di avere // i membri rappresentati con dei nomi, l'accesso agli elementi avviene tramite // il loro ordine all'interno della tupla. // Cominciamo costruendo una tupla. // Inserire i valori in una tupla auto prima = make_tuple(10, 'A'); const int maxN = 1e9; const int maxL = 15; auto seconda = make_tuple(maxN, maxL); // Vediamo gli elementi contenuti nella tupla "prima" cout << get<0>(prima) << " " << get<1>(prima) << "\n"; // stampa : 10 A // Vediamo gli elementi contenuti nella tupla "seconda" cout << get<0>(seconda) << " " << get<1>(seconda) << "\n"; // stampa: 1000000000 15 // Estrarre i valori dalla tupla, salvandoli nelle variabili int primo_intero; char primo_char; tie(primo_intero, primo_char) = prima; cout << primo_intero << " " << primo_char << "\n"; // stampa : 10 A // E' possibile creare tuple anche in questo modo tuple terza(11, 'A', 3.14141); // tuple_size ritorna il numero di elementi in una tupla (come constexpr) cout << tuple_size::value << "\n"; // stampa: 3 // tuple_cat concatena gli elementi di tutte le tuple, nell'esatto ordine // in cui sono posizionati all'interno delle tuple stesse auto tupla_concatenata = tuple_cat(prima, seconda, terza); // tupla_concatenata diventa = (10, 'A', 1e9, 15, 11, 'A' ,3.14141) cout << get<0>(tupla_concatenata) << "\n"; // stampa: 10 cout << get<3>(tupla_concatenata) << "\n"; // stampa: 15 cout << get<5>(tupla_concatenata) << "\n"; // stampa: 'A' ///////////////////// // Contenitori ///////////////////// // I Contenitori della "Standard Template Library", ovvero la libreria standard // dei template contenuti nel C++, sono template predefiniti. // I Contenitori si occupano di come allocare lo spazio per gli elementi contenuti, // e forniscono funzioni per accedervi e manipolarli // Vediamo alcuni tipi di contenitori: // Vector (array dinamici/vettori) // Permettono di definire un vettore, o una lista di oggetti, a runtime #include vector nome_vettore; // usato per inizializzare un vettore cin >> val; nome_vettore.push_back(val); // inserisce il valore di "val" nel vettore // Per iterare in un vettore, abbiamo due possibilità: // Ciclo normale for(int i=0; i::iterator it; // inizializza l'iteratore per il vettore for(it=nome_vettore.begin(); it!=nome_vettore.end();++it) // Nota che adesso non cicla più sugli indici, ma direttamente sugli elementi! // Per accedere agli elementi del vettore // Operatore [] var = nome_vettore[indice]; // Assegna a "var" il valore del vettore all'indice dato // Set (insiemi) // Gli insiemi sono contenitori che memorizzano elementi secondo uno specifico ordine. // Gli insiemi vengono per lo più utilizzati per memorizzare valori unici, secondo // un ordine, senza scrivere ulteriore codice. #include set insieme; // Inizializza un insieme di interi insieme.insert(30); // Inserisce il valore 30 nell'insieme insieme.insert(10); // Inserisce il valore 10 nell'insieme insieme.insert(20); // Inserisce il valore 20 nell'insieme insieme.insert(30); // Inserisce il valore 30 nell'insieme // Gli elementi dell'insieme sono: // 10 20 30 // Per cancellare un elemento insieme.erase(20); // Cancella l'elemento con valore 20 // L'insieme contiene adesso: 10 30 // Per iterare su un insieme, usiamo gli iteratori set::iterator it; for(it=insieme.begin();it map mia_mappa; // Inizializza una mappa che usa i char come chiave, e gli interi come valore mia_mappa.insert(pair('A',1)); // Inserisce il valore 1 per la chiave A mia_mappa.insert(pair('Z',26)); // Inserisce il valore 26 per la chiave Z // Per iterare map::iterator it; for (it=mia_mappa.begin(); it!=mia_mappa.end(); ++it) std::cout << it->first << "->" << it->second << '\n'; // Stampa: // A->1 // Z->26 // Per trovare il valore corrispondente ad una data chiave it = mia_mappa.find('Z'); cout << it->second; // Stampa: 26 /////////////////////////////////// // Operatori logici e bitwise(bit-a-bit) ////////////////////////////////// // La maggior parte di questi operatori in C++ sono gli stessi degli altri linguaggi // Operatori logici // Il C++ usa la "Short-circuit evaluation" per le espressioni booleane. Cosa significa? // In pratica, in una condizione con due argomenti, il secondo viene considerato solo se // il primo non basta a determinate il valore finale dell'espresione. true && false // Effettua il **and logico** e ritorna falso true || false // Effettua il **or logico** e ritorna vero ! true // Effettua il **not logico** e ritorna falso // Invece di usare i simboli, si possono usare le keyword equivalenti true and false // Effettua il **and logico** e ritorna falso true or false // Effettua il **or logico** e ritorna vero not true // Effettua il **not logico** e ritorna falso // Operatori bitwise(bit-a-bit) // **<<** Operatore di Shift a Sinistra // << sposta i bit a sinistra 4 << 1 // Sposta a sinistra di 1 i bit di 4, ottenendo 8 // x << n in pratica realizza x * 2^n // **>>** Operatore di Shift a Destra // >> sposta i bit a destra 4 >> 1 // Sposta a destra di 1 i bit di 4, ottenendo 2 // x >> n in pratica realizza x / 2^n ~4 // Effettua il NOT bit-a-bit 4 | 3 // Effettua il OR bit-a-bit 4 & 3 // Effettua il AND bit-a-bit 4 ^ 3 // Effettua il XOR bit-a-bit // Le keyword equivalenti sono compl 4 // Effettua il NOT bit-a-bit 4 bitor 3 // Effettua il OR bit-a-bit 4 bitand 3 // Effettua il AND bit-a-bit 4 xor 3 // Effettua il XOR bit-a-bit ``` Letture consigliate: * Un riferimento aggiornato del linguaggio può essere trovato qui [CPP Reference](http://cppreference.com/w/cpp). * Risorse addizionali possono essere trovate qui [CPlusPlus](http://cplusplus.com). * Un tutorial che copre le basi del linguaggio e l'impostazione dell'ambiente di codifica è disponibile su [TheChernoProject - C ++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb). ================================================ FILE: it/c.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"] - ["Jakub Trzebiatowski", "http://cbs.stgn.pl"] - ["Marco Scannadinari", "https://marcoms.github.io"] - ["Zachary Ferguson", "https://github.io/zfergus2"] - ["himanshu", "https://github.com/himanshu81494"] - ["Joshua Li", "https://github.com/JoshuaRLi"] - ["Dragos B. Chirila", "https://github.com/dchirila"] - ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"] translators: - ["lele25811", "https://github.com/lele25811"] filename: learnc-it.c --- Ah, C. Ancora **il** linguaggio per il moderno calcolo ad alte prestazioni. C è il linguaggio di più basso livello che la maggior parte dei programmatori utilizzerà mai, ma compensa ampiamente con la sua velocità pura. Basta essere consapevoli della gestione manuale della memoria e C ti porterà ovunque tu abbia bisogno ```c // Una singola riga di commenti comincia con // - utilizzabile in C99 e superiori /* I commenti multi-riga appaiono come questo. Funzionano anche in C89. */ /* I commenti multi-riga non si nidificano /* fai attenzione */ // commento termina con questa linea */ // ...non con questa! // Costanti: #define // Le costanti sono scritte in MAIUSCOLO per convenzione #define DAYS_IN_YEAR 365 // Le enumerazioni sono anche sono modi per dichiarare costanti. // Tutte le dichiarazioni devono finire con un punto e virgola enum days {SUN, MON, TUE, WED, THU, FRI, SAT}; // SUN ottiene 0, MON ottiene 1, TUE ottiene 2, etc. // Il valore delle enumerazioni può essere anche specificato enum days {SUN = 1, MON, TUE, WED = 99, THU, FRI, SAT}; // MON ottiene 2 automaticamente, TUE ottiene 3, etc. // WED ottiene 99, THU ottiene 100, FRI ottiene 101, etc. // Importa le intestazioni con #include #include #include #include // I nomi dei file tra dicono al compilatore dove guardare nel tuo sistema. // di librerie per l'intestazioni. // Per le tue intestazioni, usa le doppi virgolette invece di parentesi angolari // e fornisci il percorso #include "my_header.h" // file locale #include "../my_lib/my_lib_header.h" // percorso relativo // Dichiara le segnature della funzione in anticipo in un file.h o nella parte superiore // del tuo file .c void function_1(); int function_2(void); // Almeno, è necessario dichiarare un 'prototipo di funzione' prima del suo utilizzo in qualsiasi funzione. // Normalmente, i prototipi sono nella parte superiore del file prima di qualsiasi definizione di funzione. int add_two_ints(int x1, int x2); // prototipo di funzione // Sebbene 'int add_two_ints(int, int);' è valido (non è necessario nominare gli argomenti), // si consiglia di nominare anche gli argomenti nel prototipo per un'ispezione più semplice. // Prototipi di funzione non sono necessari se la definizione della funzione avviene prima // qualsiasi altra funzione che chiama quella funzione. Comunque, è pratica standard // aggiungere sempre il prototipo di funzione a un file di intestazione (*.h) e quindi #define // il file sopra. Ciò impedisce ogni errore dove una funzione potrebbe essere chiamata // prima che il compilatore sappia della sua esistenza, dando anche allo sviluppatore // una intestazione pulita da condividere con il resto del progetto. // Il tuo punto di accesso al programma è una funzione chiamata 'main'. Il tipo di ritorno // può essere qualsiasi, tuttavia molti sistemi operativi si aspettano un tipo di ritorno 'int' // per l'elaborazione del codice di errore. int main(void) { // il tuo programma } // Gli argomenti della riga di comando utilizzati per eseguire il programma vengono anche passati al main // argc è il numero di argomenti: il nome del programma conta come 1 // argv è un array di array di caratteri - contiene gli argomenti stessi // argv[0] = nome del programma // argv[1] = primo argomento, ecc int main (int argc, char** argv) { // stampa l'output usanto 'printf', per la formattazione di stampa // %d è un intero, \n è un a capo printf("%d\n", 0); // => Stampa 0 // prende un input utilizzando 'scanf' // '&' viene utilizzato per definire la posizione // dove vogliamo archiviare il valore di input int input; scanf("%d", &input); /////////////////////////////////////// // Tipi /////////////////////////////////////// // I compilatori che non sono uniformi a C99 richiedono che le variabili DEVONO essere // dichiarate nella parte superiore del blocco corrente. // I compilatori che sono uniformi a C99 permettono la dichiarazione delle variabili vicino // al punto in cui viene utilizzato il valore. // Per motivi di tutorial, le variaibli sono dichiarate dinamicamente sotto lo standard coforme a C99. // gli int (interi) sono generalmente di 4 byte (usa l'operatore `sizeof` per controllare) int x_int = 0; // gli short sono generalmente di 2 byte (usa l'operatore `sizeof` per controllare) short x_short = 0; // i char (letterali) sono definiti come le unità indirizzabili più piccole per un processore. // Questo generalmente è 1 byte, ma per alcuni sistemi può essere più, // (es. per TMS320 da TI è 2 byte). char x_char = 0; char y_char = 'y'; // i char sono citati con '' // i long sono generalmente di 4 o 8 byte; i lunghi long sono garantiti almeno per essere 8 byte long x_long = 0; long long x_long_long = 0; // i float sono generalmente 32 bit, numeri a virgola mobile float x_float = 0.0f; // il suffisso 'f' indica 'floating' per floating point, quindi numeri a virgola mobile // i double sono generalmente 64 bit, numeri a virgola mobile double x_double = 0.0; // i numeri reali senza nessun suffiso sono double // i tipi interi possono essere 'unsigned', sono firmati (maggiore o uguale a zero) unsigned short ux_short; unsigned int ux_int; unsigned long long ux_long_long; // i char all'interno delle virgolette singole sono numeri interi nel insieme di caratteri della macchina. '0'; // => 48 nel insieme di caratteri ASCII. 'A'; // => 65 nel insieme di caratteri ASCII. // sizeof(T) ti dà la dimensione di una variabile con tipo T in byte // sizeof(OBJ) produce la dimensione dell'espressione (variabile, letterale, ecc) printf("%zu\n", sizeof(int)); // => 4 (sulla maggior parte delle macchine con parole a 4 byte) // Se l'argomento del operatore `sizeof` è un espressione, allora il suo argomento // non viene valutato (trannte VLA, vedi sotto) // Il valore che produce in questo caso è una costante a tempo di compilazione. int a = 1; // size_t è un tipo intero non firmato di almeno 2 byte usati per rappresentare // la dimensione di un oggetto. size_t size = sizeof(a++); // a++ non viene valutato printf("sizeof(a++) = %zu where a = %d\n", size, a); // la stampa "sizeof(a++) = 4 dove a=1" (su un'archiettura a 32 bit) // Gli array devono essere inizializzati con una dimensione fissa char my_char_array[20]; // Questo array occupa 1 * 20 = 20 bytes int my_int_array[20]; // Questo array 4 * 20 = 80 bytes // (assumendo parole a 4 byte) // Puoi inizializzare un array di venti int dove sono tutti 0 così: int my_array[20] = {0}; // dove la parte '{0}' è chiamata 'Initializer array' (inizializzatore di array) // Tutti gli elementi (se presenti) oltre quelli nell'inizializzatore sono inizializzati a 0: int my_array[5] = {1, 2}; // Quindi my_array ora ha cinque elementi, tutti tranne i primi due sono 0: // [1, 2, 0, 0, 0] // NOTE: se non dichiari esplicitamente la dimensione del array // puoi inizializzarlo comunque sulla stessa riga int my_array[] = {0}; // NOTE: quando non si dichiara la lunghezza, la lunghezza è il numero // degli elementi nell'inizializzatore. Con '{0}' my_array è ora di dimensioni: [0]. // Per valutare le dimensioni dell'array in fase di esecuzione, // dividere le dimensioni del byte per le dimensioni del byte del tipo di elemento: size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]); // ATTENZIONE: È necessario valutare la dimensione prima di iniziare a passare l'array // alle funzioni (vedi discussione successiva) perchè gli array vengono 'declassati' // a puntatori grezzi quando vengono passati alle funzioni // (quindi l'affermazione sopra produrra il risultato errato all'interno della funzione) // Indicizzare un array è come negli altri linguaggi // o meglio, gli altri linguaggi sono come il C. my_array[0]; // => 0 // Gli array sono immutabili, È solo memorial! my_array[1] = 2; printf("%d\n", my_array[1]); // => 2 // Nel C99 (e come caratteristica opzionale in C11), gli array a lunghezza variabile (VLA) // possono essere dichiarati. La dimensione di tale array non deve essere specificata a tempo di compilazione. printf("Enter the array size: "); // chiede al utente la lunghezza del array int array_size; fscanf(stdin, "%d", &array_size); int var_length_array[array_size]; // dichiarazione di VLA printf("sizeof array = %zu\n", sizeof var_length_array); // Example: // > Enter the array size: 10 -> (Inserisci la lunghezza del array: 10) // > sizeof array = 40 -> (sizeof array = 40) // Le Stringhe sono solo array di caratteri terminati da un byte null (0x00), // rappresentato nelle stringhe come il carattere speciale '\0' // (non dobbiamo includere il byte null nei letterali delle stringhe, // il compilatore lo inserisce alla fine dell'array per noi). char a_string[20] = "This is a string"; printf("%s\n", a_string); // %s formattazione di una stringa printf("%d\n", a_string[16]); // => 0 // i.e., byte #17 è 0 (come sono 18, 19, e 20) // Se noi abbiamo caratteri tra le vergolette doppie (""), quei caratteri sono un letterale. // È di tipo `int` e *non* `char` (per motivi storici) int cha = 'a'; // ok char chb = 'a'; // ok lo stesso (implicitamente la conversione da int a char) // Array di più dimensioni: int multi_array[2][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 0} }; // accesso agli elementi: int array_int = multi_array[0][2]; // => 3 /////////////////////////////////////// // Operatori /////////////////////////////////////// // versione corta per molteplici dichiarazioni: int i1 = 1, i2 = 2; float f1 = 1.0, f2 = 2.0; int b, c; b = c = 0; // Aritmetica semplice i1 + i2; // => 3 i2 - i1; // => 1 i2 * i1; // => 2 i1 / i2; // => 0 (0.5, ma troncato è 0) // Hai bisogno di un cambio di tipo (cast) da `int` a `float` per ottenere un risultato in virgola mobile (float)i1 / i2; // => 0.5f i1 / (double)i2; // => 0.5 // Lo stesso per i double f1 / f2; // => 0.5, più o meno epsilon // I numeri a virgola mobile sono definiti da IEEE 754, quindi non possono archiviare perfettamente // valori esatti. Ad esempio, quanto segue non produce risultati previsti // perchè 0.1 potrebbe effettivamente essere 0,09999999999 dentro il computer, // e 0.3 potrebbe essere memorizzato come 0.300000000001. (0.1 + 0.1 + 0.1) != 0.3; // => 1 (vero) // e non è associato per ragioni di sopra menzionate. 1 + (1e123 - 1e123) != (1 + 1e123) - 1e123; // => 1 (vero) // questa notazione è la notazione scientifica per i numeri: 1e123 = 1*10^123 // È importante considerare che la maggior parte dei sistemi utilizza IEEE 754 per // rappresentare i numeri in virgola mobile, Anche in python viene utilizzato per il calcolo scientifico // alla fine chiama C che utilizza IEEE754. È mensionato in questo modo non per indicare che l'implementazione // è scarsa, ma invece come avvertimento per quando si effettuano confronti in virgola mobile // un po di errore (Epsilon) deve essere considerato. // Il modulo è presente, ma fai attenzione se gli argomenti sono negativi 11 % 3; // => 2 come 11 = 2 + 3*x (x=3) (-11) % 3; // => -2, come ci si aspetterebbe 11 % (-3); // => 2 e non -2, ed è abbastanza intuitivo // Gli operatori di confronto sono probabilmente famigliari, // ma non esiste nessun tipo di booleano in C. Usiamo invece 'int'. // (C99 ha introdotto il tipo _bool fornito in stdbool.h) // 0 è falso, qualsiasi altra cosa è vera. // (il confronto tra operatori produce sempre 0 o 1 -> falso o vero) 3 == 2; // => 0 (falso) 3 != 2; // => 1 (vero) 3 > 2; // => 1 3 < 2; // => 0 2 <= 2; // => 1 2 >= 2; // => 1 // C non è python - i confronti non sono a catena. // ATTENZIONE: la riga seguente si compilerà, ma significa '(0 a) 2'. // Questa espressione è sempre vera, perchè (0 a) potrebbe essere 1 o 0. // In questo caso è 1, perchè (0 1). int between_0_and_2 = 0 < a < 2; // Invece utilizza: int between_0_and_2 = 0 < a && a < 2; // La logica lavora sugli 'int' !3; // => 0 (Logica not) !0; // => 1 1 && 1; // => 1 (Logica and) 0 && 1; // => 0 0 || 1; // => 1 (Logica or) 0 || 0; // => 0 // Espressione di condizione ternaria ( ? : ) int e = 5; int f = 10; int z; z = (e > f) ? e : f; // => 10 "if e > f return e, else return f." // Incremento e decremento degli operatori: int j = 0; int s = j++; // Return j THEN incremento j. (s = 0, j = 1) s = ++j; // Incremento j THEN return j. (s = 2, j = 2) // stesso con j-- e --j // Operatori bitwise! ~0x0F; // => 0xFFFFFFF0 (negazione bitwise, "complemento di 1", nel esempio il risultato per int a 32 bit) 0x0F & 0xF0; // => 0x00 (bitwise AND) 0x0F | 0xF0; // => 0xFF (bitwise OR) 0x04 ^ 0x0F; // => 0x0B (bitwise XOR) 0x01 << 1; // => 0x02 (bitwise spostamento a sinistra (di 1)) 0x02 >> 1; // => 0x01 (bitwise spostamento a destra (di 1)) // Fai attenzione quando si spostano numeri interi: i seguenti sono indefiniti: // - spostamento nel bit di segno di un numero intero (int a = 1 << 31) // - spostamento a sinistra di un numero negativo (int a = -1 << 2) // - spostamento di un offset che è >= la larghezza del tipo di LHS: // int a = 1 << 32; // oltre la grandezza di a se l'intero è largo 32 bit /////////////////////////////////////// // Strutture di controllo /////////////////////////////////////// if (0) { printf("I am never run\n"); } else if (0) { printf("I am also never run\n"); } else { printf("I print\n"); } // Esistono i while loop innestati int ii = 0; while (ii < 10) { // qualsiasi valore inferiore a dieci è vero. printf("%d, ", ii++); // il ii++ incrementa ii DOPO aver utilizzato il suo valore corrente. } // => stampa "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); int kk = 0; do { printf("%d, ", kk); } while (++kk < 10); // il ++kk incrementa kk PRIMA di utilizzare il suo valore corrente. // => stampa "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // Esistono anche i ciclo for int jj; for (jj=0; jj < 10; jj++) { printf("%d, ", jj); } // => stampa "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // *****NOTES*****: // Cicli e funzioni devono avere un corpo. Se nessun corpo è necessario: int i; for (i = 0; i <= 5; i++) { ; // usa le ';' per fungere da corpo (null statement) } // oppure for (i = 0; i <= 5; i++); // ramificazione con più scelte: switch () switch (a) { case 0: // Le etichette devono essere *espessioni costanti* (come gli enums) printf("Hey, 'a' equals 0!\n"); break; // se non si rompe il flusso (break) continua sulle etichette successive case 1: printf("Huh, 'a' equals 1!\n"); break; // Stai attendo: senza 'break' l'esecuzione continua fino a che non viene // raggiunta la prossima pausa case 3: case 4: printf("Look at that.. 'a' is either 3, or 4\n"); break; default: // se il valore di a non corrisponde a nessuna delle etichette fputs("Error!\n", stderr); exit(-1); break; } /* Usiamo il "goto" in C */ typedef enum { false, true } bool; // per il C che non ha booleani come tipi di dato prima del C99 :( bool disaster = false; int i, j; for(i=0; i<100; ++i) for(j=0; j<100; ++j) { if((i + j) >= 150) disaster = true; if(disaster) goto error; // esci da entrambi i cicli for } error: // questa è un etichetta a cui puoi "saltare" con `goto error` printf("Error occurred at i = %d & j = %d.\n", i, j); /* https://ideone.com/GuPhd6 Questo stamperà l'errore 'Error occured at i=51 & j=99.' */ /* È generalmente considerato una cattiva pratica farlo, tranne se davvero sai cosa stai facendo, vedi: https://en.wikipedia.org/wiki/Spaghetti_code#Meaning */ /////////////////////////////////////// // Typecasting /////////////////////////////////////// // Ogni valore in C ha un tipo, ma puoi lanciare un valore in un altro tipo // se vuoi (con alcuni vincoli) int x_hex = 0x01; // Puoi assegnare variabili con caratteri esadecimali // il binario non è nello standard, ma consentito da alcuni // compilatori (x_bin = 0b0010010110) // I casting tra i tipi tenterà di preservare i loro valori numerici printf("%d\n", x_hex); // => Stampa 1 printf("%d\n", (short) x_hex); // => Stampa 1 printf("%d\n", (char) x_hex); // => Stampa1 1 // Se si assegna un valore superiore a un tipo di massimo, il rollover senza preavviso. printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 se char è lunga 8 bits) // Per determinare il valore massimo di un `char`, un char unsigned è un char senza sengno, // rispettivamente, usa i macro char_max, schar_max e uchar_max da limiti.h // I tipi integrati possono essere cambiati (cast) in virgola mobile e vice versa printf("%f\n", (double) 100); // %f formatta sempre un doppio... printf("%f\n", (float) 100); // ...anche con un vigola mobile. printf("%d\n", (char)100.0); /////////////////////////////////////// // Puntatori (Pointers) /////////////////////////////////////// // Un puntatore è una variabile chiamata per archiviare un indirizzo di memoria. // La sua dichiarazione dirà il tipo di dato a cui è indicato. // Puoi recuperare l'indirizzo di memoria dalle tue variabili, poi potrai utilizzarle. int x = 0; printf("%p\n", (void *)&x); // Usa e recupera l'indirizzo di una variabile // (%p formattazione di un puntatore, oggetto di tipo void *) // => Stampa alcuni indirizzi in memoria; // I puntatori iniziano con * nella loro dichiarazione int *px, not_a_pointer; // px è un puntatore ad un int px = &x; // memorizza l'indirizzo di x in px printf("%p\n", (void *)px); // => stampa un indirizzo di memoria printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); // => Stampa '8, 4' su un tipico sistema a 64 bit // Per recuperare il valore all'indirizzo che un puntatore sta puntando // metti * davanti alla referenza // Note: si, potrebbe confondere il fatto che '*' si usa per entrambe, // dichiarazione a puntatore e referenza ad esso. printf("%d\n", *px); // => Stampa 0, la variabile di x // Puoi anche modificare il valore a cui punta il puntatore. // dovremmo avvolgere la referenza tra parentesi perchè // ++ ha una precedenza maggiore di *. (*px)++; // Incrementa il valore che px punta di 1 printf("%d\n", *px); // => Stampa 1 printf("%d\n", x); // => Stampa 1 // Gli array sono un buon modo di allocare blocchi di memoria contigui int x_array[20]; // dichiarazione di un array di dimensione 20 (non può essere cambiata la dimensione) int xx; for (xx = 0; xx < 20; xx++) { x_array[xx] = 20 - xx; } // Inizializza x_array a 20, 19, 18,... 2, 1 // dichiara un puntatore di tipo int e inizializzalo per indicare x_array int* x_ptr = x_array; // x_ptr ora indica il primo elemento nell'array (il numero intero 20). // Funziona perchè gli array spesso decadono nei puntatori del loro primo elemento. // Ad esempio, quando un array viene passato a una funzione o viene assegnato a un puntatore, // decade in (implicitamente convertito in) un puntatore. // Eccezioni: quando l'array è l'argomento dell'operatore `&` (indirizzo di): int arr[10]; int (*ptr_to_arr)[10] = &arr; // &arr non è un tipo`int *`! // È un tipo 'puntatore all'array' (del decimo 'int'). // o quando l'array è una stringa di caratteri utilizzata per l'inizializzazione di un array di char: char otherarr[] = "foobarbazquirk"; // oppure quando è un argomento di un operatore `sizeof` o `alignof`: int arraythethird[10]; int *ptr = arraythethird; // equivalente con int *ptr = &arr[0]; printf("%zu, %zu\n", sizeof(arraythethird), sizeof(ptr)); // probabilmente stamperà "40, 4" or "40, 8" // I puntatori sono incrementati e decrementati in base al loro tipo // (questo si chiama puntatore aritmetico) printf("%d\n", *(x_ptr + 1)); // => Stampa 19 printf("%d\n", x_array[1]); // => Stampa 19 // E ancora possibile allocare dinamicamente blocchi di memoria contigui con la // funzione di libreria standard malloc, che prende un argomento di tipo `size_t` // che rappresenta il numero di byte da allocare (di solito dalla heap, sebbene questo // potrebbe non essere vero su alcuni sistemi embedded - il C standard non dice nulla al riguardo). int *my_ptr = malloc(sizeof(*my_ptr) * 20); for (xx = 0; xx < 20; xx++) { *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx } // Inizializza la memoria a 20, 19, 18, 17... 2, 1 (come int) // Fai attenzione a passare i valori forniti dall'utente alla malloc! // Se vuoi essere al sicuro, puoi usare calloc invece (che, a differenza di malloc, // inizializza tutti zero in memorial) int* my_other_ptr = calloc(20, sizeof(int)); // Nota che non esiste un modo standard per ottenere la lunghezza di un array allocato dinamicamente in C. // Per questo motivo, se i tuoi array sono passati attraverso il programma per molto tempo, // avrai bisogno di un altra variabile per tenere traccia del numero di elementi (dimensione) del array. // Vedi la sezione delle funzioni per maggiori informazioni. size_t size = 10; int *my_arr = calloc(size, sizeof(int)); // Aggiungi un elemento all'array size++; my_arr = realloc(my_arr, sizeof(int) * size); if (my_arr == NULL) { // Ricordati di verificare il fallimento di realloc! return } my_arr[10] = 5; // la Memoria di dereferenziazione che non hai assegnato darà 'risultati imprevedibili' // - Si dice che il programma invochi 'comportamento indefinito' printf("%d\n", *(my_ptr + 21)); // => Stampa chi-sa-cosa? potrebbe anche andare in crash. // Quando hai finito con un blocco di memoria malloc, devi liberarlo, // altrimenti nessun altro può usarlo fino a quando il programma non termina // (questo è chiamato perdita di memoria (= memory leak)) free(my_ptr); // Le stringhe sono array di char, ma solitamente sono rappresentate come // puntatori-al-char (che è un puntatore al primo elemento dell'array). // È una buona pratica usare `const chat *` quando si fa riferimento a una stringa di caratteri, // poichè i caratteri di una stringa non devono essere modificati // (ovvero 'foo' [0] = 'a' è illegale) const char *my_str = "This is my very own string literal"; printf("%c\n", *my_str); // => 'T' // Questo non è il caso se la stringa è un array // (potenzialmente inizializzato con una stringa di caratteri) // che risiede nella memoria scrivibile, come in: char foo[] = "foo"; foo[0] = 'a'; // questo è legale, foo ora contiene 'aoo'. function_1(); } // fine della funzione main /////////////////////////////////////// // Funzioni (Functions) /////////////////////////////////////// // Sintassi della dichiarazione di una funzione: // () int add_two_ints(int x1, int x2) { return x1 + x2; // Utilizzare return per restituire un valore } /* Le funzioni sono chiamate per valore. Quando viene chiamata una funzione, gli argomenti passati alla funzione sono copie di argomenti originali (tranne gli array). Qualunque cosa tu fai l'argomento nella funzione non cambia il valore originale rispetto a quando è stata chiamata. Usa i puntatori se te hai bisogno di modificare l'argomento originale (gli array sono sempre passati come puntatori). Esempio: inversione della stringa. */ // Una funzione void in ritorna nulla void str_reverse(char *str_in) { char tmp; size_t ii = 0; size_t len = strlen(str_in); // `strlen()` è parte della libreria standard // NOTE: la lunghezza ritornata da `strlen` NON // include la terminazione con il NULL byte ('\0') // nella versione C99 e superiori, puoi direttamente dichiamare le variabili nel controllo del ciclo // nelle parentesi del loop e.g. `for (size_t ii = 0; ...` for (ii = 0; ii < len / 2; ii++) { tmp = str_in[ii]; str_in[ii] = str_in[len - ii - 1]; // ii-iesimo chat dalla fine str_in[len - ii - 1] = tmp; } } //NOTE: string.h il file di intestazione ha bisogno di includere /* char c[] = "This is a test."; str_reverse(c); printf("%s\n", c); // => ".tset a si sihT" */ /* come possiamo ritornare solo una variabile per cambiare valori in più di una variabile possiamo utilizzare le referenze */ void swapTwoNumbers(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } /* int first = 10; int second = 20; printf("first: %d\nsecond: %d\n", first, second); swapTwoNumbers(&first, &second); printf("first: %d\nsecond: %d\n", first, second); // i valori verranno scambiati */ // Restituire più valori. // Il linguaggio C non permette di restituire più valori utilizzando l'istruzione return. // Se si desidera restituire più valori, la funzione deve ricevere in ingresso le variabili // in cui salvare i risultati. Queste variabili devono essere passate come puntatori, // in modo che la funzione possa modificarne direttamente il contenuto. int return_multiple( int *array_of_3, int *ret1, int *ret2, int *ret3) { if(array_of_3 == NULL) return 0; // ritorna il codice d'errore (falso) // mettiamo le varibili nel puntatore in modo da modificare il suo valore *ret1 = array_of_3[0]; *ret2 = array_of_3[1]; *ret3 = array_of_3[2]; return 1; //return codice d'errore (vero) } /* Per qunato riguarda gli array, saranno sempre passati alla funzioni come indicatori. Anche se allochi staticamente un array come `arr[10]` Viene ancora passato come puntatore al primo elemento in qualsiasi chiamata di funzioni. Ancora una volta non esiste un modo standard per ottenere le dimensioni di un array allocato dinamicamente in C. */ // La grandezza deve essere passata! // Altrimenti, questa funzione non ha modo di sapere quanto sia grande l'array. void printIntArray(int *arr, size_t size) { int i; for (i = 0; i < size; i++) { printf("arr[%d] is: %d\n", i, arr[i]); } } /* int my_arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int size = 10; printIntArray(my_arr, size); // stamperà "arr[0] is: 1" etc */ // Se si fa riferimento a variaibli esterne, fuori dalla funzione, // è necessario utilizzare la parola chiave extern int i = 0; void testFunc() { extern int i; //i qui ora sta usando la variabile esterna i } // rendi le variabili esterne private per il file di origine con static: static int j = 0; // altri file che utilizzano testFunc2() non possono accedere alla variabile j void testFunc2() { extern int j; } // La parola chiave `static` rende una variabile inaccessibile al codice al di fuori del // unità di compilazione. (Su quasi tutti i sistemi, un'unità di compilazione è un file .c). // `static` si può applicare sia alla variabili globali (all'unità di compilazione), // funzioni e variabili e variabili di funzioni locali. // Quando si usa `static` con variabili di funzioni locali, la variabile è effettivamente globale // e conserva il suo valore tra le chiamate di funzione, ma è accessibile solo all'interno della funzione // in cui è dichiarata. // In più, le variabili statiche sono inizializzate a 0 se non dichiarate con qualche valore di partenza. // **Puoi dichiarare funzioni statiche per renderle private** /////////////////////////////////////// // Tipi definiti dal utente e strutture /////////////////////////////////////// // Typedefs può essere utilizzato per creare alias di tipo typedef int my_type; my_type my_type_var = 0; // Le strutture sono delle raccolte di dati, i membri vengono allocati in memorial in sequenza, // nell'ordine sono scritti: struct rectangle { int width; int height; }; // non è generalmente vero // sizeof(struct rectangle) == sizeof(int) + sizeof(int) // a causa del possibile padding tra i membri // della struttura (necessario per motivi di allineamento) [1] void function_1() { struct rectangle my_rec = { 1, 2 }; // Campo che può essere inizializzato immediatamente // Accesso alla struttura con . my_rec.width = 10; my_rec.height = 20; // Puoi dichiarare puntatori alle strutture struct rectangle *my_rec_ptr = &my_rec; // Usa la dereferenziazione per impostare i membri del puntatore... (*my_rec_ptr).width = 30; // ... o anche meglio: preferisci la -> per motivi di legibilità my_rec_ptr->height = 10; // Stesso di (*my_rec_ptr).height = 10; } // Puoi applicare typedef alla struttura per convenienza typedef struct rectangle rect; int area(rect r) { return r.width * r.height; } // I Typedefs possono anche essere definiti a destra durante la definizione della struttura typedef struct { int width; int height; } rect; // Come prima, fare questo significa che puoi scrivere rect r; // invece di dover digitare struct rectangle r; // Se hai strutture di grandi dimensioni, puoi passarle `per puntatore` // per evitare di copiare l'intera struttura: int areaptr(const rect *r) { return r->width * r->height; } /////////////////////////////////////// // Puntatori a funzioni /////////////////////////////////////// /* In fase di esecuzioni, le funzioni si trovano su indirizzi di memoria noti. I puntatori della funzione sono proprio come qualsiasi altro puntatore (memorizzano solo un indirizzo di memoria), ma possono essere utilizzati per invocare le funzioni direttamente (o le funzioni di callback). Tuttavia, la sintassi della definizione può essere inizialmente confusa Esempio: usa str_reverse da un puntatore: */ void str_reverse_through_pointer(char *str_in) { // Definire una variabile puntatore della funzione, denominata f. void (*f)(char *); // La segnatura dovrebbe corrispondere esattamente alla funzione target. f = &str_reverse; // Assegna l'indirizzo per la funzione effettiva (determinato a tempo d'esecuzione) // f = str_reverse; funzionerebbe anche: le funzioni decadono nei puntatori, simili agli array (*f)(str_in); // Per chiamare la funzione attraverso il puntatore // f(str_in); // Questa è una sintassi alternativa ma ugualmente valida per chiamarla } /* Finchè le segnature delle funzioni corrispondono, è possibile assegnare qualsiasi funzione allo stesso puntatore. I puntatori della funzione sono generalmente scritti per semplicità e leggibilità come segue: */ typedef void (*my_fnp_type)(char *); // quindi utilizzato quando si dichiara la variabile del puntatore effettivo: // ... // my_fnp_type f; ///////////////////////////// // Stampando caratteri con printf() ///////////////////////////// //Caratteri speciali: /* '\a'; // carattere di allarme '\n'; // carattere di nuova riga '\t'; // carattere di tabulazione (allinea il testo a sinistra) '\v'; // tabulazione verticale '\f'; // nuova pagina (form feed) '\r'; // ritorno a capo (carriage return) '\b'; // carattere di backspace (cancella il carattere precedente) '\0'; // carattere NULL. Di solito viene utilizzato alla fine delle stringhe in C. // Esempio: "hello\n\0". \0 viene usato per convenzione per indicare la fine della stringa. '\\'; // barra inversa (backslash) '\?'; // punto interrogativo '\''; // apostrofo (singolo apice) '\"'; // doppio apice '\xhh'; // numero esadecimale. Esempio: '\xb' corrisponde al carattere di tabulazione verticale '\0oo'; // numero ottale. Esempio: '\013' corrisponde al carattere di tabulazione verticale // Formattazione della stampa: "%d"; // intero "%3d"; // intero con una lunghezza minima di 3 cifre (allineato a destra) "%s"; // stringa "%f"; // numero in virgola mobile (float) "%ld"; // numero long "%3.2f"; // numero float con almeno 3 cifre prima della virgola e 2 dopo "%7.4s"; // applicabile anche alle stringhe "%c"; // carattere "%p"; // puntatore. NOTA: è necessario effettuare un cast a (void *) prima di passarlo come argomento a `printf`. "%x"; // numero esadecimale "%o"; // numero ottale "%%"; // stampa il carattere % */ /////////////////////////////////////// // Ordine di valutazione /////////////////////////////////////// // Da sopra a sotto, il sopra ha la precedenza //----------------------------------------------------------// // Operatori | Associatività // //----------------------------------------------------------// // () [] -> . | da sinistra a destra // // ! ~ ++ -- + = *(tipo) sizeof | da destra a sinistra // // * / % | da sinistra a destra // // + - | da sinistra a destra // // << >> | da sinistra a destra // // < <= > >= | da sinistra a destra // // == != | da sinistra a destra // // & | da sinistra a destra // // ^ | da sinistra a destra // // | | da sinistra a destra // // && | da sinistra a destra // // || | da sinistra a destra // // ?: | da destra a sinistra // // = += -= *= /= %= &= ^= |= <<= >>= | da destra a sinistra // // , | da sinistra a destra // //----------------------------------------------------------// /******************************* File d'intestazione ********************************** I file d'intestazione sono una parte importante del C, lo permettono la connesione di file sorgenti in C e possono semplificare il codice e le definizioni separandoli in file diversi. I file d'intestazione sono sintatticamente simili ai file di sorgente C ma risiedono in '.h' Possono essere inclusi nel tuo file sorgente utilizzando il pre-processore con la direttiva #include 'Esempio.h' dato che 'esempio.h' esiste nella stessa cartella come file c. */ /* Una protezione per evitare che l'header venga definito troppe volte. Questo */ /* accade in caso di dipendenze circolari, quando il contenuto dell'header è */ /* già stato definito. */ #ifndef EXAMPLE_H /* Se EXAMPLE_H non è ancora stato definito. */ #define EXAMPLE_H /* Definisce la macro EXAMPLE_H. */ /* Altri header possono essere inclusi negli header e quindi inclusi in modo */ /* transitivo nei file che includono questo header. */ #include /* Come per i file sorgente in C, le macro possono essere definite negli header */ /* e utilizzate nei file che includono questo file header. */ #define EXAMPLE_NAME "Dennis Ritchie" /* Anche le macro funzione possono essere definite. */ #define ADD(a, b) ((a) + (b)) /* Nota le parentesi che racchiudono gli argomenti: sono importanti per evitare */ /* che `a` e `b` vengano espansi in modo inaspettato. Ad esempio, considera */ /* MUL(x, y) (x * y); MUL(1 + 2, 3) verrebbe espanso in (1 + 2 * 3), dando un */ /* risultato errato. */ /* Le struct e i typedef possono essere usati per garantire coerenza tra i file. */ typedef struct Node { int val; struct Node *next; } Node; /* Anche le enumerazioni possono essere definite qui. */ enum traffic_light_state {GREEN, YELLOW, RED}; /* I prototipi di funzione possono essere definiti qui per l'uso in più file, */ /* ma è una cattiva pratica definire la funzione direttamente nell'header. */ /* Le definizioni dovrebbero essere inserite in un file C separato. */ Node createLinkedList(int *vals, int len); /* Oltre agli elementi sopra citati, altre definizioni dovrebbero essere lasciate */ /* a un file sorgente C. Inoltre, non bisognerebbe includere troppi file o */ /* definizioni in un unico header, ma organizzarli in più header separati o in */ /* un file C. */ #endif /* Fine della direttiva preprocessor if. */ ``` ## Ulteriori letture È meglio procurarsi una copia di [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language). È il libro sul C, scritto da Dennis Ritchie, il creatore del linguaggio, e Brian Kernighan. Tuttavia, fai attenzione: è piuttosto datato e contiene alcune imprecisioni (o meglio, idee che oggi non sono più considerate valide) e pratiche che nel tempo sono cambiate. Un'altra buona risorsa è [Learn C The Hard Way](http://learncodethehardway.org/c/) (non è gratuito). Se hai una domanda, consulta le [compl.lang.c Frequently Asked Questions](http://c-faq.com). È molto importante utilizzare una corretta spaziatura, indentazione e mantenere uno stile di codifica coerente in generale. Un codice leggibile è migliore di un codice "intelligente" o veloce. Per uno stile di codifica chiaro e ben strutturato, puoi fare riferimento al [Linux kernel coding style](https://www.kernel.org/doc/Documentation/process/coding-style.rst). [1] [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) ================================================ FILE: it/cmake.md ================================================ --- contributors: - ["Bruno Alano", "https://github.com/brunoalano"] translators: - ["Mario Stabile", "https://github.com/mariostabile1"] --- CMake è un build tool multi-piattaforma e open-source. Questo tool ti permette di testare, compilare e creare pacchetti del tuo codice sorgente. I problemi che CMake provara a risolvere sono quelli dei Makefile, dell'Autoconfigurazione multi-piattaforma (diversi interpreti di Make hanno comandi diversi) e la facilità d'uso nel collegamento di librerie di terze parti. CMake è un sistema estensibile e open-source che gestisce il processo di compilazione in maniera simile a come farebbero i sistemi operativi, indipendentemente dal formato usato. A differenza di altri sistemi multi-piattaforma, CMake è progettato per essere usato insieme all'ambiente di compilazione nativo. Semplici file di configurazione collocati in ogni cartella dei sorgenti (chiamati CMakeLists.txt) sono usati per generare i file di compilazione standard (ad esempio, makefile su Unix e project/workspace in Windows MSVC) che sono utilizzati nel classico modo. ```cmake # In CMake, questo è un commento # Per eseguire il nostro codice, usa questi comandi: # - mkdir build && cd build # - cmake .. # - make # # Con questi passaggi, seguiremo la pratica migliore per compilare in una sotto-cartella. # La seconda riga chiderà a CMake di generare un nuovo Makefile dipendente dal sistema operativo. # Infine, eseguiremo il comando nativo Make. #------------------------------------------------------------------------------ # Le basi #------------------------------------------------------------------------------ # # Il file CMake DEVE essere chiamato "CMakeLists.txt". # Configuriamo la versione minima di CMake per generare il Makefile cmake_minimum_required (VERSION 2.8) # Lancerà un errore FATAL_ERROR se la versione < 2.8 cmake_minimum_required (VERSION 2.8 FATAL_ERROR) # Definiamo il nome del nostro progetto, questo modificherà # le convenzioni di denominazione generate da CMake per alcune cartelle. # Possiamo passare il LANG del codice come secondo parametro project (learncmake C) # Settiamo la cartella del sorgente (è solo una convenzione) set( LEARN_CMAKE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ) set( LEARN_CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} ) # Risulta utile settare l'attuale versione del nostro codice nel sistema di compilazione # usando uno stile `semver` set (LEARN_CMAKE_VERSION_MAJOR 1) set (LEARN_CMAKE_VERSION_MINOR 0) set (LEARN_CMAKE_VERSION_PATCH 0) # Passiamo le variabili (numero di versione) all'header del sorgente configure_file ( "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in" "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # Includiamo le Librerie # In GCC, questo invocherà il comando "-I" include_directories( include ) # Dove sono installate le librerie aggiuntive? Nota: includi i percorsi # delle librerie qui, i controlli successivi risolveranno il resto set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/modules/" ) # Condizioni if ( CONDITION ) # Output! # Informazioni accessorie message(STATUS "My message") # Warning di CMake, continua a elaborare message(WARNING "My message") # Warning di CMake (dev), continua a elaborare message(AUTHOR_WARNING "My message") # Errore di CMake, continua a elaborare, ma salta la generazione message(SEND_ERROR "My message") # Errore di CMake, ferma l'elaborazione e la generazione message(FATAL_ERROR "My message") endif() if( CONDITION ) elseif( CONDITION ) else( CONDITION ) endif( CONDITION ) # Cicli foreach(loop_var arg1 arg2 ...) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... endforeach(loop_var) foreach(loop_var RANGE total) foreach(loop_var RANGE start stop [step]) foreach(loop_var IN [LISTS [list1 [...]]] [ITEMS [item1 [...]]]) while(condition) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... endwhile(condition) # Operazioni logiche if(FALSE AND (FALSE OR TRUE)) message("Don't display!") endif() # Impostiamo una variabile regolare, di cache o di ambiente a un determinato valore. # Se viene fornita l'opzione PARENT_SCOPE, la variabile verrà settata nello scope # sopra lo scope corrente. # `set( ... [PARENT_SCOPE])` # Come fare riferimento a variabili all'interno di argomenti tra virgolette e non? # Un riferimento a una variabile è sostituito sia dal valore della variabile, sia da # una stringa vuota se la variabile non è settata. ${variable_name} # Liste # Prepariamo la lista dei file sorgente set( LEARN_CMAKE_SOURCES src/main.c src/imagem.c src/pather.c ) # Chiamate al compilatore # # ${PROJECT_NAME} fa riferimento a Learn_CMake add_executable( ${PROJECT_NAME} ${LEARN_CMAKE_SOURCES} ) # Link alle librerie target_link_libraries( ${PROJECT_NAME} ${LIBS} m ) # Dove sono installate le librerie aggiuntive? Nota: includi i percorsi # delle librerie qui, i controlli successivi risolveranno il resto set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake/modules/" ) # Condizioni del compilatore (gcc ; g++) if ( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" ) message( STATUS "Setting the flags for ${CMAKE_C_COMPILER_ID} compiler" ) add_definitions( --std=c99 ) endif() # Controllo del sistema operativo if( UNIX ) set( LEARN_CMAKE_DEFINITIONS "${LEARN_CMAKE_DEFINITIONS} -Wall -Wextra -Werror -Wno-deprecated-declarations -Wno-unused-parameter -Wno-comment" ) endif() ``` ### Maggiori risorse + [Tutorial CMake](https://cmake.org/cmake-tutorial/) + [Documentazione CMake](https://cmake.org/documentation/) + [Mastera CMake](http://amzn.com/1930934319/) + [Un'introduzione al CMake moderno](https://cliutils.gitlab.io/modern-cmake/) ================================================ FILE: it/coffeescript.md ================================================ --- contributors: - ["Luca 'Kino' Maroni", "http://github.com/kino90"] - ["Tenor Biel", "http://github.com/L8D"] - ["Xavier Yao", "http://github.com/xavieryao"] --- CoffeeScript è un piccolo linguaggio che compila direttamente nell'equivalente JavaScript, non c'è nessuna interpretazione a runtime. Come possibile successore di JavaScript, CoffeeScript fa il suo meglio per restituire un codice leggibile, ben stampato e performante in ogni ambiente JavaScript. Guarda anche [il sito di CoffeeScript](http://coffeescript.org/), che ha una guida completa a CoffeeScript. ```coffeescript # CoffeeScript è un linguaggio hipster. # Segue le mode di alcuni linguaggi moderni. # Quindi i commenti sono come quelli di Ruby e Python, usano il cancelletto. ### I blocchi di commenti sono definiti con tre cancelletti, che vengono tradotti direttamente in `/*` e `*/` nel codice JavaScript risultante. Prima di continuare devi conoscere la maggior parte delle semantiche JavaScript. ### # Assegnamento: numero = 42 #=> var numero = 42; contrario = true #=> var contrario = true; # Condizioni: numero = -42 if contrario #=> if(contrario) { numero = -42; } # Funzioni: quadrato = (x) -> x * x #=> var quadrato = function(x) { return x * x; } riempi = (contenitore, liquido = "caffè") -> "Sto riempiendo #{contenitore} con #{liquido}..." #=>var riempi; # #riempi = function(contenitore, liquido) { # if (liquido == null) { # liquido = "caffè"; # } # return "Sto riempiendo " + contenitore + " con " + liquido + "..."; #}; # Intervalli: lista = [1..5] #=> var lista = [1, 2, 3, 4, 5]; # Oggetti: matematica = radice: Math.sqrt quadrato: quadrato cubo: (x) -> x * quadrato x #=> var matematica = { # "radice": Math.sqrt, # "quadrato": quadrato, # "cubo": function(x) { return x * quadrato(x); } # } # Splats: gara = (vincitore, partecipanti...) -> print vincitore, partecipanti #=>gara = function() { # var partecipanti, vincitore; # vincitore = arguments[0], partecipanti = 2 <= arguments.length ? __slice.call(arguments, 1) : []; # return print(vincitore, partecipanti); # }; # Esistenza: alert "Lo sapevo!" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("Lo sapevo!"); } # Comprensione degli Array: cubi = (matematica.cubo num for num in lista) #=>cubi = (function() { # var _i, _len, _results; # _results = []; # for (_i = 0, _len = lista.length; _i < _len; _i++) { # num = lista[_i]; # _results.push(matematica.cubo(num)); # } # return _results; # })(); cibi = ['broccoli', 'spinaci', 'cioccolato'] mangia cibo for cibo in cibi when cibo isnt 'cioccolato' #=>cibi = ['broccoli', 'spinaci', 'cioccolato']; # #for (_k = 0, _len2 = cibi.length; _k < _len2; _k++) { # cibo = cibi[_k]; # if (cibo !== 'cioccolato') { # mangia(cibo); # } #} ``` ## Altre risorse - [Smooth CoffeeScript](http://autotelicum.github.io/Smooth-CoffeeScript/) - [CoffeeScript Ristretto](https://leanpub.com/coffeescript-ristretto/read) ================================================ FILE: it/dynamic-programming.md ================================================ --- contributors: - ["Akashdeep Goel", "http://github.com/akashdeepgoel"] translators: - ["Ale46", "https://github.com/ale46"] --- # Programmazione dinamica ## Introduzione La programmazione dinamica è una tecnica potente utilizzata per risolvere una particolare classe di problemi, come vedremo. L'idea è molto semplice, se hai risolto un problema con l'input dato, salva il risultato come riferimento futuro, in modo da evitare di risolvere nuovamente lo stesso problema. Ricordate sempre! "Chi non ricorda il passato è condannato a ripeterlo" ## Modi per risolvere questi problemi 1. *Top-Down* : Inizia a risolvere il problema specifico suddividendolo. Se vedi che il problema è già stato risolto, rispondi semplicemente con la risposta già salvata. Se non è stato risolto, risolvilo e salva la risposta. Di solito è facile da pensare e molto intuitivo. Questo è indicato come Memoization. 2. *Bottom-Up* : Analizza il problema e vedi l'ordine in cui i sotto-problemi sono risolti e inizia a risolvere dal sottoproblema banale, verso il problema dato. In questo processo, è garantito che i sottoproblemi vengono risolti prima di risolvere il problema. Si parla di programmazione dinamica. ## Esempio di programmazione dinamica Il problema di "Longest Increasing Subsequence" consiste nel trovare la sottosequenza crescente più lunga di una determinata sequenza. Data una sequenza `S= {a1 , a2 , a3, a4, ............., an-1, an }` dobbiamo trovare il sottoinsieme più lungo tale che per tutti gli `j` e gli `i`, `j a[j] and LS[i] 1 # Liste, che sono implementate come liste concatenate (o linked list). [1,2,3] # lista (List) # Possiamo accedere alla testa (head) e alla coda (tail) delle liste così: [testa | coda] = [1,2,3] testa #=> 1 coda #=> [2,3] # In Elixir, proprio come in Erlang, il simbolo `=` denota pattern matching e # non un assegnamento. # # Questo significa che la parte sinistra (pattern) viene confrontata alla # parte destra. # # Questo spiega il funzionamento dell'esempio dell'accesso alla lista di prima. # Un pattern match darà errore quando le parti non combaciano, ad esempio se # le tuple hanno dimensione differente. # {a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2} # Ci sono anche i binari <<1,2,3>> # binari (Binary) # Stringhe e liste di caratteri "ciao" # stringa (String) 'ciao' # lista di caratteri (List) # Stringhe multilinea """ Sono una stringa multi-linea. """ #=> "Sono una stringa\nmulti-linea.\n" # Le stringhe sono tutte codificate in UTF-8: "cìaò" #=> "cìaò" # le stringhe in realtà sono dei binari, e le liste di caratteri sono liste. <> #=> "abc" [?a, ?b, ?c] #=> 'abc' # `?a` in Elixir restituisce il valore ASCII della lettera `a` ?a #=> 97 # Per concatenare liste si usa `++`, per binari si usa `<>` [1,2,3] ++ [4,5] #=> [1,2,3,4,5] 'ciao ' ++ 'mondo' #=> 'ciao mondo' <<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>> "ciao " <> "mondo" #=> "ciao mondo" # Gli intervalli sono rappresentati come `inizio..fine` (estremi inclusi) 1..10 #=> 1..10 (Range) minore..maggiore = 1..10 # Puoi fare pattern matching anche sugli intervalli [minore, maggiore] #=> [1, 10] ## --------------------------- ## -- Operatori ## --------------------------- # Un po' di matematica 1 + 1 #=> 2 10 - 5 #=> 5 5 * 2 #=> 10 10 / 2 #=> 5.0 # In Elixir l'operatore `/` restituisce sempre un decimale. # Per fare una divisione intera si usa `div` div(10, 2) #=> 5 # Per ottenere il resto di una divisione si usa `rem` rem(10, 3) #=> 1 # Ci sono anche gli operatori booleani: `or`, `and` e `not`. # Questi operatori si aspettano un booleano come primo argomento. true and true #=> true false or true #=> true # 1 and true #=> ** (BadBooleanError) expected a boolean on left-side of "and", got: 1 # Elixir fornisce anche `||`, `&&` e `!` che accettano argomenti # di qualsiasi tipo. # Tutti i valori tranne `false` e `nil` saranno valutati come true. 1 || true #=> 1 false && 1 #=> false nil && 20 #=> nil !true #=> false # Per i confronti abbiamo: `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<` e `>` 1 == 1 #=> true 1 != 1 #=> false 1 < 2 #=> true # `===` e `!==` sono più rigidi quando si confrontano interi e decimali: 1 == 1.0 #=> true 1 === 1.0 #=> false # Possiamo anche confrontare tipi di dato diversi: 1 < :ciao #=> true # L'ordine generale è definito sotto: # numeri < atomi < riferimenti < funzioni < porte < pid < tuple < liste # < stringhe di bit # Per citare Joe Armstrong su questo: "L'ordine non è importante, # ma è importante che sia definito un ordine." ## --------------------------- ## -- Controllo di flusso ## --------------------------- # espressione `se` (`if`) if false do "Questo non si vedrà mai" else "Questo sì" end # Ti ricordi il pattern matching? # Moltre strutture di controllo di flusso in Elixir si basano su di esso. # `case` ci permette di confrontare un valore a diversi pattern: case {:uno, :due} do {:quattro, :cinque} -> "Questo non farà match" {:uno, x} -> "Questo farà match e binderà `x` a `:due`" _ -> "Questo farà match con qualsiasi valore" end # Solitamente si usa `_` se non si ha bisogno di utilizzare un valore. # Ad esempio, se ci serve solo la testa di una lista: [testa | _] = [1,2,3] testa #=> 1 # Per aumentare la leggibilità possiamo usarlo in questo modo: [testa | _coda] = [:a, :b, :c] testa #=> :a # `cond` ci permette di verificare più condizioni allo stesso momento. # Usa `cond` invece di innestare più espressioni `if`. cond do 1 + 1 == 3 -> "Questa stringa non si vedrà mai" 2 * 5 == 12 -> "Nemmeno questa" 1 + 2 == 3 -> "Questa sì!" end # È pratica comune mettere l'ultima condizione a `true`, che farà sempre match cond do 1 + 1 == 3 -> "Questa stringa non si vedrà mai" 2 * 5 == 12 -> "Nemmeno questa" true -> "Questa sì! (essenzialmente funziona come un else)" end # `try/catch` si usa per gestire i valori lanciati (throw), # Supporta anche una clausola `after` che è invocata in ogni caso. try do throw(:ciao) catch message -> "Ho ricevuto #{message}." after IO.puts("Io sono la clausola 'after'.") end #=> Io sono la clausola 'after' # "Ho ricevuto :ciao" ## --------------------------- ## -- Moduli e Funzioni ## --------------------------- # Funzioni anonime (notare il punto) quadrato = fn(x) -> x * x end quadrato.(5) #=> 25 # Accettano anche guardie e condizioni multiple. # le guardie ti permettono di perfezionare il tuo pattern matching, # sono indicate dalla parola chiave `when`: f = fn x, y when x > 0 -> x + y x, y -> x * y end f.(1, 3) #=> 4 f.(-1, 3) #=> -3 # Elixir fornisce anche molte funzioni, disponibili nello scope corrente. is_number(10) #=> true is_list("ciao") #=> false elem({1,2,3}, 0) #=> 1 # Puoi raggruppare delle funzioni all'interno di un modulo. # All'interno di un modulo usa `def` per definire le tue funzioni. defmodule Matematica do def somma(a, b) do a + b end def quadrato(x) do x * x end end Matematica.somma(1, 2) #=> 3 Matematica.quadrato(3) #=> 9 # Per compilare il modulo 'Matematica' salvalo come `matematica.ex` e usa # `elixirc`. # nel tuo terminale: elixirc matematica.ex # All'interno di un modulo possiamo definire le funzioni con `def` e funzioni # private con `defp`. # Una funzione definita con `def` è disponibile per essere invocata anche da # altri moduli, una funziona privata può essere invocata solo localmente. defmodule MatematicaPrivata do def somma(a, b) do esegui_somma(a, b) end defp esegui_somma(a, b) do a + b end end MatematicaPrivata.somma(1, 2) #=> 3 # MatematicaPrivata.esegui_somma(1, 2) #=> ** (UndefinedFunctionError) # Anche le dichiarazioni di funzione supportano guardie e condizioni multiple. # Quando viene chiamata una funzione dichiarata con più match, solo la prima # che matcha viene effettivamente invocata. # Ad esempio: chiamando area({:cerchio, 3}) vedrà invocata la seconda definizione # di area mostrata sotto, non la prima: defmodule Geometria do def area({:rettangolo, w, h}) do w * h end def area({:cerchio, r}) when is_number(r) do 3.14 * r * r end end Geometria.area({:rettangolo, 2, 3}) #=> 6 Geometria.area({:cerchio, 3}) #=> 28.25999999999999801048 # Geometria.area({:cerchio, "non_un_numero"}) #=> ** (FunctionClauseError) no function clause matching in Geometria.area/1 # A causa dell'immutabilità dei dati, la ricorsione è molto frequente in Elixir defmodule Ricorsione do def somma_lista([testa | coda], accumulatore) do somma_lista(coda, accumulatore + testa) end def somma_lista([], accumulatore) do accumulatore end end Ricorsione.somma_lista([1,2,3], 0) #=> 6 # I moduli di Elixir supportano attributi. Ci sono degli attributi incorporati # e puoi anche aggiungerne di personalizzati. defmodule Modulo do @moduledoc """ Questo è un attributo incorporato in un modulo di esempio. """ @miei_dati 100 # Questo è un attributo personalizzato. IO.inspect(@miei_dati) #=> 100 end # L'operatore pipe |> permette di passare l'output di una espressione # come primo parametro di una funzione. # Questo facilita operazioni quali pipeline di operazioni, composizione di # funzioni, ecc. Range.new(1,10) |> Enum.map(fn x -> x * x end) |> Enum.filter(fn x -> rem(x, 2) == 0 end) #=> [4, 16, 36, 64, 100] ## --------------------------- ## -- Strutture ed Eccezioni ## --------------------------- # Le Strutture (Structs) sono estensioni alle mappe che portano # valori di default, garanzia alla compilazione e polimorfismo in Elixir. defmodule Persona do defstruct nome: nil, eta: 0, altezza: 0 end luca = %Persona{ nome: "Luca", eta: 24, altezza: 185 } #=> %Persona{eta: 24, altezza: 185, nome: "Luca"} # Legge al valore di 'nome' luca.nome #=> "Luca" # Modifica il valore di eta luca_invecchiato = %{ luca | eta: 25 } #=> %Persona{eta: 25, altezza: 185, nome: "Luca"} # Il blocco `try` con la parola chiave `rescue` è usato per gestire le eccezioni try do raise "un errore" rescue RuntimeError -> "Salvato un errore di Runtime" _error -> "Questo salverà da qualsiasi errore" end # Tutte le eccezioni hanno un messaggio try do raise "un errore" rescue x in [RuntimeError] -> x.message end ## --------------------------- ## -- Concorrenza ## --------------------------- # Elixir si basa sul modello degli attori per la concorrenza. # Tutto ciò di cui abbiamo bisogno per scrivere programmi concorrenti in Elixir # sono tre primitive: creare processi, inviare messaggi e ricevere messaggi. # Per creare un nuovo processo si usa la funzione `spawn`, che riceve una # funzione come argomento. f = fn -> 2 * 2 end #=> #Function spawn(f) #=> #PID<0.40.0> # `spawn` restituisce un pid (identificatore di processo). Puoi usare questo # pid per inviare messaggi al processo. # Per passare messaggi si usa l'operatore `send`. # Perché tutto questo sia utile dobbiamo essere capaci di ricevere messaggi, # oltre ad inviarli. Questo è realizzabile con `receive`: # Il blocco `receive do` viene usato per mettersi in ascolto di messaggi # ed elaborarli quando vengono ricevuti. Un blocco `receive do` elabora # un solo messaggio ricevuto: per fare elaborazione multipla di messaggi, # una funzione con un blocco `receive do` al suo intero dovrà chiamare # ricorsivamente sé stessa per entrare di nuovo nel blocco `receive do`. defmodule Geometria do def calcolo_area do receive do {:rettangolo, w, h} -> IO.puts("Area = #{w * h}") calcolo_area() {:cerchio, r} -> IO.puts("Area = #{3.14 * r * r}") calcolo_area() end end end # Compila il modulo e crea un processo che esegue `calcolo_area` nella shell pid = spawn(fn -> Geometria.calcolo_area() end) #=> #PID<0.40.0> # Alternativamente pid = spawn(Geometria, :calcolo_area, []) # Invia un messaggio a `pid` che farà match su un pattern nel blocco in receive send pid, {:rettangolo, 2, 3} #=> Area = 6 # {:rettangolo,2,3} send pid, {:cerchio, 2} #=> Area = 12.56000000000000049738 # {:cerchio,2} # Anche la shell è un processo. Puoi usare `self` per ottenere il pid corrente self() #=> #PID<0.27.0> ``` ## Referenze * [Getting started guide](http://elixir-lang.org/getting_started/1.html) dalla [pagina web ufficiale di Elixir](http://elixir-lang.org) * [Documentazione Elixir](https://elixir-lang.org/docs.html) * ["Programming Elixir"](https://pragprog.com/book/elixir/programming-elixir) di Dave Thomas * [Elixir Cheat Sheet](http://media.pragprog.com/titles/elixir/ElixirCheat.pdf) * ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) di Fred Hebert * ["Programming Erlang: Software for a Concurrent World"](https://pragprog.com/book/jaerlang2/programming-erlang) di Joe Armstrong ================================================ FILE: it/fish.md ================================================ --- contributors: - ["MySurmise", "https://github.com/MySurmise"] - ["Geo Maciolek", "https://github.com/GeoffMaciolek"] translators: - ["Mario Stabile", "https://github.com/mariostabile1"] filename: learnfish.fish --- Fish (**f**riendly **i**nteractive **sh**ell) è il nome di una shell esotica. Si tratta di una shell la cui sintassi non deriva né dalla Bourne-Shell né dalla C-Shell. Il vantaggio di fish è che molte caratteristiche che si desiderano in una shell moderna sono implementate out-of-the-box (già pronte), quindi non è necessario installare software aggiuntivi come zsh e oh-my-zsh. Esempi di queste caratteristiche sono i suggerimenti automatici, i colori a 24 bit, il completamento delle pagine man (cioè fish analizza automaticamente le pagine man e suggerisce opzioni aggiuntive per i comandi) o la possibilità di modificare le impostazioni attraverso una pagina web (quando è installata un'interfaccia grafica). È stato rilasciato nel Febbraio 2005. - [Leggi di più](https://fishshell.com/docs/current/language.html) - [Guida all'installazione](https://github.com/fish-shell/fish-shell#getting-fish) ## Guida Verifica di avere l'ultima versione di fish shell, Questa guida è stata fatta con la 3.3.0. Per farlo, scrivi: ``` > fish -v ``` Per avviare la shell di fish, scrivi: ``` > fish ``` per uscire, scrivi: ``` > exit ``` o premi Ctrl + D Ora, sin dall'inizio, c'è una cosa fastidiosa in fish. Il messaggio di benvenuto. A chi importa, giusto? Quando si avvia la shell, basta scrivere: ``` > set -U fish_greeting "" ``` Se volessi eseguire un singolo comando in bash, senza passare a quella shell, puoi scrivere: ``` > bash -c 'echo "Questo testo sarà stampato sul terminale"' ``` Su fish, si possono usare sia le singole che le doppie virgolette. Il carattere di escape è uno `\` (slash) Puoi cambiare le configurazioni di fish modificando il file di config ``` > vim ~/.config/fish/config.fish ``` o aprendo l'interfaccia web: ``` > fish_config ``` Aggiungere qualcosa alla variabile PATH di fish è semplice: ``` > fish_add_path ~/cowsay ``` Questo puoi farlo con bash, eh? No, devi sempre cercarlo... Così è facile! Ma c'è di più. La maggior parte dei comandi specifici per fish iniziano, hai indovinato, con 'fish'. Basta scrivere `fish` e premere TAB. Ed ecco una delle tante funzioni interessanti di fish: L'autocompletamento che **funziona.** Ora puoi navigare con TAB, Shift + TAB e le frecce . Per avere aiuto, chiama il tuo psichiatra di fiducia oppure scrivi `man`. Ti mostrerà il manuale per quel comando, per esempio: ``` > man set ``` Se finalmente hai provato fish, potrai vedere in questa shell qualcosa di diverso, il che è molto figo. Ogni cosa ha colori fantastici, se scrivi qualcosa di sbagliato viene segnato in rosso, senza nemmeno eseguirlo!, se si mette qualcosa tra virgolette, si vede dove finisce e perchè quella citazione non funziona. fish ha varie altre cose interessanti, come le wildcards (o carattere jolly). Per esempio, scrivi: ``` > ls *.fish ``` Questo elencherà ogni file .fish nella directory corrente. Puoi avere multiple wildcards per comando o anche una wildcard ricorsiva, `**`, il che significa che includerà tutti i sotto-file e le sotto-directory presenti nella directory corrente. Per esempio, il seguente comando restituirà (in questo caso): ``` > ls ~/images/**.jpg ~/images/nudini/pewdiepie.jpg ~/images/nudini/peppa.jpg ~/images/screenshots/2020-42-69.jpg ~/images/omegalul.jpg ``` Ovviamente, puoi anche inviare l'output di un comando ad un'altro con una pipe ``` >echo . Qui ci sarà un testo | grep [udense] ``` scrivere su un file: ``` >echo Questo\ é\ un\ testo > file.txt ``` (notato il carattere di escape?) Aggiungere a un file: ``` >echo Questa\ è\ una\ riga >> file.txt >echo Questa\ è\ un'altra\ riga >> file.txt ``` Per l'autompletamento, basta premere sempre TAB. Ti sorprenderà quante cose conosce fish Per usare le variabili, basta scrivere `$VAR`, come in bash. ``` > echo "La mia home è $HOME" La mia home è /home/mioutente ``` Qui arriva la differenza tra le virgolette singole e doppie. Se usi una variabile dentro singole virgolette, non verrà sostituita. ``` > echo 'La mia home è $HOME' La mia home è $HOME ``` Più info sulle variabili successivamente. Per eseguire due comandi, separali con `;` ``` > echo Lol; echo questo è divertente ``` Lo status dell'ultimo comando eseguito è contenuto in `$status` Puoi usare && per due comandi che dipendolo l'uno dall'altro. ``` > set var lol && echo $var ``` Puoi anche usare `and` che esegue solo se il comando precedente ha avuto successo, `or` che esegue solo se il comando precedente fallisce, e `not` che inverte lo stato di output del comando. Per esempio: ``` > if not echo Testo testo, bla bla bla echo Altro testo, bla bla end ``` (Ovviamente tutto questo lo puoi fare nella shell) --- Adesso cominciamo con la parte di scripting di fish. Come per ogni shell, puoi non solo eseguire comandi nella shell, ma anche da file, salvati come file `.fish`. (Puoi anche eseguire file `.sh` con la sintassi di fish, ma io uso sempre l'estensione `.fish` per la sintassi di fish per distinguerla dai file in bash) ```fish # Questo è un commento in fish. # # Se esegui un file senza specificare un interprete, # cioè il programma che fa girare il tuo script, è necessario per dire alla shell, # dove l'interprete è posizionato. # In fish basta aggiungere questo commento nella prima linea del tuo script: #!/bin/fish # Quando esegui lo script tramite, per esempio, fish /path/to/script.fish # non è necessario, perchè hai specificato fish come interprete # Cominciamo con le variabili. # per l'uso interno a un programma, puoi usare la sintassi set nome 'La mia variabile' # Utilizzo... set -x nome valore # per esportare, o set -e nome # per Eliminare # una variabile settata con uno spazio non viene inviata come due argomenti, ma come uno solo, come ci si aspetterebbe. set directoryBella 'Directory Bella' mkdir $directoryBella # Questo creerà una sola directory, come ci si aspetterebbe, non due come in bash... # chi vorrebbe una roba del genere? è UnA FeAtUrE n0n Un BuG... # puoi anche avere liste in forma di variabili. Questo ha senso, perchè se volessi una variabile che crei due directory, basta dare a mkdir un elenco di nomi di directory. # puoi anche contare le istanze nella lista con: count $PATH # Non solo è tutto fantastico, ma in fish, tutto è anche una lista. # $PWD per esempio è una lista di lunghezza 1. # Per fare una lista, basta dare al comando set più argomenti: set list argomento1 argomento2 argomento3 # in questo modo puoi anche inserire qualcosa in una variabile pre-esistente: set PATH $PATH ~/cowsay/ # Ma, come precedentemente menzionato, abbiamo anche un'altro modo più semplice per farlo, specialmente in fish. # Come per ogni Array/Lista, puoi anche accedergli con $listavar[2] # ci sono anche gli intervalli $listavar[1..5] # puoi anche usare numeri negativi $listavar[-1] # accesso all'ultimo elemento. # Quando combini due liste di variabili puoi anche usare un bel prodotto cartesiano:: set a 1 2 3 set 1 a b c echo $a$1 # Restituirà : 1a 2a 3a 1b 2b 3b 1c 2c 3c # Naturalmente, se li si separa, saranno visti come due argomenti separati e li stamperà uno dopo l'altro. QUESTO è il comportamento che ci si aspetta da @bash. # Ci sono anche altre cose utili, come la sostituzione di comandi. Per esempio, quando vuoi che ti sia restituito l'output di due comandi in una sola riga. In bash lo faresti in questo modo echo "`ls` è in $PWD" # oppure echo "$(ls) è in $PWD" # secondo me, non è necessario. Scrivo sempre l'apostrofo sbagliato. Perchè non usare semplicemente le parentesi, come in fish? echo (ls) è in $PWD # Yep, è facile. E grazie all'highlighting di fish lo puoi vedere istantaneamente, se lo scrivi correttamente. # E, come ci si aspetterebbe, a mio avviso, i comandi non funzionano tra virgolette. Voglio dire, perchè bash? Ok adesso la smetto. Ma in fish, basta fare: echo (ls)" è in $PWD" # oppure set miavar "Il file"(ls -a)" è nella directory $PWD" # creerà una lista con la stringa e tutti i file. Prova. Non è una figata? # E per semparare le variabili in diversi argomenti, basta mettere uno spazio: set miavar "I file" (ls -a) " sono nella directory $PWD" # Ci sono anche if, else if, else if grep fish /etc/shells echo Trovato fish else if grep bash /etc/shells echo Trovato bash else echo Non ho trovato niente end # Risulta un pò strano confrontare due cose con un solo segno =, ovviamente perchè non en abbiamo bisogno per settare le variabili, ma comunque... e la parola chiave "test": if test $var = "test" echo si else echo no end # Naturalmente, ci sono anche gli switch case switch $OS case Linux echo "Sei un grande" case Windows echo "Potresti provare fish su WSL" case MacOS echo "Su MacOS c'è fish!" case '*' echo "quale OS è $OS, per favore?" end # le funzioni in fish prendono gli argomenti attraverso la variabile $argv. La sintassi è la seguente: function stampa echo $argv end # Ci sono anche gli eventi, come l'evento "fish_exit" (Cosa farà mai, hmm?). # Puoi usarli aggiungendoli alle definizioni di funzione: function in_uscita --on-event fish_exit echo fish si sta chiuendo end # trova gli eventi con il comando functions --handlers # Puoi usare il comando functions per approfondire, beh, le funzioni. # Per esempio puoi far stampare il codice sorgente di ogni funzione: functions cd functions print # oppure ottenere il nome di ogni funzione: functions # Ci sono i cicli while, ovviamente while test $var = lol echo lol end # Cicli for (con le wildcards, sono ancora meglio): for immagine in *.jpg echo $immagine end # c'è un equivalente di range(0, 5) in Python, quindi puoi anche fare il classico ciclo for con i numeri: set files (ls) for numeri in (seq 10) echo "$files[$numeri] è il file numero $numeri" end # Bello! # L'equivalente di bashrc non è fishrc, ma il già citato file config.fish in ~/.config/fish/ # Per aggiungere una funzione a fish, però, occorre creare un semplice file .fish in quella directory. Non incollare la funzione nel file config.fish. È brutto. # Se avete altro da dire, aggiugete pure, ma queste sono le basi più importanti. ``` ================================================ FILE: it/gdscript.md ================================================ --- contributors: - ["Wichamir", "https://github.com/Wichamir/"] - ["zacryol", "https://github.com/zacryol"] translators: - ["lele25811", "https://github.com/lele25811"] --- GDScript un linguaggio di scripting dinamicamente e staticamente tipizzato per il motore di gioco gratuito e open source Godot. La sua sintassi è vagamente simile a quella di Python. I suoi principali vantaggi sono la facilità d'uso e la stretta integrazione con il motore di gioco. È perfetto per lo sviluppo di giochi. ## Basi ```gdscript # I commenti a linea singola sono scritti usando il simbolo hash. """ Commenti su più linee sono scritti usando i triplici apici doppi """ # I commenti del documento possono aggiungere una descrizione a classi e campi # che può essere visualizzato nella documentazione del engine. ## Questa classe è una dimostrazione di GDScript. # Il file script è una classe e puoi opzionalmente definire un nome. class_name MyClass # Eredita extends Node2D # Variabili var x = 8 # int var y = 1.2 # float var b = true # bool var s = "Hello World!" # String var a = [1, false, "brown fox"] # Array - simile alle liste in Python, # può contenere diversi tipi # di variabili contemporaneamente. var d = { "key" : "value", 42 : true } # Dizionario - contiene coppie chiave-valore. var p_arr = PackedStringArray(["Hi", "there", "!"]) # Array impacchettato può # contenere solo un tipo di dato. # Commenti della documentazione applicati alle proprietà. ## Quante volte questo oggetto ha saltato var jump_count = 0 # Tipi vettoriali integrati: var v2 = Vector2(1, 2) var v3 = Vector3(1, 2, 3) # Costanti const ANSWER_TO_EVERYTHING = 42 const BREAKFAST = "Spam and eggs!" # Enumerazioni enum { ZERO, ONE , TWO, THREE } enum NamedEnum { ONE = 1, TWO, THREE } # Le variabili esportate sono visibili nell'ispettore. # # oppure un tipo suggerimento (spiegato in seguito) o un valore predefinito che è necessario in seguito # l'editor suggerisce diverse opzioni @export var age: int @export var height: float @export var person_name = "Bob" # Ma entrambe sono accettate @export var favorite_color: String = "Green" @export var favorite_food := "Pizza" # Funzioni func foo(): pass # pass è la parola chiave per passare al codice successivo func add(first, second): return first + second # Commenti documentazione sulle funzioni ## Incrementa il conteggio dei salti func jump(): jump_count += 1 # Stampa valori func printing(): print("GDScript ", "is ", " awesome.") prints("These", "words", "are", "divided", "by", "spaces.") printt("These", "words", "are", "divided", "by", "tabs.") printraw("This gets printed to system console.") # Funzioni Lambda var my_lambda = func(): print("hello from lambda!") my_lambda.call() # Matematica func doing_math(): var first = 8 var second = 4 print(first + second) # 12 print(first - second) # 4 print(first * second) # 32 print(first / second) # 2 print(first % second) # 0 # Ci sono anche +=, -=, *=, /=, %= etc., # Anche operatori ++ o --. print(pow(first, 2)) # 64 print(sqrt(second)) # 2 printt(PI, TAU, INF, NAN) # Costanti Integrate # Controllo del flusso func control_flow(): x = 8 y = 2 # y era inizialmente un float, # ma possiamo cambiare il tipo in int # stiamo usando la potenza della programmazione dinamica! if x < y: print("x is smaller than y") elif x > y: print("x is bigger than y") else: print("x and y are equal") var a = true var b = false var c = false if a and b or not c: # in alternativa puoi utilizzare &&, || e ! print("This is true!") for i in range(20): # L'intervallo di GDScript è simile a quello di Python print(i) # questo stamperà i numeri da 0 a 29 for i in 20: # differentemente da Python puoi ciclare direttamente su un int print(i) # questo stamperà i numeri da 0 a 19 for i in ["two", 3, 1.0]: # iterazione su un array print(i) while x > y: printt(x, y) y += 1 x = 2 y = 10 while x < y: x += 1 if x == 6: continue # 6 non verrà stampato causa la dichiarazione: continue prints("x is equal to:", x) if x == 7: break # il ciclo si fermerà a 7, quindi 8, 9 e 10 non verranno stampati match x: 1: print("Match is similar to switch.") 2: print("However you don't need to put cases before each value.") 3: print("Furthermore each case breaks on default.") break # ERRORE! la dichiarazione break non è necessaria 4: print("If you need fallthrough use continue.") continue _: print("Underscore is a default case.") # operatore ternario (la dichiarazione if-else è su una linea) prints("x is", "positive" if x >= 0 else "negative") # Assegnazione delle parti (Casting) func casting_examples(): var i = 42 var f = float(42) # assegnazione utilizzando il costruttore di variabili var b = i as bool # oppure utilizzando la parola "as" # Funzioni di sovraccarico (Override functions) # Per convenzione le funzione di Override iniziano con un trattino basso ( _ ), # ma in pratica puoi fare l'Override di qualsiasi funzione. # _init è chiamata quando un oggetto viene inizializzato # È il costuttore del oggetto func _init(): # Inizializza le cose interne dell'oggetto pass # _ready viene chiamato quando il nodo di script e # i suoi figli sono entrati nell'albero della scena. func _ready(): pass # _process viene chiamato ogni frame func _process(delta): # L'argomento Delta passato a questa funzione è il numero di secondi # che passa tra l'ultimo frame e quello attuale. print("Delta time equals: ", delta) # _physics_process viene chiamato ogni frame di fisica. # Ciò significa che delta dovrebbe essere una costante. func _physics_process(delta): # Semplice movimento mediante la somma vettoriale e la moltiplicazione. var direction = Vector2(1, 0) # oppure Vector2.RIGHT var speed = 100.0 self.global_position += direction * speed * delta # self si riferisce a se stesso nel attuale istanza di classe # Quando si fa l'override di una funzione si può chiamare la funzione padre # tramite la funzione super() # come qui: func get_children(): # Fai cose in più qui. var r = super() # implementazione della chiamata alla funzione padre return r # Classe annidata class InnerClass: extends Object func hello(): print("Hello from inner class!") func use_inner_class(): var ic = InnerClass.new() ic.hello() ic.free() # utilizza free per pulire la memoria ``` ## Accesso ad altri nodi nel albero di scena ```gdscript extends Node2D var sprite # La variabile conterrà il riferimento. # Puoi ottenere le referenze per gli altri nodi in _ready. func _ready() -> void: # NodePath è utile per accedere ai nodi. # Crea NodePath passando il percorso al suo costruttore: var path1 = NodePath("path/to/something") # alternativamente puoi usare NodePath così: var path2 = ^"path/to/something" # NodePath esempi: var path3 = ^"Sprite" # percorso relativo, primo figlio dell'attuale nodo var path4 = ^"Timers/Firerate" # percorso relativo, figlio di suo figlio var path5 = ^".." # genitore del nodo corrente var path6 = ^"../Enemy" # fratello del nodo corrente var path7 = ^"/root" # percorso assoluto, equivalente a get_tree().get_root() var path8 = ^"/root/Main/Player/Sprite" # percorso assoluto alla sprite del giocatore var path9 = ^"Timers/Firerate:wait_time" # accesso alle proprietà var path10 = ^"Player:position:x" # accesso alle sottoproprietà # Infine per ottenere un riferimento usa uno di questi: sprite = get_node(^"Sprite") as Sprite # sempre usata con il tipo di dati che ti aspetti sprite = get_node("Sprite") as Sprite # qui ottiene una stringa # implicitamente lanciato come NodePath sprite = get_node(path3) as Sprite sprite = get_node_or_null("Sprite") as Sprite sprite = $Sprite as Sprite func _process(delta): # Ora possiamo riutilizzare il riferimento ad altri luoghi prints("Sprite has global_position of", sprite.global_position) # Usiamo l'annotazione @onready per assegnare un valore # a una variabile prima del esecuzione di _ready. # Questa è la sintassi comunemente utilizzata. @onready var other_sprite = $Sprite as Sprite # Puoi esportare NodePath, così da poterlo assegnare all'interno dell'ispettore. @export var nodepath = ^"" @onready var reference = get_node(nodepath) as Node # oppure esportare un nodo direttamente @export var other_reference: Node ``` ## Segnali (Signals) Il sistema del segnali in Godot è una implementazione del pattern observer. Ecco un esempio: ```gdscript class_name Player extends Node2D var hp = 10 # La documentazione può andare anche sui segnali ## Emesso quando il giocatore muore signal died() # definisci un segnale signal hurt(hp_old, hp_new) # il segnale prende un argomento func apply_damage(dmg): var hp_old = hp hp -= dmg hurt.emit(hp_old, hp) # emette un segnale e passa un argomento if hp <= 0: died.emit() func _ready(): # connette il segnale "died" alla funzione "_on_death" definita in automatico died.connect(_on_death) # Alternativamente # se l'oggetto target non è se stesso, ma un altro oggetto # died.connect(Callable(self, &"_on_death")) func _on_death(): queue_free() # distrugge il giocatore alla morte ``` ## Tipi suggeriti (Type hints) GDScript opzionalmente può utilizzare la tipizzazione statica, sia per la chiarezza del codice che per i vantaggi delle prestazioni. ```gdscript extends Node var x: int # definizione del tipo di variabile var y: float = 4.2 var z := 1.0 # accenno del tipo per i valori di default usiamo l'operatore := var a: Array[int] = [1, 2, 3] # gli array possono anche avere un tipo specifico per il contenuto enum NamedEnum { ONE = 1, TWO, THREE } var n: NamedEnum = NamedEnum.ONE # l'enumerazione può essere usata anche come tipo @onready var node_ref_typed := $Child as Node @export var speed := 50.0 const CONSTANT := "Typed constant." signal example(arg: int) func _ready() -> void: # funzione che ritorna nulla x = "string" # ERRORE! Il tipo non può essere cambiato a.append("q") # ERRORE! Array[int] non può contenere stringhe return func join(arg1: String, arg2: String) -> String: # la funzione prende in input due stringhe e ritorna una stringa return arg1 + arg2 func get_child_at(index: int) -> Node: # funzione prende in input un int e ritorna un nodo return get_children()[index] ``` ## Ulteriori letture * [Sito web di Godot](https://godotengine.org/) * [Documentazione Godot](https://docs.godotengine.org/en/stable/) * [Inizia con GDScript](https://docs.godotengine.org/en/stable/getting_started/scripting/gdscript/index.html) * [NodePath](https://docs.godotengine.org/en/stable/classes/class_nodepath.html) * [Signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/signals.html) * [GDQuest](https://www.gdquest.com/) * [GDScript.com](https://gdscript.com/) ================================================ FILE: it/git.md ================================================ --- contributors: - ["Jake Prather", "http://github.com/JakeHP"] - ["Leo Rudberg" , "http://github.com/LOZORD"] - ["Betsy Lorton" , "http://github.com/schbetsy"] - ["Bruno Volcov", "http://github.com/volcov"] translators: - ["Christian Grasso", "http://chris54721.net"] --- Git è un sistema di [controllo versione distribuito](https://it.wikipedia.org/wiki/Controllo_versione_distribuito) e di gestione del codice sorgente. Git esegue una serie di _snapshot_ per salvare lo stato di un progetto, così facendo può fornirti la possibilità di gestire il tuo codice e di salvarne lo stato assegnando delle versioni. ## Basi del controllo versione ### Cos'è il controllo versione? Il controllo versione (_Version Control_ o _Versioning_) è un sistema che registra le modifiche apportate a uno o più file nel tempo. ### Controllo versione centralizzato e distribuito * Il controllo versione centralizzato si concentra sulla sincronizzazione, il monitoraggio e il backup dei file. * Il controllo versione distribuito si concentra sulla condivisione delle modifiche. Ogni modifica ha un identificatore univoco. * I sistemi distribuiti non hanno una struttura definita. Si potrebbe creare ad esempio un sistema centralizzato simile a SVN utilizzando Git. [Ulteriori informazioni](https://git-scm.com/book/it/v2/Per-Iniziare-Il-Controllo-di-Versione) ### Perchè usare Git? * Consente di lavorare offline. * Collaborare con altre persone è semplice! * Utilizzare i branch (rami di sviluppo) è semplice! * Git è veloce. * Git è flessibile. ## Architettura di Git ### Repository Un insieme di file, cartelle, registrazioni della cronologia e versioni. Immaginalo come una struttura dati del codice, con la caratteristica che ogni "elemento" del codice ti fornisce accesso alla sua cronologia delle revisioni, insieme ad altre cose. Un repository comprende la cartella .git e il working tree. ### Cartella .git (componente del repository) La cartella .git contiene tutte le configurazioni, i log, i rami e altro. [Lista dettagliata](https://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html) ### Working Tree (componente del repository) Si tratta semplicemente delle cartelle e dei file presenti nel repository. Spesso viene indicato come "directory di lavoro" ("working directory"). ### Index (componente della cartella .git) L'Index è l'area di staging di Git. Si tratta di un livello che separa il working tree dal repository. Ciò fornisce agli sviluppatori più controllo su cosa viene inviato al repository. ### Commit Un commit è uno snapshot di una serie di modifiche apportate al working tree. Ad esempio, se hai aggiunto 5 file e ne hai rimossi 2, ciò sarà registrato in un commit. Il commit può essere pushato (inviato) o meno ad altri repository. ### Branch (ramo) Un branch (ramo) è essenzialmente un puntatore all'ultimo commit che hai effettuato. Effettuando altri commit, il puntatore verrà automaticamente aggiornato per puntare all'ultimo commit. ### Tag Un tag è un contrassegno applicato a un punto specifico nella cronologia dei commit. Di solito i tag vengono utilizzati per contrassegnare le versioni rilasciate (v1.0, v1.1, etc.). ### HEAD e head (componenti della cartella .git) HEAD (in maiuscolo) è un puntatore che punta al branch corrente. Un repository può avere solo 1 puntatore HEAD *attivo*. head (in minuscolo) è un puntatore che può puntare a qualsiasi commit. Un repository può avere un numero qualsiasi di puntatori head. ### Stadi di Git * _Modified_ - Un file è stato modificato, ma non è ancora stato effettuato un commit per registrare le modifiche nel database di Git * _Staged_ - Un file modificato è stato contrassegnato per essere incluso nel prossimo commit * _Committed_ - È stato effettuato un commit e le modifiche sono state registrate nel database di Git ## Comandi ### init Crea un repository Git vuoto. Le impostazioni e le informazioni del repository sono salvate nella cartella ".git". ```bash $ git init ``` ### config Utilizzato per configurare le impostazioni, sia specifiche del repository, sia a livello globale. Le impostazioni globali sono salvate in `~/.gitconfig`. ```bash $ git config --global user.email "email@example.com" $ git config --global user.name "Nome utente" ``` [Ulteriori informazioni su git config](https://git-scm.com/docs/git-config) ### help Fornisce una documentazione molto dettagliata di ogni comando. ```bash # Mostra i comandi più comuni $ git help # Mostra tutti i comandi disponibili $ git help -a # Documentazione di un comando specifico # git help $ git help add $ git help commit $ git help init # oppure git --help $ git add --help $ git commit --help $ git init --help ``` ### Ignorare file Per impedire intenzionalmente che file privati o temporanei vengano inviati al repository Git. ```bash $ echo "temp/" >> .gitignore $ echo "privato.txt" >> .gitignore ``` ### status Mostra le differenza tra lo stato attuale del working tree e l'attuale commit HEAD. ```bash $ git status ``` ### add Aggiunge file alla staging area, ovvero li contrassegna per essere inclusi nel prossimo commit. Ricorda di aggiungere i nuovi file, altrimenti non saranno inclusi nei commit! ```bash # Aggiunge un file nella directory attuale $ git add HelloWorld.java # Aggiunge un file in una sottocartella $ git add /path/to/file/HelloWorld.c # Il comando supporta le espressioni regolari $ git add ./*.java # Aggiunge tutti i file non ancora contrassegnati $ git add --all ``` Questo comando contrassegna soltanto i file, senza effettuare un commit. ### branch Utilizzato per gestire i branch (rami). Puoi visualizzare, modificare, creare o eliminare branch utilizzando questo comando. ```bash # Visualizza i branch e i remote $ git branch -a # Crea un nuovo branch $ git branch nuovoBranch # Elimina un branch $ git branch -d nomeBranch # Rinomina un branch $ git branch -m nomeBranch nuovoNomeBranch # Permette di modificare la descrizione di un branch $ git branch nomeBranch --edit-description ``` ### tag Utilizzato per gestire i tag. ```bash # Visualizza i tag esistenti $ git tag # Crea un nuovo tag # L'opzione -m consente di specificare una descrizione per il tag. # Se l'opzione -m non viene aggiunta, Git aprirà un editor per consentire # l'inserimento del messaggio. $ git tag -a v2.0 -m 'Versione 2.0' # Mostra informazioni relative a un tag # Include informazioni sul creatore del tag, la data di creazione, e il # messaggio assegnato al tag oltre alle informazioni sul commit. $ git show v2.0 ``` ### checkout Consente di cambiare branch o ripristinare i file a una revisione specifica. Tutti i file nel working tree vengono aggiornati per corrispondere alla versione presente nel branch o nel commit specificato. ```bash # Effettua il checkout di un repository - il branch predefinito è 'master' $ git checkout # Effettua il checkout di un branch specifico $ git checkout nomeBranch # Crea un nuovo branch e ne effettua il checkout # Equivalente a "git branch ; git checkout " $ git checkout -b nuovoBranch ``` ### clone Clona, o copia, un repository esistente in una nuova directory. Inoltre, aggiunge dei branch _remote-tracking_, utilizzati per monitorare i branch remoti corrispondenti a quelli locali, e consentendo così di inviare le modifiche al repository remoto. ```bash # Clona learnxinyminutes-docs $ git clone https://github.com/adambard/learnxinyminutes-docs.git # Clona solo l'ultima revisione di un repository $ git clone --depth 1 https://github.com/adambard/learnxinyminutes-docs.git # Clona solo un branch specifico $ git clone -b master-cn https://github.com/adambard/learnxinyminutes-docs.git --single-branch ``` ### commit Effettua uno _snapshot_ dello stato attuale del working tree e registra le modifiche in un nuovo commit. Il commit contiene, oltre alle modifiche apportate, anche l'autore e una descrizione. ```bash # Crea un nuovo commit con un messaggio $ git commit -m "Aggiunta la funzione multiplyNumbers() in HelloWorld.c" # Aggiunge (git add) automaticamente i file modificati o eliminati (ESCLUSI # i nuovi file) e quindi effettua il commit $ git commit -a -m "Modificato foo.php e rimosso bar.php" # Modifica l'ultimo commit (il comando elimina il commit precedente e lo # sostituisce con uno nuovo) $ git commit --amend -m "Messaggio corretto" ``` ### diff Mostra la differenza tra un file nel working tree e la sua versione nell'index, in un branch o ad un commit specifico. ```bash # Mostra la differenza tra il working tree e l'index $ git diff # Mostra la differenza tra l'index e il commit più recente $ git diff --cached # Mostra la differenza tra il working tree e un commit specifico $ git diff # Mostra la differenza tra due commit $ git diff ``` ### grep Consente di effettuare una ricerca veloce nel repository. ```bash # Cerca "variableName" nei file Java $ git grep 'variableName' -- '*.java' # Cerca una riga contenente "arrayListName" E "add" oppure "remove" $ git grep -e 'arrayListName' --and \( -e add -e remove \) ``` Impostazioni relative a `git grep`: ```bash # Mostra il numero delle righe $ git config --global grep.lineNumber true # Rende i risultati più leggibili $ git config --global alias.g "grep --break --heading --line-number" ``` ### log Mostra la cronologia dei commit inviati al repository. ```bash # Mostra tutti i commit $ git log # Mostra ogni commit su una sola riga $ git log --oneline # Mostra solo i commit legati ai merge $ git log --merges ``` ### merge Effettua un "merge", ovvero unisce le modifiche di un branch in quello attuale. ```bash # Unisce il branch specificato a quello attuale $ git merge nomeBranch # Genera un commit in ogni caso dopo aver eseguito il merge $ git merge --no-ff nomeBranch ``` ### mv Rinomina o sposta un file. ```bash # Rinomina un file $ git mv HelloWorld.c HelloNewWorld.c # Sposta un file $ git mv HelloWorld.c ./new/path/HelloWorld.c # Forza l'esecuzione del comando # Se un file "nuovoNomeFile" esiste già nella directory, verrà sovrascritto $ git mv -f nomeFile nuovoNomeFile ``` ### pull Aggiorna il repository effettuando il merge delle nuove modifiche. ```bash # Aggiorna il branch attuale dal remote "origin" $ git pull # Di default, git pull aggiorna il branch attuale effettuando il merge # delle nuove modifiche presenti nel branch remote-tracking corrispondente $ git pull # Aggiorna le modifiche dal branch remoto, quindi effettua il rebase dei commit # nel branch locale # Equivalente a: "git pull ; git rebase " $ git pull origin master --rebase ``` ### push Invia ed effettua il merge delle modifiche da un branch locale ad uno remoto. ```bash # Invia ed effettua il merge delle modifiche dal branch "master" # al remote "origin". # git push $ git push origin master # Di default, git push invia ed effettua il merge delle modifiche # dal branch attuale al branch remote-tracking corrispondente $ git push # Per collegare il branch attuale ad uno remoto, basta aggiungere l'opzione -u $ git push -u origin master ``` ### stash Salva lo stato attuale del working tree in una lista di modifiche non ancora inviate al repository con un commit che possono essere applicate nuovamente in seguito. Questo comando può essere utile se, ad esempio, mentre stai effettuando delle modifiche non ancora completate, hai bisogno di aggiornare il repository locale con `git pull`. Poichè non hai ancora effettuato il commit di tutte le modifiche, non sarà possibile effettuare il pull. Tuttavia, puoi utilizzare `git stash` per salvare temporaneamente le modifiche e applicarle in seguito. ```bash $ git stash ``` Ora puoi effettuare il pull: ```bash $ git pull ``` A questo punto, come già suggerito dall'output del comando `git stash`, puoi applicare le modifiche: ```bash $ git stash apply ``` Infine puoi controllare che tutto sia andato bene: ```bash $ git status ``` Puoi visualizzare gli accantonamenti che hai effettuato finora utilizzando: ```bash $ git stash list ``` ### rebase (attenzione) Applica le modifiche effettuate su un branch su un altro branch. *Non effettuare il rebase di commit che hai già inviato a un repository pubblico!* ```bash # Effettua il rebase di experimentBranch in master $ git rebase master experimentBranch ``` [Ulteriori informazioni](https://git-scm.com/book/it/v2/Git-Branching-Rebasing) ### reset (attenzione) Effettua il reset del commit HEAD attuale ad uno stato specifico. Questo comando consente di annullare `merge`, `pull`, `commit`, `add` e altro. Tuttavia, può essere pericoloso se non si sa cosa si sta facendo. ```bash # Effettua il reset della staging area (annullando le aggiunte e le rimozioni # di file dal repository, senza modificare il working tree) $ git reset # Effettua il reset completo della staging area, ovvero annulla qualsiasi # modifica al repository eliminando definitivamente anche tutte le modifiche # ai file non inviate e ripristinando il working tree $ git reset --hard # Effettua il reset del branch attuale al commit specificato (lasciando il # working tree intatto) $ git reset 31f2bb1 # Effettua il reset completo del branch attuale al commit specificato, # eliminando qualsiasi modifica non inviata $ git reset --hard 31f2bb1 ``` ### rm Consente di rimuovere un file dal working tree e dal repository. Per eliminare un file solo dal working tree ma non dal repository, è invece necessario utilizzare `/bin/rm`. ```bash # Elimina un file nella directory attuale $ git rm HelloWorld.c # Elimina un file da una sottocartella $ git rm /pather/to/the/file/HelloWorld.c ``` ================================================ FILE: it/go.md ================================================ --- contributors: - ["Sonia Keys", "https://github.com/soniakeys"] - ["Christopher Bess", "https://github.com/cbess"] - ["Jesse Johnson", "https://github.com/holocronweaver"] - ["Quint Guvernator", "https://github.com/qguv"] - ["Jose Donizetti", "https://github.com/josedonizetti"] - ["Alexej Friesen", "https://github.com/heyalexej"] - ["Clayton Walker", "https://github.com/cwalk"] translators: - ["Tommaso Pifferi","http://github.com/neslinesli93"] --- Go è stato creato per avere tra le mani uno strumento in grado di arrivare al punto, nel modo più veloce ed efficiente possibile. Non è all'ultima moda tra i linguaggi di programmazione, ma è una delle migliori soluzioni per risolvere in maniera efficace i problemi di tutti i giorni. Go presenta alcuni concetti già presenti nei linguaggi imperativi con tipizzazione statica. Compila velocemente ed esegue altrettanto veloce. Aggiunge la concorrenza in maniera diretta e semplice da capire, per far forza sulle CPU multi-core di oggigiorno. Presenta caratteristiche utili per la programmazione in larga scala. Go include un'ottima libreria standard e ha una community entusiasta. ```go // Commento su riga singola /* Commento su riga multipla */ // In cima ad ogni file è necessario specificare il package. // main è un package speciale che identifica un eseguibile anziché una libreria. package main // Con import sono dichiarate tutte le librerie a cui si fa riferimento // all'interno del file. import ( "fmt" // Un package nella libreria standard di Go. "io/ioutil" // Implementa alcune funzioni di utility per l'I/O. m "math" // Libreria matematica, con alias locale m "net/http" // Sì, un web server! "strconv" // Package per la conversione di stringhe. ) // Una definizione di funzione. Il main è speciale: è il punto di ingresso // per il programma. Amalo o odialo, ma Go usa le parentesi graffe. func main() { // Println stampa una riga a schermo. // Questa funzione è all'interno del package fmt. fmt.Println("Ciao mondo!") // Chiama un'altra funzione all'interno di questo package. oltreIlCiaoMondo() } // Le funzioni ricevono i parametri all'interno di parentesi tonde. // Se la funzione non riceve parametri, vanno comunque messe le parentesi (vuote). func oltreIlCiaoMondo() { var x int // Dichiarazione di una variabile. Ricordati di dichiarare sempre le variabili prima di usarle! x = 3 // Assegnazione di una variabile. // E' possibile la dichiarazione "rapida" := per inferire il tipo, dichiarare e assegnare contemporaneamente. y := 4 // Una funzione che restituisce due valori. somma, prod := imparaMoltepliciValoriRestituiti(x, y) fmt.Println("somma:", somma, "prodotto:", prod) // Semplice output. imparaTipi() // < y minuti, devi imparare ancora! } /* <- commento su righe multiple Le funzioni possono avere parametri e restituire (molteplici!) valori. In questo esempio, x e y sono gli argomenti, mentre somma e prod sono i valori restituiti. Da notare il fatto che x e somma vengono dichiarati come interi. */ func imparaMoltepliciValoriRestituiti(x, y int) (somma, prod int) { return x + y, x * y // Restituisce due valori. } // Ecco alcuni tipi presenti in Go func imparaTipi() { // La dichiarazione rapida di solito fa il suo lavoro. str := "Impara il Go!" // Tipo stringa. s2 := `Una stringa letterale può includere andata a capo.` // Sempre di tipo stringa. // Stringa letterale non ASCII. I sorgenti Go sono in UTF-8. g := 'Σ' // Il tipo runa, alias per int32, è costituito da un code point unicode. f := 3.14159 // float64, un numero in virgola mobile a 64-bit (IEEE-754) c := 3 + 4i // complex128, rappresentato internamente con due float64. // Inizializzare le variabili con var. var u uint = 7 // Senza segno, ma la dimensione dipende dall'implementazione (come l'int) var pi float32 = 22. / 7 // Sintassi per la conversione. n := byte('\n') // Il tipo byte è un alias per uint8. // I vettori hanno dimensione fissa, stabilita durante la compilazione. var a4 [4]int // Un vettore di 4 interi, tutti inizializzati a 0. a3 := [...]int{3, 1, 5} // Un vettore inizializzato con una dimensione fissa pari a 3, i cui elementi sono 3, 1 e 5. // Gli slice hanno dimensione variabile. Vettori e slice hanno pro e contro, // ma generalmente si tende a usare più spesso gli slice. s3 := []int{4, 5, 9} // La differenza con a3 è che qua non ci sono i 3 punti all'interno delle parentesi quadre. s4 := make([]int, 4) // Alloca uno slice di 4 interi, tutti inizializzati a 0. var d2 [][]float64 // Semplice dichiarazione, non vengono fatte allocazioni. bs := []byte("uno slice") // Sintassi per la conversione. // Poiché gli slice sono dinamici, è possibile aggiungere elementi // quando è necessario. Per farlo, si usa la funzione append(). Il primo // argomento è lo slice a cui stiamo aggiungendo elementi. Di solito // lo slice viene aggiornato, senza fare una copia, come nell'esempio: s := []int{1, 2, 3} // Il risultato è uno slice di dimensione 3. s = append(s, 4, 5, 6) // Aggiunge 3 elementi: lo slice ha dimensione 6. fmt.Println(s) // Lo slice aggiornato è [1 2 3 4 5 6] // Per aggiungere un altro slice, invece che elencare gli elementi uno ad // uno, è possibile passare alla funzione append un riferimento ad uno // slice, oppure uno slice letterale: in questo caso si usano i tre punti, // dopo lo slice, a significare "prendi ciascun elemento dello slice": s = append(s, []int{7, 8, 9}...) // Il secondo argomento è uno slice letterale. fmt.Println(s) // Lo slice aggiornato è [1 2 3 4 5 6 7 8 9] p, q := imparaLaMemoria() // Dichiara due puntatori a intero: p e q. fmt.Println(*p, *q) // * dereferenzia un puntatore. Questo stampa due interi. // Una variabile di tipo map è un vettore associativo di dimensione variabile, // e funzionano come le tabelle di hash o i dizionari in altri linguaggi. m := map[string]int{"tre": 3, "quattro": 4} m["uno"] = 1 // Le variabili dichiarate e non usate sono un errore in Go. // L'underscore permette di "usare" una variabile, scartandone il valore. _, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs // Stampare a schermo ovviamente significa usare una variabile. fmt.Println(s, c, a4, s3, d2, m) imparaControlloDiFlusso() // Torniamo in carreggiata. } // In Go è possibile associare dei nomi ai valori restituiti da una funzione. // Assegnare un nome al tipo di dato restituito permette di fare return in vari // punti all'interno del corpo della funzione, ma anche di usare return senza // specificare in modo esplicito che cosa restituire. func imparaValoriRestituitiConNome(x, y int) (z int) { z = x * y return // z è implicito, perchè compare nella definizione di funzione. } // Go è dotato di garbage collection. Ha i puntatori, ma non l'aritmetica dei // puntatori. Puoi commettere errori a causa di puntatori nulli, ma non puoi // incrementare un puntatore direttamente. func imparaLaMemoria() (p, q *int) { // I valori restituiti (con nome) p e q sono puntatori a int. p = new(int) // La funzione new si occupa di allocare memoria. // L'int allocato viene inizializzato a 0, dunque p non è più nil. s := make([]int, 20) // Alloca 20 int come un singolo blocco di memoria. s[3] = 7 // Ne assegna uno. r := -2 // Dichiara un'altra variabile locale return &s[3], &r // & "prende" l'indirizzo di un oggetto. } func calcoloCostoso() float64 { return m.Exp(10) } func imparaControlloDiFlusso() { // L'istruzione if richiede parentesi graffe per il corpo, mentre non ha // bisogno di parentesi tonde per la condizione. if true { fmt.Println("te l'ho detto") } // Eseguendo "go fmt" da riga di comando, il codice viene formattato // in maniera standard. if false { // :( } else { // :D } // L'istruzione switch serve ad evitare tanti if messi in cascata. x := 42.0 switch x { case 0: case 1: case 42: // Quando è soddisfatta la condizione all'interno di un case, il // programma esce dal switch senza che siano specificate istruzioni // di tipo "break". In Go infatti di default non è presente il // cosiddetto "fall through" all'interno dell'istruzione switch. // Tuttavia, il linguaggio mette a disposizione la parola chiave // fallthrough per permettere, in casi particolari, questo comportamento. case 43: // Non si arriva qua. default: // Il caso di default è opzionale. } // Come l'if, anche il for non usa parentesi tonde per la condizione. // Le variabili dichiarate all'interno di if/for sono locali al loro scope. for x := 0; x < 3; x++ { // ++ è un'istruzione! fmt.Println("ciclo numero", x) } // x == 42 qua. // Il for è l'unica istruzione per i loop in Go, ma ha varie forme. for { // Ciclo infinito. break // Scherzavo. continue // Non si arriva qua. } // Puoi usare range per iterare lungo un vettore, slice, stringa, mappa o canale. // range restituisce uno (per i canali) o due valori (vettore, slice, stringa, mappa). for chiave, valore := range map[string]int{"uno": 1, "due": 2, "tre": 3} { // per ogni coppia dentro la mappa, stampa chiave e valore fmt.Printf("chiave=%s, valore=%d\n", chiave, valore) } // Come nel for, := dentro la condizione dell'if è usato per dichiarare // e assegnare y, poi testare se y > x. if y := calcoloCostoso(); y > x { x = y } // Le funzioni letterali sono closure. xGrande := func() bool { return x > 10000 // Si riferisce a x dichiarata sopra al switch (vedi sopra). } fmt.Println("xGrande:", xGrande()) // true (abbiamo assegnato e^10 a x). x = 1.3e3 // Adesso x == 1300 fmt.Println("xGrande:", xGrande()) // false ora. // Inoltre le funzioni letterali possono essere definite e chiamate // inline, col ruolo di parametri di funzione, a patto che: // a) la funzione letterale venga chiamata subito (), // b) il valore restituito è in accordo con il tipo dell'argomento. fmt.Println("Somma e raddoppia due numeri: ", func(a, b int) int { return (a + b) * 2 }(10, 2)) // Chiamata con argomenti 10 e 2 // => Somma e raddoppia due numeri: 24 // Quando ti servirà, lo amerai. goto amore amore: imparaFabbricaDiFunzioni() // Una funzione che restituisce un'altra funzione è divertente! imparaDefer() // Un tour veloce di una parola chiave importante. imparaInterfacce() // Arriva la roba buona! } func imparaFabbricaDiFunzioni() { // Questi due blocchi di istruzioni sono equivalenti, ma il secondo è più semplice da capire. fmt.Println(fabbricaDiFrasi("estate")("Una bella giornata", "giornata!")) d := fabbricaDiFrasi("estate") fmt.Println(d("Una bella", "giornata!")) fmt.Println(d("Un pigro", "pomeriggio!")) } // I decoratori sono comuni in alcuni linguaggi. Si può fare lo stesso in Go // con le funzioni letterali che accettano argomenti. func fabbricaDiFrasi(miaStringa string) func(prima, dopo string) string { return func(prima, dopo string) string { return fmt.Sprintf("%s %s %s", prima, miaStringa, dopo) // Nuova stringa } } func imparaDefer() (ok bool) { // La parola chiave "defer" inserisce una funzione in una lista. // La lista contenente tutte le chiamate a funzione viene eseguita DOPO // il return finale della funzione che le circonda. defer fmt.Println("le istruzioni 'deferred' sono eseguite in ordine inverso (LIFO).") defer fmt.Println("\nQuesta riga viene stampata per prima perché") // defer viene usato di solito per chiudere un file, così la funzione che // chiude il file, preceduta da "defer", viene messa vicino a quella che lo apre. return true } // Definisce Stringer come un'interfaccia con un metodo, String. type Stringer interface { String() string } // Definisce coppia come una struct con due campi interi, chiamati x e y. type coppia struct { x, y int } // Definisce un metodo sul tipo coppia, che adesso implementa Stringer. func (p coppia) String() string { // p viene definito "ricevente" // Sprintf è un'altra funzione del package ftm. // La notazione con il punto serve per richiamare i campi di p. return fmt.Sprintf("(%d, %d)", p.x, p.y) } func imparaInterfacce() { // Brace syntax is a "struct literal". It evaluates to an initialized // struct. The := syntax declares and initializes p to this struct. // Le parentesi graffe sono usate per le cosiddette "struct letterali". // Con :=, p viene dichiarata e inizializzata a questa struct. p := coppia{3, 4} fmt.Println(p.String()) // Chiama il metodo String di p, che è di tipo coppia. var i Stringer // Dichiara i come interfaccia Stringer. i = p // Valido perchè coppia implementa Stringer. // Chiama il metodo String di i, che è di tipo Stringer. Output uguale a sopra. fmt.Println(i.String()) // Functions in the fmt package call the String method to ask an object // for a printable representation of itself. // Le funzioni dentro al package fmt chiamano il metodo String per // chiedere ad un oggetto una rappresentazione in stringhe di sé stesso. fmt.Println(p) // Output uguale a sopra. Println chiama il metodo String. fmt.Println(i) // Output uguale a sopra. imparaParametriVariadici("grande", "imparando", "qua!") } // Le funzioni possono avere parametri variadici (ovvero di lunghezza variabile). func imparaParametriVariadici(mieStringhe ...interface{}) { // Cicla su ogni valore variadico. // L'underscore serve a ignorare l'indice del vettore. for _, param := range mieStringhe { fmt.Println("parametro:", param) } // Passa un valore variadico come parametro variadico. fmt.Println("parametri:", fmt.Sprintln(mieStringhe...)) imparaGestioneErrori() } func imparaGestioneErrori() { // La sintassi ", ok" è usata per indicare se qualcosa ha funzionato o no. m := map[int]string{3: "tre", 4: "quattro"} if x, ok := m[1]; !ok { // ok sarà false perchè 1 non è dentro la mappa. fmt.Println("qua non c'è nessuno!") } else { fmt.Print(x) // x sarebbe il valore che corrisponde alla chiave 1, se fosse nella mappa. } // Un errore non riporta soltanto "ok" ma è più specifico riguardo al problema. if _, err := strconv.Atoi("non_intero"); err != nil { // _ scarta il valore // stampa 'strconv.ParseInt: parsing "non_intero": invalid syntax' fmt.Println(err) } // Approfondiremo le interfacce un'altra volta. Nel frattempo, imparaConcorrenza() } // c è un canale, un oggetto per comunicare in modo concorrente e sicuro. func inc(i int, c chan int) { c <- i + 1 // <- è l'operatore di "invio" quando un canale sta a sinistra. } // Useremo inc per incrementare alcuni numeri in modo concorrente. func imparaConcorrenza() { // Stessa funzione usata prima per creare uno slice. Make alloca e // inizializza slice, mappe e canali. c := make(chan int) // Lancia tre goroutine. I numeri saranno incrementati in modo concorrente, // forse in parallelo se la macchina lo supporta. Tutti e tre inviano dati // sullo stesso canale. go inc(0, c) // go è un'istruzione che avvia una goroutine. go inc(10, c) go inc(-805, c) // Legge tre risultati dal canale e li stampa a schermo. // Non si conosce a priori l'ordine in cui i risultati arriveranno! fmt.Println(<-c, <-c, <-c) // <- è l'operatore di "ricevuta" quando // un canale sta a destra. cs := make(chan string) // Un altro canale, gestisce le stringhe. ccs := make(chan chan string) // Un canale che gestisce canali di stringhe. go func() { c <- 84 }() // Lancia una goroutine, solo per inviare un valore. go func() { cs <- "parolina" }() // Stessa cosa ma per cs. // select è simile a switch, ma ogni case riguarda un'operazione su un // canale. Seleziona, in modo random, uno tra i canali che sono pronti // a comunicare. select { case i := <-c: // Il valore ricevuto può essere assegnato a una variabile, fmt.Printf("E' un %T", i) case <-cs: // oppure il valore ricevuto può essere scartato. fmt.Println("E' una stringa.") case <-ccs: // Canale vuoto, non pronto per comunicare. fmt.Println("Non succede niente.") } // A questo punto un valore è stato preso da c o cs. Una delle tue goroutine // cominciate sopra ha completato l'esecuzione, l'altra rimarrà bloccata. imparaProgrammazioneWeb() // Se lo fa Go, lo puoi fare anche tu. } // Una funzione all'interno del package http avvia un webserver. func imparaProgrammazioneWeb() { // Il primo parametro di ListenAndServe è l'indirizzo TCP su cui ascoltare. // Il secondo parametro è un'interfaccia, precisamente http.Handler. go func() { err := http.ListenAndServe(":8080", coppia{}) fmt.Println(err) // Non ignorare gli errori. }() richiediServer() } // Per rendere coppia un http.Handler basta implementare il metodo ServeHTTP. func (p coppia) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Il server fornisce dati con un metodo di http.ResponseWriter. w.Write([]byte("Hai imparato Go in Y minuti!")) } func richiediServer() { risposta, err := http.Get("http://localhost:8080") fmt.Println(err) defer risposta.Body.Close() corpo, err := ioutil.ReadAll(risposta.Body) fmt.Printf("\nIl webserver dice: `%s`", string(corpo)) } ``` ## Letture consigliate La risorsa più importante per imparare il Go è il [sito ufficiale di Go](https://go.dev/). Qui puoi seguire i tutorial, scrivere codice in modo interattivo, e leggere tutti i dettagli. Oltre al tour, [la documentazione](https://go.dev/doc/) contiene informazioni su come scrivere ottimo codice in Go, documentazione sui package e sui comandi, e la cronologia delle release. Anche il documento che definisce il linguaggio è un'ottima lettura. E' semplice da leggere e incredibilmente corto (rispetto ad altri documenti riguardanti la creazione di linguaggi). Puoi giocare con il codice visto finora nel [Go playground](https://go.dev/play/p/Am120Xe7qf). Prova a cambiarlo e ad eseguirlo dal browser! Osserva che puoi usare [https://go.dev/play/](https://go.dev/play/) come una [REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop) per scrivere codice all'interno del browser, senza neanche installare Go! Una lettura importante per capire Go in modo più profondo è il [codice sorgente della libreria standard](https://go.dev/src/). Infatti è molto ben documentato e costituisce quanto più chiaro e conciso ci sia riguardo gli idiomi e le buone pratiche del Go. Inoltre, clickando sul nome di una funzione [nella documentazione](https://go.dev/pkg/) compare il relativo codice sorgente! Un'altra ottima risorsa per imparare è [Go by example](https://gobyexample.com/). Go Mobile aggiunge il supporto per lo sviluppo mobile (Android e iOS). In questo modo è possibile scrivere un'app mobile nativa in Go, oppure una libreria che contiene binding da un package scritto in Go, e che può essere richiamata da Java(Android) e Objective-C(iOS). Visita la pagina di [Go Mobile](https://go.dev/wiki/Mobile) per maggiori informazioni. ================================================ FILE: it/html.md ================================================ --- contributors: - ["Christophe THOMAS", "https://github.com/WinChris"] translators: - ["Ale46", "http://github.com/Ale46/"] --- HTML sta per HyperText Markup Language (linguaggio a marcatori per ipertesti). È un linguaggio che consente di scrivere pagine web per il world wide web. È un linguaggio di markup, che permette di scrivere pagine web usando del codice che indica come il testo ed i dati devono essere mostrati. Infatti, i files html sono semplici file di testo. Cos'è il markup? È un metodo per organizzare i dati della pagina circondandoli con tag di apertura e tag di chiusura. Questo markup serve a dare significato al testo che racchiude. Come altri linguaggi di programmazione, HTML ha molte versioni. Qui discuteremo di HTML5. **NOTA :** Puoi testare i differenti tags ed elementi man mano che prosegui nel tutorial in un sito come [codepen](http://codepen.io/pen/) per vedere i loro effetti, capire come lavorano e familiarizzare con il linguaggio. Questo articolo riguarda principalmente la sintassi HTML ed alcuni suggerimenti utili. ```html Il mio sito

Ciao, mondo!

Vieni a vedere ciò che mostra

Questo è un paragrafo.

Questo è un altro paragrafo.

  • Questo è un elemento di un elenco non numerato (elenco puntato)
  • Questo è un altro elemento
  • E questo è l'ultimo elemento dell'elenco
Il mio sito

Ciao, mondo!

Vieni a vedere ciò che mostra

Questo è un paragrafo.

Questo è un altro paragrafo.

  • Questo è un elemento in un elenco non elencato (elenco puntato)
  • Questo è un altro elemento
  • E questo è l'ultimo elemento dell'elenco
Prima intestazione Seconda intestazione
prima riga, prima colonna prima riga, seconda colonna
seconda riga, prima colonna seconda riga, seconda colonna
``` ## Uso HTML è scritto in files che finiscono con `.html` o `.htm`. Il "MIME type" è `text/html`. ## Per saperne di più * [wikipedia](https://it.wikipedia.org/wiki/HTML) * [HTML tutorial](https://developer.mozilla.org/it/docs/Web/HTML) * [W3School](http://www.w3schools.com/html/html_intro.asp) ================================================ FILE: it/java.md ================================================ --- contributors: - ["Jake Prather", "http://github.com/JakeHP"] - ["Madison Dickson", "http://github.com/mix3d"] translators: - ["Ivan Sala","http://github.com/slavni96"] - ["Tommaso Pifferi","http://github.com/neslinesli93"] --- Java è un linguaggio di programmazione orientato ad oggetti, concorrente, basato su classi e adatto a svariati scopi. [Per saperne di più](http://docs.oracle.com/javase/tutorial/java/index.html) ```java // I commenti su singola linea incominciano con // /* I commenti su più linee invece sono così */ /** I commenti per la documentazione JavaDoc si fanno così. Vengono usati per descrivere una classe o alcuni suoi attributi. */ // Per importare la classe ArrayList contenuta nel package java.util import java.util.ArrayList; // Per importare tutte le classi contenute nel package java.security import java.security.*; // Ogni file .java contiene una classe pubblica, con lo stesso nome del file public class LearnJava { // Un programma deve avere un metodo main come punto di partenza. // Tuttavia si possono creare anche file senza main, che però // per essere usati devono essere richiamati da altri file. public static void main (String[] args) { // Per stampare a schermo si usa System.out.println System.out.println("Ciao Mondo!"); System.out.println( "Intero [integer]: " + 10 + " Reale [double]: " + 3.14 + " Booleano [boolean]: " + true); // Se non si vuole andare a capo, si puo' usare System.out.print System.out.print("Ciao "); System.out.print("Mondo "); // Per stampare del testo formattato, si può usare System.out.printf System.out.printf("pi greco = %.5f", Math.PI); // => pi greco = 3.14159 /////////////////////////////////////// // Variabili /////////////////////////////////////// /* * Dichiarazione delle Variabili */ // Per dichiarare una variabile basta fare int fooInt; // Per dichiarare più di una variabile dello lo stesso tipo si usa: // , , int fooInt1, fooInt2, fooInt3; /* * Inizializzazione delle Variabili */ // Per inizializzare una variabile si usa // = int fooInt = 1; // Per inizializzare più di una variabile dello lo stesso tipo // si usa , , = int fooInt1, fooInt2, fooInt3; fooInt1 = fooInt2 = fooInt3 = 1; /* * Tipi di Variabili */ // Byte - intero con segno a 8 bit (in complemento a 2) // (-128 <= byte <= 127) byte fooByte = 100; // Short - intero con segno a 16 bit (in complemento a 2) // (-32,768 <= short <= 32,767) short fooShort = 10000; // Integer - intero con segno a 32 bit (in complemento a 2) // (-2,147,483,648 <= int <= 2,147,483,647) int fooInt = 1; // Long - intero con segno a 64 bit (in complemento a 2) // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) long fooLong = 100000L; // L viene usato per indicare che il valore è di tipo Long; // altrimenti il valore viene considerato come intero. // Nota: Java non dispone di interi senza segno. // Float - Numero in virgola mobile a 32 bit con precisione singola (IEEE 754) // 2^-149 <= float <= (2-2^-23) * 2^127 float fooFloat = 234.5f; // f o F indicano the la variabile è di tipo float; // altrimenti il valore viene considerato come double. // Double - Numero in virgola mobile a 64 bit con precisione doppia (IEEE 754) // 2^-1074 <= x <= (2-2^-52) * 2^1023 double fooDouble = 123.4; // Boolean - Può assumere il valore vero (true) o falso (false) boolean fooBoolean = true; boolean barBoolean = false; // Char - Un singolo carattere Unicode a 16-bit char fooChar = 'A'; // Le variabili precedute da final possono essere inizializzate una volta sola, final int HOURS_I_WORK_PER_WEEK = 9001; // però è possibile dichiararle e poi inizializzarle in un secondo momento. final double E; E = 2.71828; // BigInteger - Interi a precisione arbitraria // // BigInteger è un tipo di dato che permette ai programmatori di // gestire interi più grandi di 64 bit. Internamente, le variabili // di tipo BigInteger vengono memorizzate come un vettore di byte e // vengono manipolate usando funzioni dentro la classe BigInteger. // // Una variabile di tipo BigInteger può essere inizializzata usando // un array di byte oppure una stringa. BigInteger fooBigInteger = new BigDecimal(fooByteArray); // BigDecimal - Numero con segno, immutabile, a precisione arbitraria // // Una variabile di tipo BigDecimal è composta da due parti: un intero // a precisione arbitraria detto 'non scalato', e un intero a 32 bit // che rappresenta la 'scala', ovvero la potenza di 10 con cui // moltiplicare l'intero non scalato. // // I BigDecimal permettono un controllo completo sull'arrotondamento // dei numeri. Essi sono molto usati in ambito finanziario, nella // gestione delle valute, e in ogni altro posto in cui serve // precisione esatta. // // Le variabili di tipo BigDecimal possono essere inizializzate con un // int, long, double o String, oppure con un intero non scalato // (di tipo BigInteger) e una scala (int). BigDecimal fooBigDecimal = new BigDecimal(fooBigInteger, fooInt); // Stringhe String fooString = "Questa e' la mia stringa!"; // \n è un carattere di escape che rappresenta l'andare a capo String barString = "Stampare su una nuova riga?\nNessun problema!"; // \t è un carattere di escape che aggiunge un tab String bazString = "Vuoi aggiungere un tab?\tNessun problema!"; System.out.println(fooString); System.out.println(barString); System.out.println(bazString); // Vettori // La dimensione di un array deve essere decisa in fase di // istanziazione. Per dichiarare un array si può fare in due modi: // [] = new []; // [] = new []; int[] intArray = new int[10]; String[] stringArray = new String[1]; boolean boolArray[] = new boolean[100]; // Un altro modo per dichiarare ed insieme inizializzare un vettore. int[] y = {9000, 1000, 1337}; String names[] = {"Gianni", "Anna", "Luca", "Cristina"}; boolean bools[] = new boolean[] {true, false, false}; // Per accedere ad un elemento di un vettore System.out.println("intArray @ 0: " + intArray[0]); // I vettori non sono immutabili (ma la loro dimensione si!) // e gli indici partono da 0. intArray[1] = 1; System.out.println("intArray @ 1: " + intArray[1]); // => 1 // Ci sono altri tipo di dato interessanti. // ArrayList - Simili ai vettori, però offrono altre funzionalità, // e la loro dimensione può essere modificata. // LinkedList - Si tratta di una lista linkata doppia, e come tale // implementa tutte le operazioni del caso. // Map - Un insieme di oggetti che fa corrispondere delle chiavi // a dei valori. Non permette l'inserimento di chiavi uguali. // HashMap - Questa classe usa una tabella di hash per implementare // l'interfaccia di tipo Map. Questo permette di effettuare // operazioni basilari, come inserimento e cancellazione, // in tempo costante anche su insiemi molto grandi. /////////////////////////////////////// // Operatori /////////////////////////////////////// System.out.println("\n->Operatori"); int i1 = 1, i2 = 2; // Dichiarazone multipla in contemporanea // L'aritmetica è lineare. System.out.println("1+2 = " + (i1 + i2)); // => 3 System.out.println("2-1 = " + (i2 - i1)); // => 1 System.out.println("2*1 = " + (i2 * i1)); // => 2 System.out.println("1/2 = " + (i1 / i2)); // => 0 // (con 0.5 arrotonda per difetto) // Modulo System.out.println("11%3 = "+(11 % 3)); // => 2 // Operatori di confronto System.out.println("3 == 2? " + (3 == 2)); // => falso System.out.println("3 != 2? " + (3 != 2)); // => vero System.out.println("3 > 2? " + (3 > 2)); // => vero System.out.println("3 < 2? " + (3 < 2)); // => falso System.out.println("2 <= 2? " + (2 <= 2)); // => vero System.out.println("2 >= 2? " + (2 >= 2)); // => vero // Operatori binari orientati ai bit // effettuano le operazioni logiche confrontando, i bit degli operandi: /* ~ complemento << shift sinistro con segno >> shift destro con segno >>> shift destro senza segno & AND Binario Bitwise AND ^ OR Esclusivo | OR Incusivo */ // Incrementare e Decrementare int i = 0; System.out.println("\n->Incrementare/Decrementare"); // Gli operatori ++ e -- incrementano e decrementano rispettivamente di 1. // Se posizionati prima della variabile, incrementano, quindi riportano. // Se si trovano dopo la variabile, riporano, e quindi incrementano. System.out.println(i++); //i = 1, Stampa 0 (post-incremento) System.out.println(++i); //i = 2, Stampa 2 (pre-incremento) System.out.println(i--); //i = 1, Stampa 2 (post-decremento) System.out.println(--i); //i = 0, Stampa 0 (pre-decremento) /////////////////////////////////////// // Strutture di controllo /////////////////////////////////////// System.out.println("\n->Strutture di controllo"); // La dichiarazione dell'If è C-like. int j = 10; if (j == 10){ System.out.println("Io vengo stampato"); } else if (j > 10) { System.out.println("Io no"); } else { System.out.println("E io neppure"); } // Struttura While int fooWhile = 0; while(fooWhile < 100) { //System.out.println(fooWhile); //Incrementa il contatore //Si ripete per 100 volte, fooWhile 0,1,2...99 fooWhile++; } System.out.println("Valore di fooWhile: " + fooWhile); // Struttura Do While int fooDoWhile = 0; do { //System.out.println(fooDoWhile); //Incrementa il contaore //Si repete per 99 volte, fooDoWhile 0->99 fooDoWhile++; }while(fooDoWhile < 100); System.out.println("Valore di fooWhile: " + fooDoWhile); // Struttura For int fooFor; //Struttura For => for(; ; ) for(fooFor=0; fooFor<10; fooFor++){ //System.out.println(fooFor); //Itera 10 volte, fooFor 0->9 } System.out.println("Valore di fooFor: " + fooFor); // Struttura For Each // Una iterazione automatica attraverso un array o una lista di oggetti int[] fooList = {1,2,3,4,5,6,7,8,9}; //struttura for each => for( : ) //si legge: per ogni oggetto dell'array fai... //Nota: il tipo dell'oggetto deve essere uguale a quello dell'array for( int bar : fooList ){ //System.out.println(bar); //Itera 9 volte e stampa 1-9 andando a capo. } // Struttura Switch Case // La struttura switch lavora con byte, short, char e int. // Se funziona con i char funzionera ovviamente anche con le stringhe. int mese = 3; String stringaMese; switch (mese){ case 1: stringaMese = "Genneio"; break; case 2: stringaMese = "Febbraio"; break; case 3: stringaMese = "Marzo"; break; default: stringaMese = "Altri mesi"; break; } System.out.println("Risultato del costrutto switch: " + stringaMese); // Condizioni brevi // Si può usare l'operatore '?' per un rapido assegnamento // o per operazioni logiche. // Si legge: // Se (condizione) è vera, usa , altrimenti usa int foo = 5; String bar = (foo < 10) ? "A" : "B"; System.out.println("Se la condizione e' vera stampa A: "+bar); // Stampa A, perché la condizione è vera. ///////////////////////////////////////// // Convertire i tipi di dati e Typecasting ///////////////////////////////////////// // Convertire tipi di dati // Stringhe ad interi Integer.parseInt("123");//Riporta una versione intera di "123" // Interi a Stringhe Integer.toString(123);//Riporta la stringa "123" // Per altre conversioni guarda le seguenti classi // Double // Long // String // Typecasting // Vi sono molti dettagli che non si possono spiegare qui, // java dispone di una ottima documentazione // Sentiti libero di leggerla // http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html /////////////////////////////////////// // Classi e funzioni /////////////////////////////////////// System.out.println("\n->Classi & Funzioni"); // (Di seguito la definizione della classe Bicicletta) // Instanziare una nuova classe Bicicletta percorso = new Bicicletta(); // Chiamare metodi percorso.accellera(3); // Si usano sempre metodi set... get... percorso.setCadenza(100); // toString riporta la rappresenzazione dell'oggetto // come se fosse una stringa System.out.println("percorso info: " + percorso.toString()); } // Fine metodo main } // Fine classe LearnJava // Si possono inculdere altre anche delle classi non pubbliche (private) // oltre a quella pubblica principale, in un file .java // Sintassi per dichiarare una classe: // class { // //dati, variabili, costruttori, funzioni, tutto qua. // //le funzioni sono chiamate come i metodi. // } class Bicicletta { // Variabili della bicicletta public int cadenza; // Public: Può essere richiamato da qualsiasi classe private int velocita; // Private: è accessibile solo dalla classe dove è stato inizializzato protected int ingranaggi; // Protected: è visto sia dalla classe che dalle sottoclassi String nome; // default: è accessibile sono all'interno dello stesso package // I costruttori vengono usati per creare variabili // Questo è un costruttore public Bicicletta() { ingranaggi = 1; cadenza = 50; velocita = 5; nome = "Bontrager"; } // Questo è un costruttore che richiede parametri public Bicicletta(int cadenza, int velocita, int ingranaggi, String nome) { this.ingranaggi = ingranaggi; this.cadenza = cadenza; this.velocita = velocita; this.nome = nome; } // Sintassi delle funzioni: // () // Le classi in java spesso implementano delle funzioni o metodo // 'get...' o 'set...' // Dichiarazione di un metodo // () public int getCandenza() { return cadenza; } // i medodi (void) non necessitano di riportare un valore public void setCadenza(int nuovoValore) { cadenza = nuovoValore; } public void setIngranaggi(int nuovoValore) { ingranaggi = nuovoValore; } public void accellera(int incrementa) { velocita += incrementa; } public void decellera(int decrementa) { velocita -= decrementa; } public void setNome(String nuovoNome) { nome = nuovoNome; } public String getNome() { return nome; } //Medoto per visualizzare gli attributi dell'oggetto @Override public String toString() { return "Ingranaggi: " + ingranaggi + " Cadenza: " + cadenza + " Velocita: " + velocita + " Nome: " + nome; } } // Fine classe bicicletta // PennyFarthing è una sottoclasse della bicicletta class PennyFarthing extends Bicicletta { // (Sono quelle biciclette con un unica ruota enorme // Non hanno ingranaggi.) public PennyFarthing(int cadenzaIniziale, int velocitaIniziale){ // Richiamo il costruttore del padre con super super(cadenzaIniziale, velocitaIniziale, 0, "PennyFarthing"); } // Bisogna contrassegnre un medodo che si sta riscrivendo // con una @annotazione // Per saperne di più sulle annotazioni // Vedi la guida: http://docs.oracle.com/javase/tutorial/java/annotations/ @Override public void setIngranaggi(int ingranaggi) { ingranaggi = 0; } } /* //Interfacce //Sintassi per dichiarare una interfaccia // interface extends { // //Costanti // //Dichiarazioni dei metodi //} //Esempi- Cibo: interface Commestibile { public void mangia(); //Ogni classe che implementa questa interfaccia //deve implementare questo metodo. } interface Digeribile { public void digerisci(); } //Possiamo quindi creare una classe che implementa entrambe le interfaccie class Frutta implements Commestibile, Digestibile { public void mangia() { //... } public void digerisci() { //... } } //In Java si può estendere solo una classe, ma si possono implementare //più interfaccie, per esempio: class ClasseEsempio extends AltraClasse implements PrimaInterfaccia, SecondaInterfaccia { public void MetodoPrimaInterfaccia() { } public void MetodoSecondaInterfaccia() { } } */ ``` ## Letture future I link di seguito sono solo per capire l'argomento, cerca pure su Google degli esempi specifici **Guida ufficiale di Oracle [solo in inglese]**: * [Java Tutorial Trail from Sun / Oracle](http://docs.oracle.com/javase/tutorial/index.html) * [Java Access level modifiers](http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html) * [Object-Oriented Programming Concepts](http://docs.oracle.com/javase/tutorial/java/concepts/index.html): * [Inheritance](http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html) * [Polymorphism](http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html) * [Abstraction](http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html) * [Exceptions](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) * [Interfaces](http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html) * [Generics](http://docs.oracle.com/javase/tutorial/java/generics/index.html) * [Java Code Conventions](http://www.oracle.com/technetwork/java/codeconv-138413.html) **Tutorial Online [in inglese]** * [Codingbat.com](http://codingbat.com/java) * [Codewars - Java Katas](https://www.codewars.com/?language=java) * [University of Helsinki - Object-Oriented programming with Java](http://moocfi.github.io/courses/2013/programming-part-1/) **Libri [in italiano]** : * [Java la guida completa](http://www.amazon.it/Java-guida-completa-Herbert-Schildt/dp/8838667667/ref=sr_1_1?ie=UTF8&qid=1393422296&sr=8-1&keywords=java) * [Thinking in Java](http://www.amazon.it/Thinking-Java-1-Bruce-Eckel/dp/8871923030/ref=sr_1_8?ie=UTF8&qid=1393422296&sr=8-8&keywords=java) * [Manuale di Java 7](http://www.amazon.com/gp/product/0071606300) ================================================ FILE: it/javascript.md ================================================ --- contributors: - ["Leigh Brenecki", "https://leigh.net.au"] - ["Ariel Krakowski", "http://www.learneroo.com"] translators: - ["vinniec", "https://github.com/vinniec"] --- JavaScript è stato creato da Netscape di Brendan Eich nel 1995. È stato originariamente pensato come un semplice linguaggio di scripting per i siti web, complementare all'uso di java per applicazioni più complesse ma la sua stretta integrazione con le pagine Web e il supporto integrato con esse ha causato il suo divenire più comune di Java per i frontend web. Tuttavia JavaScript non è semplicemente limitato ai web browser: Node.js è un progetto che fornisce una runtime standalone dell'engine JavaScript V8 per Google Chrome, sta diventando sempre più popolare. JavaScript ha una sintassi C-like, quindi se usate linguaggi come C o Java, molta della sintassi di base sarà già familiare. A dispetto di questo, e a dispetto del nome similare, il modello a oggetti di JavaScript è significativamente diverso da quello di Java. ```js // I commenti a singola linea iniziano con due slash. /* I commenti multilinea cominciano con uno slash e un asterisco, e terminano con un asterisco e uno slash */ // Le istruzioni possono essere terminate con ; doStuff(); // ... ma non devono esserci per forza, i punti e virgola vengono automaticamente inseriti // dove c'è un newline, ad eccezione di alcuni casi. doStuff() // Poiché questi casi possono causare risultati inaspettati, noi continueremo ad usare // i punti e virgola in questa guida. /////////////////////////////////// // 1. Numeri, Stringe e Operatori // JavaScript ha un tipo numero (che è a 64-bit IEEE 754 double). // Double ha una mantissa di 52-bit che è abbastanza per memorizzare interi // fino a 9x10¹⁵ per essere precisi. 3; // = 3 1.5; // = 1.5 // Alcuni lavori aritmetici di base come ci si può aspettare. 1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 // inclusa la divisione con la virgola. 5 / 2; // = 2.5 // E il modulo. 10 % 2; // = 0 30 % 4; // = 2 18.5 % 7; // = 4.5 // Anche le operazioni binarie funzionano; quando effettuate una operazione binaria il vostro numero decimale // è convertito in un intero con segno *fino a* 32 bit.. 1 << 2; // = 4 // Le precedenza è subordinata dalle parentesi. (1 + 3) * 2; // = 8 // Ci sono tre valori speciali che non sono numeri reali: Infinity; // ad esempio il risultato di 1/0 -Infinity; // ad esempio il risultato di -1/0 NaN; // ad esempio il risultato di 0/0, sta per 'Not a Number' // Ci sono anche i tipi booleani. true; false; // Le stringe sono create con ' oppure ". 'abc'; "Hello, world"; // La negazione usa il ! simbolo !true; // = false !false; // = true // L'uguaglianza è === 1 === 1; // = true 2 === 1; // = false // L'inuguaglianza è !== 1 !== 1; // = false 2 !== 1; // = true // Altre comparazioni 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true // Le stringhe si concatenano con il + "Hello " + "world!"; // = "Hello world!" // ... che funziona con qualcosa in più delle semplici stringhe "1, 2, " + 3; // = "1, 2, 3" "Hello " + ["world", "!"]; // = "Hello world,!" // e sono comparate con < e > "a" < "b"; // = true // La comparazione con conversione implicita si fa con il doppio uguale... "5" == 5; // = true null == undefined; // = true // ...ammenoché non si usi === "5" === 5; // = false null === undefined; // = false // ...che può provocare strani comportamenti... 13 + !0; // 14 "13" + !0; // '13true' // Si può accedere ai caratteri di una stringa con `charAt` "This is a string".charAt(0); // = 'T' // ...o usando le `substring` per ottenere una parte. "Hello world".substring(0, 5); // = "Hello" // `length` è una proprietà, quindi non usate le (). "Hello".length; // = 5 // Ci sono anche `null` e `undefined`. null; // usato per indicato deliberatamente un non-valore undefined; // usato per indicare un valore che attualmente non è presente (sebbene // `undefined` sia un valore a sua stessa volta) // false, null, undefined, NaN, 0 e "" sono falsi; tutto il resto è vero. // Notare che 0 è falso e "0" è vero, nonostante 0 == "0". /////////////////////////////////// // 2. Variabili, Array e Oggetti // Le variabili sono dichiarate con la parola chiave `var`. JavaScript è tipato // dinamicamente, quindi non serve specificare il tipo. L'assegnamento usa un carattere `=` // singolo. var someVar = 5; // Se si toglie la parola chiave var non si otterrà un errore... someOtherVar = 10; // ...ma la tua variabile sarà creata con visibilità globale e non // nel blocco dove la si è definita. // Le variabili dichiarate senza essere definite vengono impostate come undefined. var someThirdVar; // = undefined // Se si vuole dichiarare una coppia di variabili, lo si può fare usando una virgola // come separatore var someFourthVar = 2, someFifthVar = 4; // C'è una scorciatoia per effettuare operazioni matematiche sulle variabili: someVar += 5; // equivalente di someVar = someVar + 5; someVar vale 10 ora someVar *= 10; // ora someVar è 100 // e un ulteriore scorciatoia per aggiungere o sottrarre 1 someVar++; // ora someVar è 101 someVar--; // di nuovo 100 // Gli array sono liste ordinati di valori, di qualsiasi tipo. var myArray = ["Hello", 45, true]; // Si può accedere ai loro membri usando la sintassi sottoscritta con le parentesi quadra. // Gli indici degli array iniziano a zero. myArray[1]; // = 45 // Gli Array sono mutabili e di dimensione variabile. myArray.push("World"); myArray.length; // = 4 // Aggiungere/Modificare in un indice preciso myArray[3] = "Hello"; // Aggiungere e rimovere un elemento dall'inizio o dalla fine di un array myArray.unshift(3); // Aggiungere come primo elemento someVar = myArray.shift(); // Rimuovere il primo elemento e restituirlo myArray.push(3); // Aggiungere come ultimo elemento someVar = myArray.pop(); // Rimuovere l'ultimo elemento e restituirlo // Unire tutti gli elementi di un array con un punto e virgola var myArray0 = [32,false,"js",12,56,90]; myArray0.join(";") // = "32;false;js;12;56;90" // Ottenere un subarray di elementi dall'indice 1 (incluso) al 4 (escluso) myArray0.slice(1,4); // = [false,"js",12] // Rimuovere 4 elementi partendo dall'indice 2 e inserirci delle stringhe // "hi","wr" e "ld"; restituiscono i subarray rimossi myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] // myArray0 === [32,false,"hi","wr","ld"] // Gli oggetti di JavaScript sono equivalenti ai "dizionari" o "mappe" in altri // linguaggi: una collezione non ordinata di coppie di chiave-valore. var myObj = {key1: "Hello", key2: "World"}; // Le chiavi sono stringhe, ma non è necessario quotarle se sono identificatori // JavaScript validi. I valori possono essere di ogni tipo. var myObj = {myKey: "myValue", "my other key": 4}; // Gli attributi degli oggetti possono essere acceduti usando la sintassi "subscript", myObj["my other key"]; // = 4 // ... o usando la notazione puntata fornendo una chiave che sia un identificatore valido. myObj.myKey; // = "myValue" // Gli oggetti sono mutabilil; i valori possono essere cambiati e nuove chiavi possono essere aggiunte. myObj.myThirdKey = true; // se si prova ad accedere ad un valore che non è stato ancora impostato, si otterrà undefined. myObj.myFourthKey; // = undefined /////////////////////////////////// // 3. Strutture logiche e di controllo. // La struttura `if` funziona come ci si aspetta. var count = 1; if (count == 3){ // eseguito se count vale 3 } else if (count == 4){ // eseguito se count vale 4 } else { // eseguito se count non è né 3 e né 4 } // Così come il `while`. while (true){ // Un ciclo infinito! } // I cicli do-while sono come i cicli while ad eccezione che loro iterano almeno una volta. var input; do { input = getInput(); } while (!isValid(input)); // Il ciclo `for` è lo stesso di C e di Java: // inizializzazione, condizione di proseguimento; iterazione. for (var i = 0; i < 5; i++){ // verrà eseguito 5 volte } // Uscire forzatamente da un un ciclo etichettato è simile a java: outer: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; // esce fuori dal ciclo outer invece che solo da quello più interno } } } // L'istruzione for/in permette l'iterazione sulle proprietà di un oggetto. var description = ""; var person = {fname:"Paul", lname:"Ken", age:18}; for (var x in person){ description += person[x] + " "; } // description = 'Paul Ken 18 ' // L'istruzione for/of permette l'iterazione su oggetti iterabili (inclusi i built-in String, // Array, es. gli argomenti Array-like o gli oggetti NodeList, TypedArray, Map e Set, // e gli iterabili decisi dall'utente). var myPets = ""; var pets = ["cat", "dog", "hamster", "hedgehog"]; for (var pet of pets){ myPets += pet + " "; } // myPets = 'cat dog hamster hedgehog ' // && è la congiunzione logica, || è la disgiunione logica if (house.size == "big" && house.colour == "blue"){ house.contains = "bear"; } if (colour == "red" || colour == "blue"){ // i colori sono sia rossi che blu } // && e || "short circuit", utili per impostare i valori di default. var name = otherName || "default"; // L'istruzione `switch` controlla l'uguaglianza con `===`. // Usare 'break' dopo ogni caso // oppure i casi dopo quello corretto verranno eseguiti comunque. grade = 'B'; switch (grade) { case 'A': console.log("Great job"); break; case 'B': console.log("OK job"); break; case 'C': console.log("You can do better"); break; default: console.log("Oy vey"); break; } /////////////////////////////////// // 4. Funzioni, Visibilità e Closure // Le funzioni di JavaScript sono dichiarate con la parolachiave `function`. function myFunction(thing){ return thing.toUpperCase(); } myFunction("foo"); // = "FOO" // Nota che il valore da restituire deve iniziare nella stessa riga della // keyword `return`, altrimenti verrà sempre restituito `undefined` per via due to // dell'inserimento automatico dei punti e virgola. Fare attenzione a questo quando si usa lo stile Allman. function myFunction(){ return // <- punto e virgola automaticamente inserito qui {thisIsAn: 'object literal'}; } myFunction(); // = undefined // Le funzioni di JavaScript sono oggetti di prima classe, quindi possono essere riassegnate // a diversi nomi di variabili e passate ad altre funzioni come argomenti - per esempio, // mentre si fornisce un gestore di eventi: function myFunction(){ // questo codice sarà chiamato in 5 secondi } setTimeout(myFunction, 5000); // Nota: setTimeout non è parte del linguaggio JS, ma è fornito dai browser // e da Node.js. // Un altra funzione fornita dai browser è setInterval function myFunction(){ // questo codice verrà chiamato ogni 5 secondi } setInterval(myFunction, 5000); // Gli oggetti funzione non devono essere dichiarati con un nome - potete scrivere // la definizione di una funzione anonima direttamente come argomento di un'altra. setTimeout(function(){ // questo codice sarà chiamato in 5 secondi }, 5000); // In JavaScript le funzioni hanno una propria visibilità; le funzioni hanno // il loro scope ma gli altri blocchi no. if (true){ var i = 5; } i; // = 5 - non è undefined come ci si potrebbe aspettare in un linguaggio con una propria visibilità per blocco // Questo ha portato ad un pattern comune di "esecuzione immediata di funzioni // anonime", che previene alle variabili temporanee di finire nella // visibilità globale. (function(){ var temporary = 5; // Noi possiamo accedere alla visibilità globale assegnando all' "oggetto globale", che // in un browser web è sempre `windows`. L'oggetto globale potrebbe avere // nomi differenti in ambienti diverso dal browser come Node.js. window.permanent = 10; })(); temporary; // solleva ReferenceError permanent; // = 10 // Una delle più potenti caratteristiche di JavaScript sono le closure. Se una funzione è // definita dentro un'altra funzione, la funzione interna ha accesso a le variabili // della funzione esterna, anche dopo essere uscita dalla funzione esterna. function sayHelloInFiveSeconds(name){ var prompt = "Hello, " + name + "!"; // Le funzioni interne sono messe nella visibilità locale in modo predefinito, anche se vengono // dichiarate con `var`. function inner(){ alert(prompt); } setTimeout(inner, 5000); // setTimeout è asincrono, quindi la funzione sayHelloInFiveSeconds // esce immediatamente e setTimeout chiamera inner successivamente. Tuttavia, // poiché inner è "chiuso prima" di sayHelloInFiveSeconds, inner ha ancora // accesso alla variabile `prompt` quando viene finalmente richiamato. } sayHelloInFiveSeconds("Adam"); // aprirà un popup con "Hello, Adam!" in 5s /////////////////////////////////// // 5. Di più sugli oggetti, costruttori e prototipi. // Gli oggetti possono contenere funzioni. var myObj = { myFunc: function(){ return "Hello world!"; } }; myObj.myFunc(); // = "Hello world!" // Quando una funzione contenuta in un oggetto viene chiamata, essa può accedere a questo oggetto // possono farlo usando la parola chiave `this`. myObj = { myString: "Hello world!", myFunc: function(){ return this.myString; } }; myObj.myFunc(); // = "Hello world!" // Questo ha a che fare con come la funzione è chiamata, non con dove // è definita. Quindi, la nostra funzione non funziona se non è chiamata // nel contesto dell'oggetto. var myFunc = myObj.myFunc; myFunc(); // = undefined // Al contrario, una funzione può essere assegnata ad un oggetto e poi accedere ad esso // attraverso `this`, anche se non è stata inserita durante la definizione. var myOtherFunc = function(){ return this.myString.toUpperCase(); }; myObj.myOtherFunc = myOtherFunc; myObj.myOtherFunc(); // = "HELLO WORLD!" // Possiamo anche specificare un contesto per una funzione da eseguire quando la invochiamo // usando `call` o `apply`. var anotherFunc = function(s){ return this.myString + s; }; anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" // La funzione `apply` è quasi identica, ma prende un array come lista // di argomenti. anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" // Questo è utile quanso si lavora con una funzione che accetta una sequenza di // argomenti e si vuole passare un array. Math.min(42, 6, 27); // = 6 Math.min([42, 6, 27]); // = NaN (uh-oh!) Math.min.apply(Math, [42, 6, 27]); // = 6 // Ma, `call` e `apply` sono solo temporanei. Quando vogliamo incollarli, possiamo // usare `bind` var boundFunc = anotherFunc.bind(myObj); boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" // `bind` può essere anche usato per applicare parzialmente (curry) una funzione. var product = function(a, b){ return a * b; }; var doubler = product.bind(this, 2); doubler(8); // = 16 // Quando si chiama una funzione con la parola chiave `new`, un nuovo oggetto viene creato // e reso disponibile alla funzione attraverso la parola chiave `this`. Le funzioni progettate per essere // invocate in questo modo sono chiamate costruttrici. var MyConstructor = function(){ this.myNumber = 5; }; myNewObj = new MyConstructor(); // = {myNumber: 5} myNewObj.myNumber; // = 5 // Diversamente dalla molti degli altri linguaggi orientati agli oggetti, JavaScript non ha // il concetto di 'istanze' create sull'impronta di una 'classe'; invece JavaScript // combina l'instanziamento e l'ereditarietà in un singolo concetto: il 'prototipo'. // Ogni oggetto JavaScript ha un 'prototipo'. Quando si cerca di accedere a una proprietà // su un oggetto che non la contiene, l'interprete // guarderà i suoi prototipi. // Alcune implementazioni di JS faranno accedere al propotipo di un oggetto con la proprietà // magica `__proto__`: Anche se questo è utile per spiegare i prototipi, non è // parte dello standard; capiremo più avanti come usare i prototipi in modo standard. var myObj = { myString: "Hello world!" }; var myPrototype = { meaningOfLife: 42, myFunc: function(){ return this.myString.toLowerCase(); } }; myObj.__proto__ = myPrototype; myObj.meaningOfLife; // = 42 // Questo funziona anche per le funzioni. myObj.myFunc(); // = "hello world!" // Ovviamente, se la proprietà non è nel prototipo, il prototipo // del prototipo viene ricercato, e così via. myPrototype.__proto__ = { myBoolean: true }; myObj.myBoolean; // = true // Non c'è nessuna copia coinvolta qui; ogni oggetto mantiene una referenza al suo // prototipo. Questo significa che possiamo modificare il prototipo e i nostri cambiamenti // si rifletteranno da ogni parte. myPrototype.meaningOfLife = 43; myObj.meaningOfLife; // = 43 // L'istruzione for/in permette di iterare sulle proprietà di un oggetto, // risalendo la catena dei prototipi finché non trova un prototipo null. for (var x in myObj){ console.log(myObj[x]); } ///stampa: // Hello world! // 43 // [Function: myFunc] // true // Per considerare solamente le proprietà inserite nell'oggetto stesso // e non i loro prototipi, usare il check `hasOwnProperty()`. for (var x in myObj){ if (myObj.hasOwnProperty(x)){ console.log(myObj[x]); } } ///stampa: // Hello world! // Abbiamo menzionato che `__proto__` non è standard, e non c'è nessun modo standard per // cambiare il prototipo di un oggetto esistente. Tuttavia, ci sono due strade per // creare un nuovo oggetto con un dato prototipo. // La prima è Object.create, che è una recente aggiunta a JS, e che quindi // non è disponibile ancora in tutte le implementazioni. var myObj = Object.create(myPrototype); myObj.meaningOfLife; // = 43 // La seconda strada, che funziona ovunque, ha a che fare con i costruttori. // I costruttori hanno una proprietà chiamata prototype. Questo *non* è il prototipo del // costruttore della stessa funzione; invece è il prototipo del nuovo oggetto // che gli viene conferito alla creazione con quel costruttore e la parola chiave new. MyConstructor.prototype = { myNumber: 5, getMyNumber: function(){ return this.myNumber; } }; var myNewObj2 = new MyConstructor(); myNewObj2.getMyNumber(); // = 5 myNewObj2.myNumber = 6; myNewObj2.getMyNumber(); // = 6 // I tipi built-in come stringhe e numeri hanno anche costruttori che creano // oggetti wrapper equivalenti. var myNumber = 12; var myNumberObj = new Number(12); myNumber == myNumberObj; // = true // Eccezione, loro non sono esattamente equivalenti. typeof myNumber; // = 'number' typeof myNumberObj; // = 'object' myNumber === myNumberObj; // = false if (0){ // Questo codice non verrà eseguito perchè 0 è falso. } if (new Number(0)){ // Questo codice verrà eseguito poiché i numeri wrappati sono oggetti e gli oggetti // sono sempre veri. } // Tuttavia, gli oggetti wrapper e i regolari built-in condividono un prototipo, quindi // si possono aggiungere funzionalità ad una stringa, per esempio. String.prototype.firstCharacter = function(){ return this.charAt(0); }; "abc".firstCharacter(); // = "a" // Questa caratteristica viene spesso usata nel "polyfilling", che implementa nuovi // aspetti in un vecchio sottoinsieme di JavaScript, in modo che si possano // usare in vecchi ambienti come browser non aggiornati. // Per esempio, abbiamo menzionato che Object.create non è disponibile in tutte le // implementazioni, ma possiamo ancora usarlo con questo polyfill: if (Object.create === undefined){ // non lo sovrascrive se esiste già Object.create = function(proto){ // crea un costruttore temporaneo con il giusto prototipo var Constructor = function(){}; Constructor.prototype = proto; // quindi lo usa per creare un nuovo, propriamente-prototipato oggetto return new Constructor(); }; } ``` ## Approfondimenti Il [Mozilla Developer Networ][1] fornisce una documentazione eccellente su come JavaScript è utilizzato nei browsers. In più è un wiki, quindi si può imparare di più aiutando gli altri condividendo la propria conoscenza. MDN's [A re-introduction to JavaScript][2] copre molti dei concetti qui trattati in maggiore dettaglio. Questa guida ha deliberatamente coperto solamente il linguaggio JavaScript; se volete sapere di più su come usare JavaScript in una pagina web, iniziate leggendo il [Document Object Model][3]. [JavaScript Garden][5] è una guida approfondita di tutte le parti controintuitive del linguaggio. [JavaScript: The Definitive Guide][6] è una guida classica e referenziario. [Eloqunt JavaScript][8] di Marijn Haverbeke è un ottimo libro/ebook JS con terminale annesso [JavaScript: The Right Way][10] è una guida dedicata all'introduzione dei nuovi sviluppatori a JavaScript e come aiuto agli sviluppatori esperti per imparare di più sulle best practice. [javascript.info][11] è un moderno tutorial su JavaScript che copre le basi (linguaggio principale e lavorazione con un browser) come anche argomenti avanzati con spiegazioni concise. In aggiunta ai contributori di questo articolo, alcuni contenuti sono adattati dal Louie Dinh's Python tutorial su questo sito, e da [JS Tutorial][7] sul Mozilla Developer Network. [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript [3]: https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core [5]: https://shamansir.github.io/JavaScript-Garden/ [6]: http://www.amazon.com/gp/product/0596805527/ [7]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript [8]: http://eloquentjavascript.net/ [10]: http://jstherightway.org/ [11]: https://it.javascript.info/ ================================================ FILE: it/jquery.md ================================================ --- contributors: - ["Sawyer Charles", "https://github.com/xssc"] translators: - ["Ale46", "https://github.com/ale46"] --- jQuery è una libreria JavaScript che ti aiuta a "fare di più, scrivendo meno". Rende molte attività comuni di JavaScript più facili da scrivere. jQuery è utilizzato da molte grandi aziende e sviluppatori in tutto il mondo. Rende AJAX, gestione degli eventi, manipolazione dei documenti e molto altro, più facile e veloce. Visto che jQuery è una libreria JavaScript dovresti prima [imparare JavaScript](../javascript/) ```js /////////////////////////////////// // 1. Selettori // I selettori in jQuery vengono utilizzati per selezionare un elemento var page = $(window); // Seleziona l'intera finestra // I selettori possono anche essere selettori CSS var paragraph = $('p'); // Seleziona tutti gli elementi del paragrafo var table1 = $('#table1'); // Seleziona elemento con id 'table1' var squares = $('.square'); // Seleziona tutti gli elementi con la classe 'square' var square_p = $('p.square') // Seleziona i paragrafi con la classe 'square' /////////////////////////////////// // 2. Eventi ed effetti // jQuery è molto bravo a gestire ciò che accade quando un evento viene attivato // Un evento molto comune è l'evento "pronto" sul documento // Puoi usare il metodo 'ready' per aspettare che l'elemento abbia finito di caricare $(document).ready(function(){ // Il codice non verrà eseguito fino a quando il documento non verrà caricato }); // Puoi anche usare funzioni definite function onAction() { // Questo viene eseguito quando l'evento viene attivato } $('#btn').click(onAction); // Invoca onAction al click // Alcuni altri eventi comuni sono: $('#btn').dblclick(onAction); // Doppio click $('#btn').hover(onAction); // Al passaggio del mouse $('#btn').focus(onAction); // Al focus $('#btn').blur(onAction); // Focus perso $('#btn').submit(onAction); // Al submit $('#btn').select(onAction); // Quando un elemento è selezionato $('#btn').keydown(onAction); // Quando un tasto è premuto (ma non rilasciato) $('#btn').keyup(onAction); // Quando viene rilasciato un tasto $('#btn').keypress(onAction); // Quando viene premuto un tasto $('#btn').mousemove(onAction); // Quando il mouse viene spostato $('#btn').mouseenter(onAction); // Il mouse entra nell'elemento $('#btn').mouseleave(onAction); // Il mouse lascia l'elemento // Questi possono anche innescare l'evento invece di gestirlo // semplicemente non passando alcun parametro $('#btn').dblclick(); // Innesca il doppio click sull'elemento // Puoi gestire più eventi mentre usi il selettore solo una volta $('#btn').on( {dblclick: myFunction1} // Attivato con doppio clic {blur: myFunction1} // Attivato al blur ); // Puoi spostare e nascondere elementi con alcuni metodi di effetto $('.table').hide(); // Nascondi gli elementi // Nota: chiamare una funzione in questi metodi nasconderà comunque l'elemento $('.table').hide(function(){ // Elemento nascosto quindi funzione eseguita }); // È possibile memorizzare selettori in variabili var tables = $('.table'); // Alcuni metodi di manipolazione dei documenti di base sono: tables.hide(); // Nascondi elementi tables.show(); // Mostra elementi tables.toggle(); // Cambia lo stato nascondi/mostra tables.fadeOut(); // Fades out tables.fadeIn(); // Fades in tables.fadeToggle(); // Fades in o out tables.fadeTo(0.5); // Dissolve in opacità (tra 0 e 1) tables.slideUp(); // Scorre verso l'alto tables.slideDown(); // Scorre verso il basso tables.slideToggle(); // Scorre su o giù // Tutti i precedenti prendono una velocità (millisecondi) e la funzione di callback tables.hide(1000, myFunction); // nasconde l'animazione per 1 secondo quindi esegue la funzione // fadeTo ha un'opacità richiesta come secondo parametro tables.fadeTo(2000, 0.1, myFunction); // esegue in 2 sec. il fade sino ad una opacità di 0.1 opacity e poi la funzione // Puoi ottenere un effetti più avanzati con il metodo animate tables.animate({margin-top:"+=50", height: "100px"}, 500, myFunction); // Il metodo animate accetta un oggetto di css e valori con cui terminare, // parametri opzionali per affinare l'animazione, // e naturalmente la funzione di callback /////////////////////////////////// // 3. Manipolazione // Questi sono simili agli effetti ma possono fare di più $('div').addClass('taming-slim-20'); // Aggiunge la classe taming-slim-20 a tutti i div // Metodi di manipolazione comuni $('p').append('Hello world'); // Aggiunge alla fine dell'elemento $('p').attr('class'); // Ottiene l'attributo $('p').attr('class', 'content'); // Imposta l'attributo $('p').hasClass('taming-slim-20'); // Restituisce vero se ha la classe $('p').height(); // Ottiene l'altezza dell'elemento o imposta l'altezza // Per molti metodi di manipolazione, ottenere informazioni su un elemento // restituirà SOLO il primo elemento corrispondente $('p').height(); // Ottiene solo la prima altezza del tag 'p' // È possibile utilizzare each per scorrere tutti gli elementi var heights = []; $('p').each(function() { heights.push($(this).height()); // Aggiunge tutte le altezze del tag 'p' all'array }); ``` ================================================ FILE: it/json.md ================================================ --- contributors: - ["Anna Harren", "https://github.com/iirelu"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["himanshu", "https://github.com/himanshu81494"] translators: - ["Robert Margelli", "http://github.com/sinkswim/"] - ["Christian Grasso", "http://chris54721.net"] --- JSON è un formato per l'interscambio di dati estremamente semplice, per cui questo sarà con molta probabilità il più semplice Learn X in Y Minutes. Nella sua forma più pura JSON non ha commenti, ma molti parser accettano commenti in stile C (//, /\* \*/). Per lo scopo prefissato, tuttavia, tutto sarà 100% JSON valido. Fortunatamente, si spiega da sè. I tipi supportati da JSON comprendono: numeri, stringhe, boolean, array, oggetti e null. I browser supportati sono: Firefox (Mozilla) 3.5+, Internet Explorer 8+, Google Chrome, Opera 10+, Safari 4+. I file JSON sono salvati nel formato ".json". Il MIME type per documenti JSON è "application/json". Gli svantaggi del JSON includono l'assenza di una definizione dei tipi e di una sorta di [DTD](https://it.wikipedia.org/wiki/Document_Type_Definition). ```json { "chiave": "valore", "chiavi": "devono sempre essere racchiuse tra doppi apici", "numeri": 0, "stringhe": "Ciaø, møndø. Tutti i caratteri Unicode sono permessi, insieme all'\"escaping\".", "ha booleani?": true, "il nulla": null, "numero grande": 1.2e+100, "oggetti": { "commento": "La maggior parte della tua struttura viene dagli oggetti.", "array": [0, 1, 2, 3, "Gli array possono contenere qualsiasi cosa.", 5], "un altro oggetto": { "commento": "Queste cose possono essere annidate, molto utile." } }, "sciocchezze": [ { "sorgenti di potassio": ["banane"] }, [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, "neo"], [0, 0, 0, 1] ] ], "stile alternativo": { "commento": "Guarda qua!" , "posizione della virgola": "non conta - se è prima della chiave successiva, allora è valida" , "un altro commento": "che bello" }, "è stato molto breve": "Ed hai finito. Adesso sai tutto cio che JSON ha da offrire." } ``` ================================================ FILE: it/logtalk.md ================================================ --- contributors: - ["Paulo Moura", "http://github.com/pmoura"] translators: - ["Ugo Chirico", "https://github.com/ugochirico"] --- Logtalk è un linguaggio di programmazione logica orientata agli oggetti che estende il linguaggio Prolog con le moderne tecniche di Object-Oriented Programming quali incapsulamento, ereditarietà e riutilizzo del codice, senza compromettere le caratteristiche di programmazione dichiarativa del Prolog. Logtalk è implementato in codice altamente portabile e utilizza i più moderni standard di conformità del Prolog rispetto al compilatore backend. Per mantenere una dimensione ragionevole, questo tutorial presuppone necessariamente che il lettore abbia una conoscenza del linguaggio Prolog ed è inoltre focalizzato esclusivamente sulla descrizione delle caratteristiche object-oriented di Logtalk. # Sintassi Logtalk utilizza la sintassi standard del linguaggio Prolog con l'aggiunta di un paio di operatori e di alcune direttive per una curva di apprendimento morbida e per assicurare ampia portabilità. Una conseguenza importante è che il codice Prolog può essere facilmente incapsulato in oggetti con poche o nessuna modifica. Inoltre, Logtalk può interpretare come oggetti Logtalk, in modo trasparente, la maggior parte dei moduli Prolog già esistenti. I principali operatori sono: * `::/2` - per inviare un messaggio ad un oggetto * `::/1` - per inviare un messaggio a se stesso _self_ (cioè all'oggetto che riceverà il messaggio) * `^^/1` - _super_ per chiamare un predicato ereditato o importato Alcune delle più importanti entità e direttive saranno introdotte nelle sezioni successive. # Entità e Ruoli Logtalk tratta gli oggetti, i protocolli e le categorie come entità di prima classe. I rapporti tra le entità definiscono i _patterns of code reuse_ ossia i modelli di riutilizzo del codice e i _roles_ ossia i ruoli svolti da tali entità. Ad esempio, quando un oggetto istanzia un altro oggetto, il primo oggetto assume il ruolo di istanza e il secondo oggetto assume il ruolo di classe. Una relazione di tipo _extends_ tra due oggetti implica che entrambi gli oggetti svolgano il ruolo di prototipi, in cui uno di loro estende l'altro, che diventa quindi suo prototipo padre. # Definizione di un oggetto Un oggetto incapsula le dichiarazioni e le definizioni dei predicati. Gli oggetti possono essere creati in modo dinamico, ma di solito sono dichiarati come statici e definiti nel codice sorgente. Un singolo file sorgente può contenere un qualsiasi numero di definizioni di entità. Ecco un semplice oggetto `list` che definisce un membro pubblico `member/2`: ```logtalk :- object(list). :- public(member/2). member(Head, [Head| _]). member(Head, [_| Tail]) :- member(Head, Tail). :- end_object. ``` # Compilazione e il caricamento dei file sorgenti Supponendo che il codice di cui sopra per l'oggetto `list` venga salvato in un file `list.lgt`, esso può essere compilato e caricato utilizzando il predicato predefiniti `logtalk_load/1` o la sua abbreviazione `{}/1`, con il percorso del file come argomento (l'estensione può essere omessa): ```logtalk ?- {list}. yes ``` In generale, le entità potrebbero avere dipendenze sulle entità definite in altri file di origine (ad esempio le entità di biblioteca). Per caricare un file e tutte le sue dipendenze, la soluzione consigliata consiste nel definire un file _loader_ che carica tutti i file necessari per un'applicazione. Un file loader è semplicemente un file di origine, in genere denominato `loader.lgt`, che effettua chiamate ai predicati built-in `logtalk_load/1-2`, di solito da una direttiva `initialization/1` per la portabilità e conformità agli standard. Caricatore file vengono forniti per tutte le librerie, strumenti ed esempi. # Inviare un messaggio ad un oggetto L'operatore infisso `::/2` è usato per inviare messaggi ad un oggetto. Analogamente al Prolog, è possibile fare backtracking per le soluzioni alternative: ```logtalk ?- list::member(X, [1,2,3]). X = 1 ; X = 2 ; X = 3 yes ``` Analogamente alla programmazione object-oriented, logtalk consente anche l'Incapsulamento. Un predicato può essere dichiarata pubblico, protetto o privato. Può anche essere _local_ quando non esiste una direttiva specifica per esso all'interno dello scope. Per esempio: ```logtalk :- object(scopes). :- private(bar/0). bar. local. :- end_object. ``` Assumendo che l'oggetto è salvato nel file `scopes.lgt`: ```logtalk ?- {scopes}. yes ?- catch(scopes::bar, Error, true). Error = error( permission_error(access, private_predicate, bar/0), logtalk(scopes::bar, user) ) yes ?- catch(scopes::local, Error, true). Error = error( existence_error(predicate_declaration, local/0), logtalk(scopes::local, user) ) yes ``` Quando il predicato in un messaggio non è noto per l'oggetto (il ruolo dell'oggetto determina le procedure di ricerca), si ha un errore. Per esempio: ```logtalk ?- catch(scopes::unknown, Error, true). Error = error( existence_error(predicate_declaration, unknown/0), logtalk(scopes::unknown, user) ) yes ``` Un punto fondamentale da capire è che le direttive che specificano il predicato nello scope specificano la semantica di chiamata (_calling_) del predicato, e non la semantica di definizione (_definition_). Ad esempio, se un oggetto ha il ruolo di una classe e dichiara un predicato privato, tale predicato può essere definito nelle sue sottoclassi e nelle istanze *ma* può essere chiamato solo nelle sue istanza (_from_) dalla classe. # Definizione e implementazione di un protocollo Un Protocollo contiene le dichiarazioni dei predicati che possono essere implementati da un qualsivoglia numero di oggetti e categorie: ```logtalk :- protocol(listp). :- public(member/2). :- end_protocol. :- object(list, implements(listp)). member(Head, [Head| _]). member(Head, [_| Tail]) :- member(Head, Tail). :- end_object. ``` Lo scope dei predicati di un protocollo può essere ristretto usando implementazioni protected e private. Ad esempio: ```logtalk :- object(stack, implements(private::listp)). :- end_object. ``` Difatti, tutte le relazioni tra entità (nella direttiva di apertura di un entità) possono essere definite come public (default), protected, o private. # Prototipi Un oggetto senza una istanza o senza una relazione di specializzazione con un altro oggetto interpreta il ruolo di prototipo. Un prototipo può estendere un altro oggetto, il suo prototipo genitore. ```logtalk % clyde, our prototypical elephant :- object(clyde). :- public(color/1). color(grey). :- public(number_of_legs/1). number_of_legs(4). :- end_object. % fred, another elephant, is like clyde, except that he's white :- object(fred, extends(clyde)). color(white). :- end_object. ``` Per rispondere ad un messaggio inviato ad un oggetto che ha il ruolo di prototipo, si cerca prima una risposta nel prototipo stesso e se il prototipo non sa rispondere si passa all'eventuale prototipo genitore (se esiste): ```logtalk ?- fred::number_of_legs(N). N = 4 yes ?- fred::color(C). C = white yes ``` Un messaggio è valido se il relativo predicato è dichiarato in un oggetto (e se il mittente è nel campo di applicazione), ma fallirà, piuttosto che lanciare un errore, se il predicato non è definito. Questa è chiamata la _closed-world assumption_. Ad esempio, si consideri il seguente oggetto, salvato in un file `foo.lgt`: ```logtalk :- object(foo). :- public(bar/0). :- end_object. ``` Caricando il file e cercando di chiamare il predicato `bar/0` questo fallisce come previsto. Si noti che ciò è diverso dal chiamare un predicato sconosciuto _unknown_, che invece genera un errore: ```logtalk ?- {foo}. yes ?- foo::bar. no ?- catch(foo::baz, Error, true). Error = error( existence_error(predicate_declaration, baz/0), logtalk(foo::baz, user) ) yes ``` # Classi e istanze Per definire gli oggetti nei ruoli di classi e/o istanze, un oggetto deve avere almeno un istanziazione o una relazione di specializzazione con un altro oggetto. Gli oggetti che hanno il ruolo di meta-classi possono essere utilizzati quando abbiamo bisogno di usare una classe come se fosse un'istanza. Il seguente esempio mostra come creare dinamicamente nuovi oggetti in fase di esecuzione: ```logtalk % a simple, generic, metaclass defining a new/2 predicate for its instances :- object(metaclass, instantiates(metaclass)). :- public(new/2). new(Instance, Clauses) :- self(Class), create_object(Instance, [instantiates(Class)], [], Clauses). :- end_object. % a simple class defining age/1 and name/1 predicate for its instances :- object(person, instantiates(metaclass)). :- public([ age/1, name/1 ]). % a default value for age/1 age(42). :- end_object. % a static instance of the class person :- object(john, instantiates(person)). name(john). age(12). :- end_object. ``` Nel rispondere ad un messaggio inviato ad un oggetto ha assunto il ruolo di istanza, tal messaggio viene convalidato partendo dalla sua classe e andando a ritroso nella gerarchia, se necessario, fino alle sue superclassi. Supponendo che il messaggio sia valido, allora si cerca una risposta a partire dall'istanza stessa: ```logtalk ?- person::new(Instance, [name(paulo)]). Instance = o1 yes ?- o1::name(Name). Name = paulo yes ?- o1::age(Age). Age = 42 yes ?- john::age(Age). Age = 12 yes ``` # Categorie Una categoria è un'unità atomica di codice riutilizzabile. Una categoria è usata per incapsulare una insieme coesivo (_cohesive_) di dichiarazioni e di definizioni di predicato ed è atta ad implementare una singola (_single_) funzionalità che può essere importata in qualsiasi oggetto. Una categoria può quindi essere concepita come il concetto duale di protocollo. Nel seguente esempio, si definiscono prima le categorie che rappresentano i motori di auto e poi si importano tali categorie negli oggetti auto: ```logtalk % a protocol describing engine characteristics :- protocol(carenginep). :- public([ reference/1, capacity/1, cylinders/1, horsepower_rpm/2, bore_stroke/2, fuel/1 ]). :- end_protocol. % a typical engine defined as a category :- category(classic, implements(carenginep)). reference('M180.940'). capacity(2195). cylinders(6). horsepower_rpm(94, 4800). bore_stroke(80, 72.8). fuel(gasoline). :- end_category. % a souped up version of the previous engine :- category(sport, extends(classic)). reference('M180.941'). horsepower_rpm(HP, RPM) :- ^^horsepower_rpm(ClassicHP, ClassicRPM), % "super" call HP is truncate(ClassicHP*1.23), RPM is truncate(ClassicRPM*0.762). :- end_category. % with engines (and other components), we may start "assembling" some cars :- object(sedan, imports(classic)). :- end_object. :- object(coupe, imports(sport)). :- end_object. ``` Le Categorie sono compilate in modo indipendente e, quindi, consentono l'importazione di oggetti da aggiornare mediante il semplice aggiornamento delle categorie importate, senza richiedere pertanto la ricompilazione dell'oggetto. Le Categorie forniscono anche la _runtime transparency_, cioè il protocollo della categoria si aggiunge al protocollo degli oggetti che importano tale categoria: ```logtalk ?- sedan::current_predicate(Predicate). Predicate = reference/1 ; Predicate = capacity/1 ; Predicate = cylinders/1 ; Predicate = horsepower_rpm/2 ; Predicate = bore_stroke/2 ; Predicate = fuel/1 yes ``` # Hot patching Le categorie possono essere anche usate per modificare gli oggetti al volo (_hot-patch_). Una categoria può aggiungere nuovi predicati ad un oggetto e/o sostituire le definizioni dei predicati dell'oggetto. Ad esempio, si consideri il seguente oggetto: ```logtalk :- object(buggy). :- public(p/0). p :- write(foo). :- end_object. ``` Si supponga che l'oggetto stampi la stringa sbagliata quando riceve il messaggio `p/0`: ```logtalk ?- {buggy}. yes ?- buggy::p. foo yes ``` Se il codice sorgente dell'oggetto non è disponibile e bisogna correggere l'applicazione che sta eseguendo il codice dell'oggetto, si può semplicemente definire una categoria che corregge il predicato non corretto: ```logtalk :- category(patch, complements(buggy)). % fixed p/0 def p :- write(bar). :- end_category. ``` Dopo la compilazione e il caricamento della categoria nell'applicazione in esecuzione si ottiene: ```logtalk ?- set_logtalk_flag(complements, allow). yes ?- {patch}. yes ?- buggy::p. bar yes ``` Poiché l'hot-patching interrompe forzatamente l'incapsulamento, è possibile impostare il flag del compilatore `complementary` può essere impostato (a livello globale o per un singolo oggetto) per consentire, limitare o prevenire l'hot-patching. # Oggetti Parametrici e Categorie Gli oggetti e le categorie possono essere parametrizzati utilizzando come identificativo un compound-term al posto di un atomo. Oggetti e parametri di una categoria sono variabili logiche _logical variables_ condivise con tutti i predicati incapsulati. Ecco un esempio con cerchi geometrici: ```logtalk :- object(circle(_Radius, _Color)). :- public([ area/1, perimeter/1 ]). area(Area) :- parameter(1, Radius), Area is pi*Radius*Radius. perimeter(Perimeter) :- parameter(1, Radius), Perimeter is 2*pi*Radius. :- end_object. ``` Oggetti parametrici possono essere utilizzati come qualsiasi altro oggetto e di solito forniscono i valori da assegnare ai parametri quando si invia un messaggio: ```logtalk ?- circle(1.23, blue)::area(Area). Area = 4.75291 yes ``` Gli oggetti parametrici forniscono anche un modo semplice per associare un insieme di predicati con un semplice predicato Prolog. Fatti Prolog possono essere interpretati come oggetti proxy parametrici ( _parametric object proxies_) quando hanno lo stesso funtore e arietà degli identificatori di oggetti parametrici. Per lavorare con i proxy viene fornita una sintassi maneggevole. Per esempio, si prendano le seguenti clausole per il predicato `circle/2`: ```logtalk circle(1.23, blue). circle(3.71, yellow). circle(0.39, green). circle(5.74, black). circle(8.32, cyan). ``` Con queste clausole, si può facilmente calcolare, ad esempio, un elenco con le aree di tutti i cerchi: ```logtalk ?- findall(Area, {circle(_, _)}::area(Area), Areas). Areas = [4.75291, 43.2412, 0.477836, 103.508, 217.468] yes ``` In pratica, il costrutto `{Goal}::Message` prova il goal `Goal`, instanziando le variabili interne e inviando un messaggio `Message` al termine risultante. # Eventi and monitor Logtalk supporta l'_event-driven programming_ mediante la definizione di eventi e di monitor. Un evento è semplicemente l'invio di un messaggio ad un oggetto. Un monitor è un gestore di un evento. L'evento (con l'invio di un messaggio) è un'attività atomica, ed è preceduta da un evento _before_ e da un evento _after_. Il monitor gestisce tali eventi mediante i predicati, `before/3` e `after/3`, che sono chiamati rispettivamente prima e dopo il verificarsi dell'evento. Un monitor può inoltre interrogare, registrare e cancellare un evento nel registro eventi a livello di sistema il quale che associa gli eventi con i monitor. Ad esempio, un semplice tracer per ogni messaggio inviato utilizzando il costrutto `::/2` può essere definito come: ```logtalk :- object(tracer, implements(monitoring)). % built-in protocol for event handlers :- initialization(define_events(_, _, _, _, tracer)). before(Object, Message, Sender) :- write('call: '), writeq(Object), write(' <-- '), writeq(Message), write(' from '), writeq(Sender), nl. after(Object, Message, Sender) :- write('exit: '), writeq(Object), write(' <-- '), writeq(Message), write(' from '), writeq(Sender), nl. :- end_object. ``` Supponendo che l'oggetto `tracer` e l'oggetto `list` definito in precedenza siano stati già compilati e caricati, si possono osservare i gestori di eventi in azione durante l'invio di un messaggio: ```logtalk ?- set_logtalk_flag(events, allow). yes ?- list::member(X, [1,2,3]). call: list <-- member(X, [1,2,3]) from user exit: list <-- member(1, [1,2,3]) from user X = 1 ; exit: list <-- member(2, [1,2,3]) from user X = 2 ; exit: list <-- member(3, [1,2,3]) from user X = 3 yes ``` Gli eventi possono essere impostati e cancellati dinamicamente in fase di esecuzione chiamando i predicati predefiniti `define_events/5` e `abolish_events/5`. La programmazione event-driven può essere vista come una forma di _computational reflection_. Si noti però che gli eventi sono generati solo quando si utilizza il costrutto di controllo per l'invio di messaggi `::/2`. # Espressioni lambda Logtalk supporta anche le espressioni lambda. I parametri della espressioni lambda sono rappresentati mediante una lista con l'operatore infisso `(>>)/2` che collega i parametri alla relativa lambda espressione. Ecco alcuni semplici esempi che utilizzano la libreria `meta`. ```logtalk ?- {meta(loader)}. yes ?- meta::map([X,Y]>>(Y is 2*X), [1,2,3], Ys). Ys = [2,4,6] yes ``` Logtalk supporta anche il _currying_: ```logtalk ?- meta::map([X]>>([Y]>>(Y is 2*X)), [1,2,3], Ys). Ys = [2,4,6] yes ``` Infine, le variabili libere Lambda possono essere espresso usando la sintassi estesa `{Free1, ...}/[Parameter1, ...]>>Lambda`. # Macro I Termini e goal nel file sorgente possono essere _estesi_ al momento della compilazione specificando una hook ad un oggetto (_hook object_) che definisce le regole di riscrittura dei termini e riscrittura dei quesiti. Ad esempio, si consideri il seguente oggetto semplice, salvato nel file `source.lgt`: ```logtalk :- object(source). :- public(bar/1). bar(X) :- foo(X). foo(a). foo(b). foo(c). :- end_object. ``` Si supponga il seguente hook all'oggetto, salvato nel file `my_macros.lgt`, che estende le clausole e chiama il predicato locale `foo/1`: ```logtalk :- object(my_macros, implements(expanding)). % built-in protocol for expanding predicates term_expansion(foo(Char), baz(Code)) :- char_code(Char, Code). % standard built-in predicate goal_expansion(foo(X), baz(X)). :- end_object. ``` Dopo aver caricato il file contenente la macro, si può espandere il nostro file sorgente usando il flag del compilatore `hook`: ```logtalk ?- logtalk_load(my_macros), logtalk_load(source, [hook(my_macros)]). yes ?- source::bar(X). X = 97 ; X = 98 ; X = 99 true ``` La libreria Logtalk fornisce infine il supporto per combinare hook agli oggetti utilizzando diversi modi (ad esempio, definendo una pipeline di espansioni). # Maggiori informazioni Visita il [Sito web di Logtalk (en)](http://logtalk.org) per maggiori informazioni. ================================================ FILE: it/lua.md ================================================ --- name: Lua contributors: - ["Tyler Neylon", "http://tylerneylon.com/"] translators: - ["valerioandreachiodi", "https://github.com/valerioandreachiodi"] --- ```lua -- Due trattini iniziano un commento su una riga. --[[ Aggiungere due [ e ] crea un commento multi-riga. --]] ---------------------------------------------------- -- 1. Variabili e controllo di flusso. ---------------------------------------------------- num = 42 -- I numeri possono essere interi o floating point. s = 'walternate' -- Stringhe immutabili come in Python. t = "anche le virgolette doppie vanno bene" u = [[ Le doppie parentesi quadre iniziano e finiscono stringhe multi-riga.]] t = nil -- Rende t indefinita; Lua ha il garbage collection. -- I blocchi sono denotati con parole chiave come do/end: while num < 50 do num = num + 1 -- Non esistono operatori tipo ++ o +=. end -- Clausole If: if num > 40 then print('sopra i 40') elseif s ~= 'walternate' then -- ~= è "diverso da". -- Il controllo di uguaglianza è == come in Python; ok per le stringhe. io.write('non sopra i 40\n') -- Default su stdout. else -- Le variabili sono globali di default. thisIsGlobal = 5 -- Il camel case è comune. -- Come rendere una variabile locale: local line = io.read() -- Legge la prossima riga da stdin. -- La concatenazione di stringhe usa l'operatore .. : print('L\'inverno sta arrivando, ' .. line) end -- Le variabili indefinite restituiscono nil. -- Questo non è un errore: foo = anUnknownVariable -- Ora foo = nil. aBoolValue = false -- Solo nil e false sono falsy; 0 e '' sono true! if not aBoolValue then print('era falso') end -- 'or' e 'and' sono a corto circuito. -- Simile all'operatore a?b:c in C/js: ans = aBoolValue and 'yes' or 'no' --> 'no' karlSum = 0 for i = 1, 100 do -- Il range include entrambi gli estremi. karlSum = karlSum + i end -- Usa "100, 1, -1" come range per contare alla rovescia: fredSum = 0 for j = 100, 1, -1 do fredSum = fredSum + j end -- In generale, il range è inizio, fine[, step]. -- Un altro costrutto di ciclo: repeat print('la via del futuro') num = num - 1 until num == 0 ---------------------------------------------------- -- 2. Funzioni. ---------------------------------------------------- function fib(n) if n < 2 then return 1 end return fib(n - 2) + fib(n - 1) end -- Closure e funzioni anonime vanno bene: function adder(x) -- La funzione restituita viene creata quando adder viene -- chiamata, e ricorda il valore di x: return function (y) return x + y end end a1 = adder(9) a2 = adder(36) print(a1(16)) --> 25 print(a2(64)) --> 100 -- Return, chiamate di funzione e assegnazioni funzionano tutti -- con liste che possono avere lunghezze diverse. -- I ricevitori senza corrispondenza sono nil; -- i mandanti in eccesso vengono scartati. x, y, z = 1, 2, 3, 4 -- Ora x = 1, y = 2, z = 3, e il 4 viene buttato via. function bar(a, b, c) print(a, b, c) return 4, 8, 15, 16, 23, 42 end x, y = bar('zaphod') --> stampa "zaphod nil nil" -- Ora x = 4, y = 8, i valori 15...42 sono scartati. -- Le funzioni sono "first-class", possono essere locali/globali. -- Queste sono la stessa cosa: function f(x) return x * x end f = function (x) return x * x end -- E anche queste: local function g(x) return math.sin(x) end local g; g = function (x) return math.sin(x) end -- la dichiarazione 'local g' rende possibili i riferimenti a g-stessa. -- Le funzioni trigonometriche lavorano in radianti, tra l'altro. -- Le chiamate con un solo parametro stringa non necessitano di parentesi: print 'hello' -- Funziona benissimo. ---------------------------------------------------- -- 3. Tabelle (Tables). ---------------------------------------------------- -- Le Tabelle = l'unica struttura dati composta di Lua; -- sono array associativi. -- Simili agli array di PHP o agli oggetti JS, sono dizionari -- con lookup hash che possono essere usati anche come liste. -- Usare le tabelle come dizionari / mappe: -- I letterali dei dizionari hanno chiavi stringa di default: t = {key1 = 'value1', key2 = false} -- Le chiavi stringa possono usare la notazione a punto tipo JS: print(t.key1) -- Stampa 'value1'. t.newKey = {} -- Aggiunge una nuova coppia chiave/valore. t.key2 = nil -- Rimuove key2 dalla tabella. -- Notazione letterale per qualsiasi valore (non-nil) come chiave: u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} print(u[6.28]) -- stampa "tau" -- La corrispondenza delle chiavi è fondamentalmente per valore per numeri -- e stringhe, ma per identità per le tabelle. a = u['@!#'] -- Ora a = 'qbert'. b = u[{}] -- Potremmo aspettarci 1729, ma è nil: -- b = nil perché il lookup fallisce. Fallisce -- perché la chiave che abbiamo usato non è lo stesso oggetto -- di quello usato per memorizzare il valore originale. Quindi -- stringhe e numeri sono chiavi più portabili. -- Una chiamata a funzione con un parametro tabella non serve parentesi: function h(x) print(x.key1) end h{key1 = 'Sonmi~451'} -- Stampa 'Sonmi~451'. for key, val in pairs(u) do -- Iterazione della tabella. print(key, val) end -- _G è una tabella speciale di tutti i globali. print(_G['_G'] == _G) -- Stampa 'true'. -- Usare le tabelle come liste / array: -- I letterali lista impostano implicitamente chiavi intere: v = {'value1', 'value2', 1.21, 'gigawatts'} for i = 1, #v do -- #v è la dimensione di v per le liste. print(v[i]) -- Gli indici partono da 1 !! FOLLIA! end -- Una 'list' non è un vero tipo. v è solo una tabella -- con chiavi intere consecutive, trattata come una lista. ---------------------------------------------------- -- 3.1 Metatabelle e metametodi. ---------------------------------------------------- -- Una tabella può avere una metatabella che le conferisce un -- comportamento simile all'overload degli operatori. Vedremo dopo -- come le metatabelle supportano il comportamento prototipale di JS. f1 = {a = 1, b = 2} -- Rappresenta la frazione a/b. f2 = {a = 2, b = 3} -- Questo fallirebbe: -- s = f1 + f2 metafraction = {} function metafraction.__add(f1, f2) sum = {} sum.b = f1.b * f2.b sum.a = f1.a * f2.b + f2.a * f1.b return sum end setmetatable(f1, metafraction) setmetatable(f2, metafraction) s = f1 + f2 -- chiama __add(f1, f2) sulla metatabella di f1 -- f1, f2 non hanno chiavi per la loro metatabella, a differenza -- dei prototipi in JS, quindi devi recuperarla come in -- getmetatable(f1). La metatabella è una normale tabella -- con chiavi che Lua conosce, come __add. -- Ma la riga successiva fallisce perché s non ha una metatabella: -- t = s + s -- I pattern simili alle classi descritti sotto risolverebbero questo. -- Un __index su una metatabella sovraccarica i lookup a punto: defaultFavs = {animal = 'gru', food = 'donuts'} myFavs = {food = 'pizza'} setmetatable(myFavs, {__index = defaultFavs}) eatenBy = myFavs.animal -- funziona! grazie, metatabella -- I lookup diretti sulla tabella che falliscono riproveranno usando -- il valore __index della metatabella, e questo è ricorsivo. -- Un valore __index può anche essere una funzione(tbl, key) -- per lookup più personalizzati. -- I valori di __index, __add, ecc. sono chiamati metametodi. -- Ecco alcuni tra i più usati: -- __add(a, b) per a + b -- __sub(a, b) per a - b -- __mul(a, b) per a * b -- __div(a, b) per a / b -- __mod(a, b) per a % b -- __pow(a, b) per a ^ b -- __unm(a) per -a -- __concat(a, b) per a .. b -- __len(a) per #a -- __eq(a, b) per a == b -- __lt(a, b) per a < b -- __le(a, b) per a <= b -- __index(a, b) per a.b -- __newindex(a, b, c) per a.b = c -- __call(a, ...) per a(...) ---------------------------------------------------- -- 3.2 Tabelle "simili a classi" ed ereditarietà. ---------------------------------------------------- -- Le classi non sono integrate; ci sono diversi modi -- per crearle usando tabelle e metatabelle. -- La spiegazione per questo esempio è riportata sotto. Dog = {} -- 1. function Dog:new() -- 2. newObj = {sound = 'woof'} -- 3. self.__index = self -- 4. return setmetatable(newObj, self) -- 5. end function Dog:makeSound() -- 6. print('Io dico ' .. self.sound) end mrDog = Dog:new() -- 7. mrDog:makeSound() -- 'Io dico woof' -- 8. -- 1. Dog agisce come una classe; in realtà è una tabella. -- 2. function tablename:fn(...) è uguale a -- function tablename.fn(self, ...) -- I : aggiungono solo un primo argomento chiamato self. -- Leggi 7 e 8 sotto per come self ottiene il suo valore. -- 3. newObj sarà un'istanza della classe Dog. -- 4. self = la classe che viene istanziata. Spesso -- self = Dog, ma l'ereditarietà può cambiarlo. -- newObj ottiene le funzioni di self quando impostiamo sia -- la metatabella di newObj che l'__index di self su self. -- 5. Promemoria: setmetatable restituisce il suo primo argomento. -- 6. I : funzionano come nel punto 2, ma stavolta ci aspettiamo -- che self sia un'istanza invece di una classe. -- 7. Uguale a Dog.new(Dog), quindi self = Dog in new(). -- 8. Uguale a mrDog.makeSound(mrDog); self = mrDog. ---------------------------------------------------- -- Esempio di ereditarietà: LoudDog = Dog:new() -- 1. function LoudDog:makeSound() s = self.sound .. ' ' -- 2. print(s .. s .. s) end seymour = LoudDog:new() -- 3. seymour:makeSound() -- 'woof woof woof' -- 4. -- 1. LoudDog ottiene i metodi e le variabili di Dog. -- 2. self ha una chiave 'sound' da new(), vedi punto 3. -- 3. Uguale a LoudDog.new(LoudDog), e convertito in -- Dog.new(LoudDog) poiché LoudDog non ha una chiave 'new', -- ma ha __index = Dog sulla sua metatabella. -- Risultato: la metatabella di seymour è LoudDog, e -- LoudDog.__index = LoudDog. Quindi seymour.chiave sarà -- = seymour.chiave, LoudDog.chiave, Dog.chiave, a seconda di quale -- tabella sia la prima a possedere la chiave data. -- 4. La chiave 'makeSound' viene trovata in LoudDog; questo -- è uguale a LoudDog.makeSound(seymour). -- Se necessario, il new() di una sottoclasse è come quello della base: function LoudDog:new() newObj = {} -- imposta newObj self.__index = self return setmetatable(newObj, self) end ---------------------------------------------------- -- 4. Moduli. ---------------------------------------------------- --[[ Commento questa sezione in modo che il resto -- di questo script rimanga eseguibile. ``` ```lua -- Supponiamo che il file mod.lua sia così: local M = {} local function sayMyName() print('Hrunkner') end function M.sayHello() print('Perbacco, ciao') sayMyName() end return M -- Un altro file può usare le funzionalità di mod.lua: local mod = require('mod') -- Esegue il file mod.lua. -- require è il modo standard per includere moduli. -- require agisce come: (se non in cache; vedi sotto) local mod = (function () end)() -- È come se mod.lua fosse il corpo di una funzione, così che -- le variabili locali dentro mod.lua sono invisibili all'esterno. -- Questo funziona perché mod qui = M in mod.lua: mod.sayHello() -- Stampa: Perbacco, ciao Hrunkner -- Questo è sbagliato; sayMyName esiste solo in mod.lua: mod.sayMyName() -- errore -- I valori di ritorno di require sono messi in cache così un file -- viene eseguito al massimo una volta, anche se richiesto più volte. -- Supponiamo che mod2.lua contenga "print('Hi!')". local a = require('mod2') -- Stampa Hi! local b = require('mod2') -- Non stampa; a=b. -- dofile è come require senza cache: dofile('mod2.lua') --> Hi! dofile('mod2.lua') --> Hi! (lo esegue di nuovo) -- loadfile carica un file lua ma non lo esegue ancora. f = loadfile('mod2.lua') -- Chiama f() per eseguirlo. -- load è loadfile per le stringhe. -- (loadstring è deprecato, usa load al suo posto) g = load('print(343)') -- Restituisce una funzione. g() -- Stampa 343; nulla era stato stampato prima di ora. --]] ``` ## Comunità Se hai bisogno di supporto unisciti alla [mailing list ufficiale di Lua](https://www.lua.org/lua-l.html), al [canale IRC](http://lua-users.org/wiki/IrcChannel), o al [forum](https://luaforum.com). ## Riferimento in italiano Ho trovato questo [Lua manuale italiano PDF](https://www.vittal.it/wp-content/uploads/2023/03/lua.pdf) che puo essere utile. ## Riferimenti originali Ero entusiasta di imparare Lua per poter creare giochi con il [motore grafico LÖVE](http://love2d.org/). Questo è il "perché". Ho iniziato con [Lua for programmers di BlackBulletIV](https://ebens.me/posts/lua-for-programmers-part-1/). Poi ho letto il libro ufficiale [Programming in Lua](http://www.lua.org/pil/contents.html). Questo è il "come". Potrebbe essere utile dare un'occhiata alla [Lua short reference](http://lua-users.org/wiki/LuaShortReference) su lua-users.org. Gli argomenti principali non trattati sono le librerie standard: * [`string` library](https://www.google.com/search?q=%5Bhttp://lua-users.org/wiki/StringLibraryTutorial%5D(http://lua-users.org/wiki/StringLibraryTutorial)) * [`table` library](https://www.google.com/search?q=%5Bhttp://lua-users.org/wiki/TableLibraryTutorial%5D(http://lua-users.org/wiki/TableLibraryTutorial)) * [`math` library](https://www.google.com/search?q=%5Bhttp://lua-users.org/wiki/MathLibraryTutorial%5D(http://lua-users.org/wiki/MathLibraryTutorial)) * [`io` library](https://www.google.com/search?q=%5Bhttp://lua-users.org/wiki/IoLibraryTutorial%5D(http://lua-users.org/wiki/IoLibraryTutorial)) * [`os` library](https://www.google.com/search?q=%5Bhttp://lua-users.org/wiki/OsLibraryTutorial%5D(http://lua-users.org/wiki/OsLibraryTutorial)) Tra l'altro, l'intero file è codice Lua valido; salvalo come learn.lua ed eseguilo con "`lua learn.lua`" ! Questo è stato scritto originariamente per tylerneylon.com, ed è disponibile anche come [GitHub gist](https://gist.github.com/tylerneylon/5853042). Buon divertimento con Lua! --- ================================================ FILE: it/markdown.md ================================================ --- contributors: - ["Dan Turkel", "http://danturkel.com/"] - ["Jacob Ward", "http://github.com/JacobCWard/"] translators: - ["Jacopo Andrea Giola", "http://geekpanda.net"] - ["Ale46", "https://github.com/Ale46"] --- Markdown è stato creato da John Gruber nel 2004. Il suo scopo è quello di essere una sintassi facile da leggere e scrivere, e che può essere convertita in HTML (ad oggi anche in molti altri formati). Markdown varia nelle sue implementazioni da un parser all'altro. Questa guida cercherà di chiarire quali caratteristiche esistono a livello globale o quando sono disponibili solo per un determinato parser. ## Elementi HTML Markdown è un superset di HTML, quindi ogni file HTML è a sua volta un file Markdown valido. ```md ``` ## Titoli Potete creare gli elementi HTML da `

` a `

` facilmente, basta che inseriate un egual numero di caratteri cancelletto (#) prima del testo che volete all'interno dell'elemento ```md # Questo è un

## Questo è un

### Questo è un

#### Questo è un

##### Questo è un

###### Questo è un
``` Markdown inoltre fornisce due alternative per indicare gli elementi h1 e h2 ```md Questo è un h1 ============== Questo è un h2 -------------- ``` ## Stili di testo semplici Il testo può essere stilizzato in corsivo o grassetto usando markdown ```md *Questo testo è in corsivo.* _Come pure questo._ **Questo testo è in grassetto.** __Come pure questo.__ ***Questo testo è stilizzato in entrabmi i modi.*** **_Come questo!_** *__E questo!__* ``` In GitHub Flavored Markdown, che è utilizzato per renderizzare i file markdown su GitHub, è presente anche lo stile barrato: ```md ~~Questo testo è barrato.~~ ``` ## Paragrafi ```md I paragrafi sono una o più linee di testo adiacenti separate da una o più righe vuote. Questo è un paragrafo. Sto scrivendo in un paragrafo, non è divertente? Ora sono nel paragrafo 2. Anche questa linea è nel paragrafo 2! Qui siamo nel paragrafo 3! ``` Se volete inserire l'elemento HTML `
`, potete terminare la linea con due o più spazi e poi iniziare un nuovo paragrafo. ```md Questa frase finisce con due spazi (evidenziatemi per vederli). C'è un
sopra di me! ``` Le citazioni sono semplici da inserire, basta usare il carattere >. ```md > Questa è una citazione. Potete > mandare a capo manualmente le linee e inserire un `>` prima di ognuna, oppure potete usare una sola linea e lasciare che vada a capo automaticamente. > Non c'è alcuna differenza, basta che iniziate ogni riga con `>`. > Potete utilizzare anche più di un livello >> di indentazione! > Quanto è comodo? ``` ## Liste Le liste non ordinate possono essere inserite usando gli asterischi, il simbolo più o dei trattini ```md * Oggetto * Oggetto * Altro oggetto oppure + Oggetto + Oggetto + Un altro oggetto oppure - Oggetto - Oggetto - Un ultimo oggetto ``` Le liste ordinate invece, sono inserite con un numero seguito da un punto. ```md 1. Primo oggetto 2. Secondo oggetto 3. Terzo oggetto ``` Non dovete nemmeno mettere i numeri nell'ordine giusto, markdown li visualizzerà comunque nell'ordine corretto, anche se potrebbe non essere una buona idea. ```md 1. Primo oggetto 1. Secondo oggetto 1. Terzo oggetto ``` (Questa lista verrà visualizzata esattamente come quella dell'esempio prima) Potete inserire anche sotto liste ```md 1. Primo oggetto 2. Secondo oggetto 3. Terzo oggetto * Sotto-oggetto * Sotto-oggetto 4. Quarto oggetto ``` Sono presenti anche le task list. In questo modo è possibile creare checkbox in HTML. ```md I box senza la 'x' sono checkbox HTML ancora da completare. - [ ] Primo task da completare. - [ ] Secondo task che deve essere completato. Il box subito sotto è una checkbox HTML spuntata. - [x] Questo task è stato completato. ``` ## Estratti di codice Potete inserire un estratto di codice (che utilizza l'elemento ``) indentando una linea con quattro spazi oppure con un carattere tab. ```md Questa è una linea di codice Come questa ``` Potete inoltre inserire un altro tab (o altri quattro spazi) per indentare il vostro codice ```md my_array.each do |item| puts item end ``` Codice inline può essere inserito usando il carattere backtick ` ```md Giovanni non sapeva neppure a cosa servisse la funzione `go_to()`! ``` In GitHub Flavored Markdown, potete inoltre usare una sintassi speciale per il codice ````md ```ruby def foobar puts "Hello world!" end ``` ```` Se usate questa sintassi, il testo non richiederà di essere indentato, inoltre GitHub userà l'evidenziazione della sintassi del linguaggio specificato dopo i ``` iniziali ## Linea orizzontale Le linee orizzontali (`
`) sono inserite facilmente usanto tre o più asterischi o trattini, con o senza spazi. ```md *** --- - - - **************** ``` ## Links Una delle funzionalità migliori di markdown è la facilità con cui si possono inserire i link. Mettete il testo da visualizzare fra parentesi quadre [] seguite dall'url messo fra parentesi tonde () ```md [Cliccami!](http://test.com/) ``` Potete inoltre aggiungere al link un titolo mettendolo fra doppi apici dopo il link ```md [Cliccami!](http://test.com/ "Link a Test.com") ``` La sintassi funziona anche con i path relativi. ```md [Vai a musica](/music/). ``` Markdown supporta inoltre anche la possibilità di aggiungere i link facendo riferimento ad altri punti del testo. ```md [Apri questo link][link1] per più informazioni! [Guarda anche questo link][foobar] se ti va. [link1]: http://test.com/ "Bello!" [foobar]: http://foobar.biz/ "Va bene!" ``` l titolo può anche essere inserito in apici singoli o in parentesi, oppure omesso interamente. Il riferimento può essere inserito in un punto qualsiasi del vostro documento e l'identificativo del riferimento può essere lungo a piacere a patto che sia univoco. Esiste anche un "identificativo implicito" che vi permette di usare il testo del link come id. ```md [Questo][] è un link. [Questo]: http://thisisalink.com/ ``` Ma non è comunemente usato. ## Immagini Le immagini sono inserite come i link ma con un punto esclamativo inserito prima delle parentesi quadre! ```md ![Questo è il testo alternativo per l'immagine](http://imgur.com/myimage.jpg "Il titolo opzionale") ``` E la modalità a riferimento funziona esattamente come ci si aspetta ```md ![Questo è il testo alternativo.][myimage] [myimage]: relative/urls/cool/image.jpg "Se vi serve un titolo, lo mettete qui" ``` ## Miscellanea ### Auto link ```md è equivalente ad [http://testwebsite.com/](http://testwebsite.com/) ``` ### Auto link per le email ```md ``` ### Caratteri di escaping ```md Voglio inserire *questo testo circondato da asterischi* ma non voglio che venga renderizzato in corsivo, quindi lo inserirò così: \*questo testo è circondato da asterischi\*. ``` ### Combinazioni di tasti In GitHub Flavored Markdown, potete utilizzare il tag `` per raffigurare i tasti della tastiera. ```md Il tuo computer è crashato? Prova a premere Ctrl+Alt+Canc ``` ### Tabelle Le tabelle sono disponibili solo in GitHub Flavored Markdown e sono leggeremente complesse, ma se proprio volete inserirle fate come segue: ```md | Col1 | Col2 | Col3 | | :------------------- | :------: | -----------------: | | Allineato a sinistra | Centrato | Allineato a destra | | blah | blah | blah | ``` oppure, per lo stesso risultato ```md Col 1 | Col2 | Col3 :-- | :-: | --: È una cosa orrenda | fatela | finire in fretta ``` --- Per altre informazioni, leggete il post ufficiale di John Gruber sulla sintassi [qui](https://daringfireball.net/projects/markdown/syntax) e il magnifico cheatsheet di Adam Pritchard [qui](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). ================================================ FILE: it/matlab.md ================================================ --- contributors: - ["mendozao", "http://github.com/mendozao"] - ["jamesscottbrown", "http://jamesscottbrown.com"] - ["Colton Kohnke", "http://github.com/voltnor"] translators: - ["Samuele Gallerani", "http://github.com/fontealpina"] --- MATLAB sta per MATrix LABoratory ed è un potente linguaggio per il calcolo numerico comunemente usato in ingegneria e matematica. ```matlab % I commenti iniziano con il segno percentuale. %{ I commenti multilinea assomigliano a qualcosa del genere %} % i comandi possono essere spezzati su più linee, usando '...': a = 1 + 2 + ... + 4 % i comandi possono essere passati al sistema operativo !ping google.com who % Mostra tutte le variabili in memoria whos % Mostra tutte le variabili in memoria, con i loro tipi clear % Cancella tutte le tue variabili dalla memoria clear('A') % Cancella una particolare variabile openvar('A') % Apre la variabile in un editor di variabile clc % Cancella il contenuto della Command Window diary % Attiva il log della Command Window su file ctrl-c % Interrompe il calcolo corrente edit('myfunction.m') % Apre la funzione/script nell'editor type('myfunction.m') % Stampa il codice della funzione/script sulla Command Window profile on % Attiva la profilazione del codice profile off % Disattiva la profilazione del codice profile viewer % Apre il profilatore help comando % Mostra la documentazione di comando sulla Command Window doc comando % Mostra la documentazione di comando sulla Help Window lookfor comando % Cerca comando nella prima linea di commento di tutte le funzioni lookfor comando -all % Cerca comando in tutte le funzioni % Formattazione dell'output format short % 4 decimali in un numero float format long % 15 decimali format bank % Solo due cifre decimali - per calcoli finaziari fprintf('text') % Stampa "text" a terminale disp('text') % Stampa "text" a terminale % Variabili ed espressioni miaVariabile = 4 % Il pannello Workspace mostra la nuova variabile creata miaVariabile = 4; % Il punto e virgola evita che l'output venga stampato sulla Command Window 4 + 6 % ans = 10 8 * myVariable % ans = 32 2 ^ 3 % ans = 8 a = 2; b = 3; c = exp(a)*sin(pi/2) % c = 7.3891 % La chiamata di funzioni può essere fatta in due modi differenti: % Sintassi standard di una funzione: load('myFile.mat', 'y') % argomenti tra parentesi, separati da virgole % Sintassi di tipo comando: load myFile.mat y % Non ci sono parentesi e gli argometi sono separati da spazi % Notare la mancanza di apici nella sintassi di tipo comando: gli input sono sempre passati come % testo letterale - non è possibile passare valori di variabili. Inoltre non può ricevere output: [V,D] = eig(A); % Questa non ha una forma equivalente con una sintassi di tipo comando [~,D] = eig(A); % Se si vuole solo D e non V % Operatori logici 1 > 5 % ans = 0 10 >= 10 % ans = 1 3 ~= 4 % Not equal to -> ans = 1 3 == 3 % equal to -> ans = 1 3 > 1 && 4 > 1 % AND -> ans = 1 3 > 1 || 4 > 1 % OR -> ans = 1 ~1 % NOT -> ans = 0 % Gli operatori logici possono essere applicati alle matrici: A > 5 % Per ogni elemento, se la condizione è vera, quell'elemento vale 1 nella matrice risultante A( A > 5 ) % Restituisce un vettore contenente gli elementi in A per cui la condizione è vera % Stringhe a = 'MyString' length(a) % ans = 8 a(2) % ans = y [a,a] % ans = MyStringMyString % Celle a = {'one', 'two', 'three'} a(1) % ans = 'one' - ritorna una cella char(a(1)) % ans = one - ritorna una stringa % Strutture A.b = {'one','two'}; A.c = [1 2]; A.d.e = false; % Vettori x = [4 32 53 7 1] x(2) % ans = 32, gli indici in MATLAB iniziano da 1, non da 0 x(2:3) % ans = 32 53 x(2:end) % ans = 32 53 7 1 x = [4; 32; 53; 7; 1] % Vettore colonna x = [1:10] % x = 1 2 3 4 5 6 7 8 9 10 % Matrici A = [1 2 3; 4 5 6; 7 8 9] % Le righe sono separate da punto e virgola, mentre gli elementi sono separati da spazi % A = % 1 2 3 % 4 5 6 % 7 8 9 A(2,3) % ans = 6, A(row, column) A(6) % ans = 8 % (implicitamente concatena le colonne in un vettore, e quindi gli indici sono riferiti al vettore) A(2,3) = 42 % Aggiorna riga 2 colonna 3 con 42 % A = % 1 2 3 % 4 5 42 % 7 8 9 A(2:3,2:3) % Crea una nuova matrice a partire da quella precedente %ans = % 5 42 % 8 9 A(:,1) % Tutte le righe nella colonna 1 %ans = % 1 % 4 % 7 A(1,:) % Tutte le colonne in riga 1 %ans = % 1 2 3 [A ; A] % Concatenazione di matrici (verticalmente) %ans = % 1 2 3 % 4 5 42 % 7 8 9 % 1 2 3 % 4 5 42 % 7 8 9 % è equivalente a vertcat(A,A); [A , A] % Concatenazione di matrici (orrizontalmente) %ans = % 1 2 3 1 2 3 % 4 5 42 4 5 42 % 7 8 9 7 8 9 % è equivalente a horzcat(A,A); A(:, [3 1 2]) % Ripristina le colonne della matrice originale %ans = % 3 1 2 % 42 4 5 % 9 7 8 size(A) % ans = 3 3 A(1, :) =[] % Rimuove la prima riga della matrice A(:, 1) =[] % Rimuove la prima colonna della matrice transpose(A) % Traspone la matrice, equivale a: A.' ctranspose(A) % Trasposizione hermitiana della matrice % (ovvero il complesso coniugato di ogni elemento della matrice trasposta) % Aritmetica Elemento per Elemento vs. Artimetica Matriciale % Gli operatori aritmetici da soli agliscono sull'intera matrice. Quando sono preceduti % da un punto, allora agiscono su ogni elemento. Per esempio: A * B % Moltiplicazione matriciale A .* B % Moltiplica ogni elemento di A per il corrispondente elemento di B % Ci sono diverse coppie di funzioni, in cui una agisce su ogni elemento, e % l'altra (il cui nome termina con m) agisce sull'intera matrice. exp(A) % Calcola l'esponenziale di ogni elemento expm(A) % Calcola la matrice esponenziale sqrt(A) % Calcola la radice quadrata di ogni elemento sqrtm(A) % Trova la matrice di cui A nè è la matrice quadrata % Plot di grafici x = 0:.10:2*pi; % Crea un vettore che inizia a 0 e termina 2*pi con incrementi di .1 y = sin(x); plot(x,y) xlabel('x axis') ylabel('y axis') title('Plot of y = sin(x)') axis([0 2*pi -1 1]) % x range da 0 a 2*pi, y range da -1 a 1 plot(x,y1,'-',x,y2,'--',x,y3,':') % Per stampare più funzioni in unico plot legend('Line 1 label', 'Line 2 label') % Aggiunge un etichetta con il nome delle curve % Metodo alternativo per stampare funzioni multiple in un unico plot. % mentre 'hold' è on, i comandi sono aggiunti al grafico esistene invece di sostituirlo plot(x, y) hold on plot(x, z) hold off loglog(x, y) % Un plot di tipo log-log semilogx(x, y) % Un plot con asse x logaritmico semilogy(x, y) % Un plot con asse y logaritmico fplot (@(x) x^2, [2,5]) % Stampa la funzione x^2 da x=2 a x=5 grid on % Mostra la griglia, disattivare con 'grid off' axis square % Rende quadrata la regione individuata dagli assi axis equal % Iposta l'aspetto del grafico in modo che le unità degli assi siano le stesse scatter(x, y); % Scatter-plot hist(x); % Istogramma z = sin(x); plot3(x,y,z); % Stampa una linea 3D pcolor(A) % Heat-map di una matrice: stampa una griglia di rettangoli, colorati in base al valore contour(A) % Contour plot di una matrice mesh(A) % Stampa come una superfice di mesh h = figure % Crea un nuovo oggetto figura, con handle f figure(h) % Rende la figura corrispondente al handle h la figura corrente close(h) % Chiude la figura con handle h close all % Chiude tutte le figure close % Chiude la figura corrente shg % Riutilizza una finestra grafica già esistente, o se necessario ne crea una nuova clf clear % Pulisce la figura corrente, e resetta le proprietà della figura % Le proprietà possono essere impostate e modificate attraverso l'handle della figura. % Si può salvare l'handle della figura quando viene creata. % La funzione gcf restituisce un handle alla figura attuale. h = plot(x, y); % Si può salvare un handle della figura quando viene creata set(h, 'Color', 'r') % 'y' yellow; 'm' magenta, 'c' cyan, 'r' red, 'g' green, 'b' blue, 'w' white, 'k' black set(h, 'LineStyle', '--') % '--' linea continua, '---' tratteggiata, ':' puntini, '-.' trattino-punto, 'none' nessuna linea get(h, 'LineStyle') % La funzione gca restituisce un handle degli assi della figura corrente set(gca, 'XDir', 'reverse'); % Inverte la direzione dell'asse x % Per creare una figura che contiene diverse sottofigure, usare subplot subplot(2,3,1); % Seleziona la prima posizione in una griglia 2 per 3 di sottofigure plot(x1); title('First Plot') % Stampa qualcosa in questa posizione subplot(2,3,2); % Seleziona la seconda posizione nella griglia plot(x2); title('Second Plot') % Stampa qualcosa in questa posizione % Per usare funzioni o script, devono essere nel tuo path o nella directory corrente path % Mostra il path corrente addpath /path/to/dir % Aggiunge al path rmpath /path/to/dir % Rimuove dal path cd /path/to/move/into % Cambia directory % Le variabili possono essere salvate in file .mat save('myFileName.mat') % Salva le variabili nel tuo Workspace load('myFileName.mat') % Carica variabili salvate nel tuo Workspace % M-file Scripts % I file di script sono file esterni che contengono una sequenza di istruzioni. % Permettono di evitare di scrivere ripetutamente lo stesso codice nella Command Window % Hanno estensione .m % M-file Functions % Come gli script, hanno la stessa estensione .m % Ma possono accettare argomenti di input e restituire un output. % Inoltre, hanno un proprio workspace (differente scope delle variabili). % Il nome della funzione dovrebbe coincidere con il nome del file (quindi salva questo esempio come double_input.m). % 'help double_input.m' restituisce i commenti sotto alla linea iniziale della funzione function output = double_input(x) %double_input(x) restituisce il doppio del valore di x output = 2*x; end double_input(6) % ans = 12 % Si possono anche avere sottofunzioni e funzioni annidate. % Le sottofunzioni sono nello stesso file della funzione primaria, e possono solo essere % chiamate da funzioni nello stesso file. Le funzioni annidate sono definite dentro ad altre % funzioni, e hanno accesso ad entrambi i workspace. % Se si vuole creare una funzione senza creare un nuovo file si può usare una % funzione anonima. Utile quando si vuole definire rapidamente una funzione da passare ad % un'altra funzione (es. stampa con fplot, valutare un integrale indefinito % con quad, trovare le radici con fzenzro, o trovare il minimo con fminsearch). % Esempio che restituisce il quadrato del proprio input, assegnato all'handle sqr: sqr = @(x) x.^2; sqr(10) % ans = 100 doc function_handle % scopri di più % Input dell'utente a = input('Enter the value: ') % Ferma l'esecuzione del file e cede il controllo alla tastiera: l'utente può esaminare % o cambiare variabili. Digita 'return' per continuare l'esecuzione, o 'dbquit' per uscire keyboard % Importarare dati (anche xlsread/importdata/imread per excel/CSV/image file) fopen(filename) % Output disp(a) % Stampa il valore della variabile a disp('Hello World') % Stampa una stringa fprintf % Stampa sulla Command Window con più controllo % Istruzioni condizionali (le parentesi sono opzionali, ma un buon stile) if (a > 15) disp('Maggiore di 15') elseif (a == 23) disp('a è 23') else disp('nessuna condizione verificata') end % Cicli % NB. Ciclare su elementi di vettori/matrici è lento! % Dove possibile, usa funzioni che agiscono sull'intero vettore/matrice for k = 1:5 disp(k) end k = 0; while (k < 5) k = k + 1; end % Misurare la durata dell'esecuzione del codice: 'toc' stampa il tempo trascorso da quando 'tic' è stato chiamato tic A = rand(1000); A*A*A*A*A*A*A; toc % Connessione a un Database MySQL dbname = 'database_name'; username = 'root'; password = 'root'; driver = 'com.mysql.jdbc.Driver'; dburl = ['jdbc:mysql://localhost:8889/' dbname]; javaclasspath('mysql-connector-java-5.1.xx-bin.jar'); % xx dipende dalla versione, download disponibile all'indirizzo http://dev.mysql.com/downloads/connector/j/ conn = database(dbname, username, password, driver, dburl); sql = ['SELECT * from table_name where id = 22'] % Esempio istruzione sql a = fetch(conn, sql) % conterra i tuoi dati % Funzioni matematiche comuni sin(x) cos(x) tan(x) asin(x) acos(x) atan(x) exp(x) sqrt(x) log(x) log10(x) abs(x) min(x) max(x) ceil(x) floor(x) round(x) rem(x) rand % Numeri pseudocasuali uniformemente distribuiti randi % Numeri interi pseudocasuali uniformemente distrubuiti randn % Numeri pseudocasuali distrbuiti normalmente % Costanti comuni pi NaN inf % Risolvere equazioni matriciali % Gli operatori \ e / sono equivalenti alle funzioni mldivide e mrdivide x=A\b % Risolve Ax=b. Più veloce e più accurato numericamente rispetto ad usare inv(A)*b. x=b/A % Risolve xA=b inv(A) % Calcola la matrice inversa pinv(A) % Calcola la matrice pseudo-inversa % Funzioni comuni su matrici zeros(m,n) % Matrice m x n di zeri ones(m,n) % Matrice m x n di uni diag(A) % Estrae gli elementi della diagonale della matrice A diag(x) % Costruisce una matrice con elementi diagonali uguali agli elementi di x, e zero negli altri elementi eye(m,n) % Matrice identità linspace(x1, x2, n) % Ritorna n punti equamente distanziati, con minimo x1 e massimo x2 inv(A) % Matrice inversa di A det(A) % Determinante di A eig(A) % Autovalori e autovettori di A trace(A) % Traccia della matrice - equivalente a sum(diag(A)) isempty(A) % Verifica se l'array è vuoto all(A) % Verifica se tutti gli elementi sono nonzero o veri any(A) % Verifica se almento un elemento è nonzero o vero isequal(A, B) % Verifica l'uguaglianza di due array numel(A) % Numero di elementi nella matrice triu(x) % Ritorna la parte triangolare superiore di x tril(x) % Ritorna la parte triangolare inferiore di x cross(A,B) % Ritorna il prodotto vettoriale dei vettori A e B dot(A,B) % Ritorna il prodotto scalare di due vettori (devono avere la stessa lunghezza) transpose(A) % Ritorna la trasposta di A fliplr(A) % Capovolge la matrice da sinistra a destra flipud(A) % Capovolge la matrice da sopra a sotto % Fattorizzazione delle matrici [L, U, P] = lu(A) % Decomposizione LU: PA = LU, L è il triangolo inferiore, U è il triangolo superiore, P è la matrice di permutazione [P, D] = eig(A) % Auto-decomposizione: AP = PD, le colonne di P sono autovettori e gli elementi sulle diagonali di D sono autovalori [U,S,V] = svd(X) % SVD: XV = US, U e V sono matrici unitarie, S ha gli elementi della diagonale non negativi in ordine decrescente % Funzioni comuni su vettori max % elemento più grande min % elemento più piccolo length % lunghezza del vettore sort % ordina in modo crescente sum % somma degli elementi prod % prodotto degli elementi mode % valore moda median % valore mediano mean % valore medio std % deviazione standard perms(x) % lista tutte le permutazioni di elementi di x % Classi % MATLAB supporta la programmazione orientata agli oggetti. % La classe deve essere messa in un file con lo stesso nome della classe e estensione .m % Per iniziare, creiamo una semplice classe per memorizzare waypoint GPS % Inizio WaypointClass.m classdef WaypointClass % Il nome della classe. properties % Le proprietà della classe funzionano come Strutture latitude longitude end methods % Questo metodo che ha lo stesso nome della classe è il costruttore function obj = WaypointClass(lat, lon) obj.latitude = lat; obj.longitude = lon; end % Altre funzioni che usano l'oggetto Waypoint function r = multiplyLatBy(obj, n) r = n*[obj.latitude]; end % Se si vuole aggiungere due oggetti Waypoint insieme senza chiamare % una funzione speciale si può sovradefinire una funzione aritmetica di MATLAB come questa: function r = plus(o1,o2) r = WaypointClass([o1.latitude] +[o2.latitude], ... [o1.longitude]+[o2.longitude]); end end end % End WaypointClass.m % Si può creare un oggetto della classe usando un costruttore a = WaypointClass(45.0, 45.0) % Le proprietà della classe si comportano esattamente come una Struttura MATLAB. a.latitude = 70.0 a.longitude = 25.0 % I metodi possono essere chiamati allo stesso modo delle funzioni ans = multiplyLatBy(a,3) % Il metodo può anche essere chiamato usando una notazione con punto. In questo caso, l'oggetto % non necessita di essere passato al metodo. ans = a.multiplyLatBy(a,1/3) % Le funzioni MATLAB possono essere sovradefinite per gestire oggetti. % Nel metodo sopra, è stato sovradefinito come MATLAB gestisce % l'addizione di due oggetti Waypoint. b = WaypointClass(15.0, 32.0) c = a + b ``` ## Di più su MATLAB * Sito ufficiale [http://http://www.mathworks.com/products/matlab/](http://www.mathworks.com/products/matlab/) * Forum ufficiale di MATLAB: [http://www.mathworks.com/matlabcentral/answers/](http://www.mathworks.com/matlabcentral/answers/) ================================================ FILE: it/pcre.md ================================================ --- contributors: - ["Sachin Divekar", "http://github.com/ssd532"] translators: - ["Christian Grasso", "https://grasso.io"] --- Un'espressione regolare (regex o regexp in breve) è una speciale stringa utilizzata per definire un pattern, ad esempio per cercare una sequenza di caratteri; ad esempio, `/^[a-z]+:/` può essere usato per estrarre `http:` dall'URL `http://github.com/`. PCRE (Perl Compatible Regular Expressions) è una libreria per i regex in C. La sintassi utilizzata per le espressioni è molto simile a quella di Perl, da cui il nome. Si tratta di una delle sintassi più diffuse per la scrittura di regex. Esistono due tipi di metacaratteri (caratteri con una funzione speciale): * Caratteri riconosciuti ovunque tranne che nelle parentesi quadre ``` \ carattere di escape ^ cerca all'inizio della stringa (o della riga, in modalità multiline) $ cerca alla fine della stringa (o della riga, in modalità multiline) . qualsiasi carattere eccetto le newline [ inizio classe di caratteri | separatore condizioni alternative ( inizio subpattern ) fine subpattern ? quantificatore "0 o 1" * quantificatore "0 o più" + quantificatore "1 o più" { inizio quantificatore numerico ``` * Caratteri riconosciuti nelle parentesi quadre ``` \ carattere di escape ^ nega la classe se è il primo carattere - indica una serie di caratteri [ classe caratteri POSIX (se seguita dalla sintassi POSIX) ] termina la classe caratteri ``` PCRE fornisce inoltre delle classi di caratteri predefinite: ``` \d cifra decimale \D NON cifra decimale \h spazio vuoto orizzontale \H NON spazio vuoto orizzontale \s spazio \S NON spazio \v spazio vuoto verticale \V NON spazio vuoto verticale \w parola \W "NON parola" ``` ## Esempi Utilizzeremo la seguente stringa per i nostri test: ``` 66.249.64.13 - - [18/Sep/2004:11:07:48 +1000] "GET /robots.txt HTTP/1.0" 200 468 "-" "Googlebot/2.1" ``` Si tratta di una riga di log del web server Apache. | Regex | Risultato | Commento | | :---- | :-------------- | :------ | | `GET` | GET | Cerca esattamente la stringa "GET" (case sensitive) | | `\d+.\d+.\d+.\d+` | 66.249.64.13 | `\d+` identifica uno o più (quantificatore `+`) numeri [0-9], `\.` identifica il carattere `.` | | `(\d+\.){3}\d+` | 66.249.64.13 | `(\d+\.){3}` cerca il gruppo (`\d+\.`) esattamente 3 volte. | | `\[.+\]` | [18/Sep/2004:11:07:48 +1000] | `.+` identifica qualsiasi carattere, eccetto le newline; `.` indica un carattere qualsiasi | | `^\S+` | 66.249.64.13 | `^` cerca all'inizio della stringa, `\S+` identifica la prima stringa di caratteri diversi dallo spazio | | `\+[0-9]+` | +1000 | `\+` identifica il carattere `+`. `[0-9]` indica una cifra da 0 a 9. L'espressione è equivalente a `\+\d+` | ## Altre risorse [Regex101](https://regex101.com/) - tester per le espressioni regolari ================================================ FILE: it/php-composer.md ================================================ --- contributors: - ["Brett Taylor", "https://github.com/glutnix"] translators: - ["Agostino Fiscale", "https://github.com/agostinofiscale"] --- [Composer](https://getcomposer.org/) è uno strumento che ti aiuta a gestire le dipendenze in PHP. Ti permette di dichiarare le librerie utilizzate dal tuo progetto e di installarle/aggiornarle per te. # Installazione ```sh # Se installi l'eseguibile in una cartella... curl -sS https://getcomposer.org/installer | php # ...dovrai utilizzare questo approccio, invocando Composer in questo modo: php composer.phar about # Se installi l'eseguibile nella directory ~/bin/composer # Nota: assicurati che ~/bin si trovi nella variabile di ambiente PATH curl -sS https://getcomposer.org/installer | php -- --install-dir=~/bin --filename=composer ``` Gli utenti Windows possono seguire le istruzioni per [installarlo su Windows](https://getcomposer.org/doc/00-intro.md#installation-windows). ## Assicuriamoci che il tutto abbia funzionato correttamente ```sh # Controlla la versione e la lista delle opzioni disponibili composer # Ottieni ulteriori informazioni riguardanti le opzioni composer help require # Controlla se Composer ha tutto il necessario per funzionare come si deve # e se è aggiornato correttamente all'ultima versione disponibile. composer diagnose composer diag # alias # Aggiorna Composer all'ultima versione disponibile composer self-update composer self # alias ``` # Cominciamo ad usare Composer Composer memorizza le dipendenze necessarie nel file `composer.json`. Puoi editare questo file manualmente, ma è meglio che lasci che Composer se ne occupi per te. ```sh # Crea un nuovo progetto nella cartella attuale composer init # ti verranno chieste delle domande interrative riguardanti il tuo progetto. # Puoi evitare di rispondere almeno che tu non stia sviluppando altri progetti # che che possano dipendere da questo. # Se il file composer.json esiste già, scarichera' le dipendenze necessarie composer install # Scarica le dipendenze necessarie per l'ambiente di produzione composer install --no-dev # Aggiunge una dipendenza per l'ambiente di produzione composer require guzzlehttp/guzzle # automaticamente selezionera' l'ultima versione, la scarichera' e la aggiungera' # come dipendenza nell'apposito campo del file composer.json. composer require guzzlehttp/guzzle:6.0.* # scarichera' l'ultima versione disponibile corrispondente al pattern (es. 6.0.2) # e lo aggiungera' come dipendenza nell'apposito campo del file composer.json. composer require --dev phpunit/phpunit:~4.5.0 # aggiungera' la dipendenza nell'ambiente di sviluppo utilizzando l'ultima versione # disponibile nel range >=4.5.0 e < 4.6.0. composer require-dev phpunit/phpunit:^4.5.0 # aggiungera' la dipendenza nell'ambiente di sviluppo utilizzando l'ultima versione # disponibile nel range >=4.5.0 and < 5.0. # Per ulteriori dettagli riguardo le versioni, vedi [la documentazione di Composer sulle versioni](https://getcomposer.org/doc/articles/versions.md) per ulteriori dettagli # Per vedere quali pacchetti sono installabili e quali sono gia' stati installati composer show # Per vedere solo quali pacchetti sono gia' stati installati composer show --installed # Per trovare una dipendenza con 'mailgun' nel suo nome o nella descrizione. composer search mailgun ``` [Packagist.org](https://packagist.org/) è il repository principale per i pacchetti di Composer. Cerca qui pacchetti di terze-parti utili per il tuo progetto. ## `composer.json` vs `composer.lock` Il file `composer.json` memorizza la versione che si preferisce per ogni dipendenza, insieme ad altre informazioni. Il file `composer.lock` memorizza quale versione è stata scaricata per ogni dipendenza. Non editare mai questo file. Se includi il file `composer.lock` nella tua repository git, ogni sviluppatore andra' a installare la versione attualmente utilizzata dal tuo progetto per ogni dipendenza. Anche quando una nuova versione è stata rilasciata, Composer andra' a installare la versione registrata nel file lock. ```sh # Se vuoi aggiornare tutte le dipendenze all'ultima versione che corrisponde al pattern descritto composer update # Se vuoi scaricare l'ultima versione di una particolare dipendenza: composer update phpunit/phpunit # Se vuoi cambiare la versione di una una dipendenza, potresti dover rimuovere # quello attualmente selezionato, per poi richiedere quello corretto successivamente, # attraverso i seguenti comandi: composer remove --dev phpunit/phpunit composer require --dev phpunit/phpunit:^5.0 ``` ## Autoloader Composer crea una classe autoloader che puoi richiamare nella tua applicazione. Puoi creare instanze delle classi tramite il loro namespace. ```php require __DIR__ . '/vendor/autoload.php'; $mailgun = new Mailgun\Mailgun("key"); ``` ### PSR-4 Autoloader Puoi aggiungere i tuoi namespace all'autoloader. Nel file `composer.json`, aggiungi il campo "autoload": ```json { "autoload": { "psr-4": {"Acme\\": "src/"} } } ``` Questo dira' all'autoloader di controllare ogni risorsa che corrisponde al namespace `\Acme\` all'interno della cartella `src`. In alternativa puoi usare [PSR-0, una Classmap o una lista di file da includere](https://getcomposer.org/doc/04-schema.md#autoload). Inoltre e' possibile anche utilizzare `autoload-dev` dedicato all'ambiente di sviluppo. Quando aggiungi o modifichi una chiave, dovrai ricompilare l'autoload attraverso: ```sh composer dump-autoload composer dump # alias # Ottimizza i pacchetti PSR0 e PSR4 per essere caricati anche con le classmap. # Sara' lento, ma migliorera' le performance in produzione. composer dump-autoload --optimize --no-dev ``` # La cache di Composer ```sh # Composer utilizzera i pacchetti scaricati anche per i progetti futuri. Per evitare che accada: composer clear-cache ``` # Problemi? ```sh composer diagnose composer self-update composer clear-cache ``` ## Argomenti che non sono stati (ancora) discussi in questo tutorial * Creare e distribuire pacchetti personali su Packagist.org o altrove * Pre- e post- script hooks: eseguire operazioni quando vengono eseguiti degli eventi ### References * [Composer - Dependency Manager for PHP](https://getcomposer.org/) * [Packagist.org](https://packagist.org/) ================================================ FILE: it/pyqt.md ================================================ --- contributors: - ["Nathan Hughes", "https://github.com/sirsharpest"] translators: - ["Ale46", "https://github.com/ale46"] --- **Qt** è un framework ampiamente conosciuto per lo sviluppo di software multipiattaforma che può essere eseguito su varie piattaforme software e hardware con modifiche minime o nulle nel codice, pur avendo la potenza e la velocità delle applicazioni native. Sebbene **Qt** sia stato originariamente scritto in *C++*. Questo è un adattamento sull'introduzione di C ++ a QT di [Aleksey Kholovchuk](https://github.com/vortexxx192), alcuni degli esempi di codice dovrebbero avere la stessa funzionalità che avrebbero se fossero fatte usando pyqt! ```python import sys from PyQt4 import QtGui def window(): # Crea un oggetto applicazione app = QtGui.QApplication(sys.argv) # Crea un widget in cui verrà inserita la nostra etichetta w = QtGui.QWidget() # Aggiungi un'etichetta al widget b = QtGui.QLabel(w) # Imposta del testo per l'etichetta b.setText("Ciao Mondo!") # Fornisce informazioni su dimensioni e posizionamento w.setGeometry(100, 100, 200, 50) b.move(50, 20) # Dai alla nostra finestra un bel titolo w.setWindowTitle("PyQt") # Visualizza tutto w.show() # Esegui ciò che abbiamo chiesto, una volta che tutto è stato configurato sys.exit(app.exec_()) if __name__ == '__main__': window() ``` Per ottenere alcune delle funzionalità più avanzate in **pyqt**, dobbiamo iniziare a cercare di creare elementi aggiuntivi. Qui mostriamo come creare una finestra popup di dialogo, utile per chiedere all'utente di confermare una decisione o fornire informazioni ```python import sys from PyQt4.QtGui import * from PyQt4.QtCore import * def window(): app = QApplication(sys.argv) w = QWidget() # Crea un pulsante e allegalo al widget w b = QPushButton(w) b.setText("Premimi") b.move(50, 50) # Indica a b di chiamare questa funzione quando si fa clic # notare la mancanza di "()" sulla chiamata di funzione b.clicked.connect(showdialog) w.setWindowTitle("PyQt Dialog") w.show() sys.exit(app.exec_()) # Questa funzione dovrebbe creare una finestra di dialogo con un pulsante # che aspetta di essere cliccato e quindi esce dal programma def showdialog(): d = QDialog() b1 = QPushButton("ok", d) b1.move(50, 50) d.setWindowTitle("Dialog") # Questa modalità dice al popup di bloccare il genitore, mentre è attivo d.setWindowModality(Qt.ApplicationModal) # Al click vorrei che l'intero processo finisse b1.clicked.connect(sys.exit) d.exec_() if __name__ == '__main__': window() ``` ================================================ FILE: it/python.md ================================================ --- contributors: - ["Louie Dinh", "http://pythonpracticeprojects.com"] - ["Steven Basart", "http://github.com/xksteven"] - ["Andre Polykanine", "https://github.com/Oire"] - ["Zachary Ferguson", "http://github.com/zfergus2"] - ["evuez", "http://github.com/evuez"] - ["Rommel Martinez", "https://ebzzry.io"] translators: - ["Draio", "http://github.com/Draio/"] - ["Ale46", "http://github.com/Ale46/"] - ["Tommaso Pifferi", "http://github.com/neslinesli93/"] --- Python è stato creato da Guido Van Rossum agli inizi degli anni 90. Oggi è uno dei più popolari linguaggi esistenti. Mi sono innamorato di Python per la sua chiarezza sintattica. E' sostanzialmente pseudocodice eseguibile. Nota: Questo articolo è riferito a Python 3 in modo specifico. Se volete avete la necessità di utilizzare Python 2.7 potete consultarla [qui](../pythonlegacy/) ```python # I commenti su una sola linea iniziano con un cancelletto """ Più stringhe possono essere scritte usando tre ", e sono spesso usate come documentazione """ #################################################### ## 1. Tipi di dati primitivi ed Operatori #################################################### # Ci sono i numeri 3 # => 3 # La matematica è quello che vi aspettereste 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 # Risultato della divisione intera troncata sia in positivo che in negativo 5 // 3 # => 1 5.0 // 3.0 # => 1.0 # works on floats too -5 // 3 # => -2 -5.0 // 3.0 # => -2.0 # Il risultato di una divisione è sempre un numero decimale (float) 10.0 / 3 # => 3.3333333333333335 # Operazione Modulo 7 % 3 # => 1 # Elevamento a potenza (x alla y-esima potenza) 2**3 # => 8 # Forzare le precedenze con le parentesi (1 + 3) * 2 # => 8 # I valori booleani sono primitive del linguaggio (nota la maiuscola) True False # nega con not not True # => False not False # => True # Operatori Booleani # Nota "and" e "or" sono case-sensitive True and False # => False False or True # => True # Note sull'uso di operatori Bool con interi # False è 0 e True è 1 # Non confonderti tra bool(ints) e le operazioni bitwise and/or (&,|) 0 and 2 # => 0 -5 or 0 # => -5 0 == False # => True 2 == True # => False 1 == True # => True -5 != False != True #=> True # Uguaglianza è == 1 == 1 # => True 2 == 1 # => False # Disuguaglianza è != 1 != 1 # => False 2 != 1 # => True # Altri confronti 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # I confronti possono essere concatenati! 1 < 2 < 3 # => True 2 < 3 < 2 # => False # ('is' vs. '==') # 'is' controlla se due variabili si riferiscono allo stesso oggetto # '==' controlla se gli oggetti puntati hanno lo stesso valore. a = [1, 2, 3, 4] # a punta ad una nuova lista [1, 2, 3, 4] b = a # b punta a ciò a cui punta a b is a # => True, a e b puntano allo stesso oggeto b == a # => True, gli oggetti di a e b sono uguali b = [1, 2, 3, 4] # b punta ad una nuova lista [1, 2, 3, 4] b is a # => False, a e b non puntano allo stesso oggetto b == a # => True, gli oggetti di a e b sono uguali # Le stringhe sono create con " o ' "Questa è una stringa." 'Anche questa è una stringa.' # Anche le stringhe possono essere sommate! Ma cerca di non farlo. "Hello " + "world!" # => "Hello world!" # Le stringhe (ma non le variabili contenenti stringhe) possono essere # sommate anche senza '+' "Hello " "world!" # => "Hello world!" # Una stringa può essere considerata come una lista di caratteri "Questa è una stringa"[0] # => 'Q' # Puoi conoscere la lunghezza di una stringa len("Questa è una stringa") # => 20 # .format può essere usato per formattare le stringhe, in questo modo: "{} possono essere {}".format("Le stringhe", "interpolate") # => "Le stringhe possono essere interpolate" # Puoi ripetere gli argomenti di formattazione per risparmiare un po' di codice "{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick") # => "Jack be nimble, Jack be quick, Jack jump over the candle stick" # Puoi usare dei nomi se non vuoi contare gli argomenti "{nome} vuole mangiare {cibo}".format(nome="Bob", cibo="le lasagne") # => "Bob vuole mangiare le lasagne" # Se il tuo codice Python 3 necessita di eseguire codice Python 2.x puoi ancora # utilizzare il vecchio stile di formattazione: "%s possono essere %s nel %s modo" % ("Le stringhe", "interpolate", "vecchio") # => "Le stringhe possono essere interpolate nel vecchio modo" # None è un oggetto None # => None # Non usare il simbolo di uguaglianza "==" per comparare oggetti a None # Usa "is" invece "etc" is None # => False None is None # => True # None, 0, e stringhe/liste/dizionari/tuple vuoti vengono considerati # falsi (False). Tutti gli altri valori sono considerati veri (True). bool(0) # => False bool("") # => False bool([]) # => False bool({}) # => False bool(()) # => False #################################################### ## 2. Variabili e Collections #################################################### # Python ha una funzione per scrivere (sul tuo schermo) print("Sono Python. Piacere di conoscerti!") # => Sono Python. Piacere di conoscerti! # Di default la funzione print() scrive e va a capo aggiungendo un carattere # newline alla fine della stringa. È possibile utilizzare l'argomento opzionale # end per cambiare quest'ultimo carattere aggiunto. print("Hello, World", end="!") # => Hello, World! # Un modo semplice per ricevere dati in input dalla riga di comando variabile_stringa_input = input("Inserisci del testo: ") # Restituisce i dati letti come stringa # Nota: Nelle precedenti vesioni di Python, il metodo input() # era chiamato raw_input() # Non c'è bisogno di dichiarare una variabile per assegnarle un valore # Come convenzione, per i nomi delle variabili, si utilizzano i caratteri # minuscoli separati, se necessario, da underscore some_var = 5 some_var # => 5 # Accedendo ad una variabile non precedentemente assegnata genera un'eccezione. # Dai un'occhiata al Control Flow per imparare di più su come gestire # le eccezioni. some_unknown_var # Genera un errore di nome # if può essere usato come un'espressione # È l'equivalente dell'operatore ternario in C "yahoo!" if 3 > 2 else 2 # => "yahoo!" # Le liste immagazzinano sequenze li = [] # Puoi partire con una lista pre-riempita other_li = [4, 5, 6] # Aggiungere alla fine di una lista con append li.append(1) # li ora è [1] li.append(2) # li ora è [1, 2] li.append(4) # li ora è [1, 2, 4] li.append(3) # li ora è [1, 2, 4, 3] # Rimuovi dalla fine della lista con pop li.pop() # => 3 e li ora è [1, 2, 4] # Rimettiamolo a posto li.append(3) # li ora è [1, 2, 4, 3] di nuovo. # Accedi ad una lista come faresti con un array li[0] # => 1 # Guarda l'ultimo elemento li[-1] # => 3 # Guardare al di fuori dei limiti genera un IndexError li[4] # Genera IndexError # Puoi guardare gli intervalli con la sintassi slice (a fetta). # (E' un intervallo chiuso/aperto per voi tipi matematici.) li[1:3] # => [2, 4] # Ometti l'inizio li[2:] # => [4, 3] # Ometti la fine li[:3] # => [1, 2, 4] # Seleziona ogni seconda voce li[::2] # =>[1, 4] # Copia al contrario della lista li[::-1] # => [3, 4, 2, 1] # Usa combinazioni per fare slices avanzate # li[inizio:fine:passo] # Crea una copia (one layer deep copy) usando la sintassi slices li2 = li[:] # => li2 = [1, 2, 4, 3] ma (li2 is li) risulterà falso. # Rimuovi arbitrariamente elementi da una lista con "del" del li[2] # li è ora [1, 2, 3] # Rimuove la prima occorrenza di un elemento li.remove(2) # Ora li è [1, 3, 4, 5, 6] li.remove(2) # Emette un ValueError, poichè 2 non è contenuto nella lista # Inserisce un elemento all'indice specificato li.insert(1, 2) # li è di nuovo [1, 2, 3, 4, 5, 6] Ritorna l'indice della prima occorrenza dell'elemento fornito li.index(2) # => 1 li.index(7) # Emette un ValueError, poichè 7 non è contenuto nella lista # Puoi sommare le liste # Nota: i valori per li e per other_li non vengono modificati. li + other_li # => [1, 2, 3, 4, 5, 6] # Concatena le liste con "extend()" li.extend(other_li) # Adesso li è [1, 2, 3, 4, 5, 6] # Controlla l'esistenza di un valore in una lista con "in" 1 in li # => True # Esamina la lunghezza con "len()" len(li) # => 6 # Le tuple sono come le liste ma immutabili. tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # Genera un TypeError # Note that a tuple of length one has to have a comma after the last element but # tuples of other lengths, even zero, do not. type((1)) # => type((1,)) # => type(()) # => # Puoi fare tutte queste cose da lista anche sulle tuple len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True # Puoi scompattare le tuple (o liste) in variabili a, b, c = (1, 2, 3) # a è ora 1, b è ora 2 e c è ora 3 d, e, f = 4, 5, 6 # puoi anche omettere le parentesi # Le tuple sono create di default se non usi le parentesi g = 4, 5, 6 # => (4, 5, 6) # Guarda come è facile scambiare due valori e, d = d, e # d è ora 5 ed e è ora 4 # I dizionari memorizzano insiemi di dati indicizzati da nomi arbitrari (chiavi) empty_dict= {} # Questo è un dizionario pre-caricato filled_dict = {"uno": 1, "due": 2, "tre": 3} # Nota: le chiavi dei dizionari devono essere di tipo immutabile. Questo per # assicurare che le chiavi possano essere convertite in calori hash costanti # per un risposta più veloce. invalid_dict = {[1,2,3]: "123"} # => Emette un TypeError: unhashable type: 'list' valid_dict = {(1,2,3):[1,2,3]} # I valori, invece, possono essere di qualunque tipo # Accedi ai valori indicando la chiave tra [] filled_dict["uno"] # => 1 # Puoi ottenere tutte le chiavi di un dizionario con "keys()" # (come oggetto iterabile). Per averle in formato lista è necessario # utilizzare list(). # Nota - Nei dizionari l'ordine delle chiavi non è garantito. # Il tuo risultato potrebbe non essere uguale a questo. list(filled_dict.keys()) # => ["tre", "due", "uno"] # Puoi ottenere tutti i valori di un dizionario con "values()" # (come oggetto iterabile). # Anche in questo caso, er averle in formato lista, è necessario utilizzare list() # Anche in questo caso, come per le chiavi, l'ordine non è garantito list(filled_dict.values()) # => [3, 2, 1] # Controlla l'esistenza delle chiavi in un dizionario con "in" "uno" in filled_dict # => True 1 in filled_dict # => False # Cercando una chiave non esistente genera un KeyError filled_dict["quattro"] # KeyError # Usa il metodo "get()" per evitare KeyError filled_dict.get("uno") # => 1 filled_dict.get("quattro") # => None # Il metodo get supporta un argomento di default quando il valore è mancante filled_dict.get("uno", 4) # => 1 filled_dict.get("quattro", 4) # => 4 # "setdefault()" inserisce un valore per una chiave in un dizionario # solo se la chiave data non è già presente filled_dict.setdefault("cinque", 5) # filled_dict["cinque"] viene impostato a 5 filled_dict.setdefault("cinque", 6) # filled_dict["cinque"] rimane 5 # Aggiungere una coppia chiave->valore a un dizionario filled_dict.update({"quattro":4}) # => {"uno": 1, "due": 2, "tre": 3, "quattro": 4} filled_dict["quattro"] = 4 # un altro modo pe aggiungere a un dizionario # Rimuovi una chiave da un dizionario con del del filled_dict["uno"] # Rimuove la chiave "uno" dal dizionario # Da Python 3.5 puoi anche usare ulteriori opzioni di spacchettamento {'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} {'a': 1, **{'a': 2}} # => {'a': 2} # I set sono come le liste ma non possono contenere doppioni empty_set = set() # Inizializza un "set()" con un dei valori. Sì, sembra un dizionario. some_set = {1, 1, 2, 2, 3, 4} # set_nuovo è {1, 2, 3, 4} # Come le chiavi di un dizionario, gli elementi di un set devono essere # di tipo immutabile invalid_set = {[1], 1} # => Genera un "TypeError: unhashable type: 'list'"" valid_set = {(1,), 1} # Aggiungere uno o più elementi ad un set some_set.add(5) # some_set ora è {1, 2, 3, 4, 5} # Fai intersezioni su un set con & other_set = {3, 4, 5, 6} some_set & other_set # => {3, 4, 5} # Fai unioni su set con | some_set | other_set # => {1, 2, 3, 4, 5, 6} # Fai differenze su set con - {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # Effettua la differenza simmetrica con ^ {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} # Controlla se il set a sinistra contiene quello a destra {1, 2} >= {1, 2, 3} # => False # Controlla se il set a sinistra è un sottoinsieme di quello a destra {1, 2} <= {1, 2, 3} # => True # Controlla l'esistenza in un set con in 2 in some_set # => True 10 in some_set # => False #################################################### ## 3. Control Flow e oggetti Iterabili #################################################### # Dichiariamo una variabile some_var = 5 # Questo è un controllo if. L'indentazione è molto importante in python! # Come convenzione si utilizzano quattro spazi, non la tabulazione. # Il seguente codice stampa "some_var è minore di 10" if some_var > 10: print("some_var è maggiore di 10") elif some_var < 10: # La clausolo elif è opzionale print("some_var è minore di 10") else: # Anche else è opzionale print("some_var è 10.") """ I cicli for iterano sulle liste, cioè ripetono un codice per ogni elemento di una lista. Il seguente codice scriverà: cane è un mammifero gatto è un mammifero topo è un mammifero """ for animale in ["cane", "gatto", "topo"]: # Puoi usare format() per interpolare le stringhe formattate. print("{} è un mammifero".format(animale)) """ "range(numero)" restituisce una lista di numeri da zero al numero dato Il seguente codice scriverà: 0 1 2 3 """ for i in range(4): print(i) """ "range(lower, upper)" restituisce una lista di numeri dal più piccolo (lower) al più grande (upper). Il seguente codice scriverà: 4 5 6 7 """ for i in range(4, 8): print(i) """ "range(lower, upper, step)" rrestituisce una lista di numeri dal più piccolo (lower) al più grande (upper), incrementando del valore step. Se step non è indicato, avrà come valore di default 1. Il seguente codice scriverà: 4 6 """ for i in range(4, 8, 2): print(i) """ I cicli while vengono eseguiti finchè una condizione viene a mancare Il seguente codice scriverà: 0 1 2 3 """ x = 0 while x < 4: print(x) x += 1 # Forma compatta per x = x + 1 # Gestione delle eccezioni con un blocco try/except try: # Usa "raise" per generare un errore raise IndexError("Questo è un IndexError") except IndexError as e: pass # Pass è solo una non-operazione. Solitamente vorrai rimediare all'errore. except (TypeError, NameError): pass # Eccezioni multiple possono essere gestite tutte insieme, se necessario. else: # Clausola opzionale al blocco try/except. Deve essere dopo tutti i blocchi except print("Tutto ok!") # Viene eseguita solo se il codice dentro try non genera eccezioni finally: # Eseguito sempre print("Possiamo liberare risorse qui") # Se ti serve solo un try/finally, per liberare risorse, puoi usare il metodo with with open("myfile.txt") as f: for line in f: print(line) # In Python qualunque oggetto in grado di essere trattato come una # sequenza è definito un oggetto Iterable (itarabile). # L'oggetto restituito da una funzione range è un iterabile. filled_dict = {"uno": 1, "due": 2, "tre": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['uno', 'due', 'tre']). # Questo è un oggetto che implementa la nostra interfaccia Iterable. # È possibile utilizzarlo con i loop: for i in our_iterable: print(i) # Scrive uno, due, tre # Tuttavia non possiamo recuperarne i valori tramite indice. our_iterable[1] # Genera un TypeError # Un oggetto iterabile è in grado di generare un iteratore our_iterator = iter(our_iterable) # L'iteratore è un oggetto che ricorda il suo stato mentro lo si "attraversa" # Possiamo accedere al successivo elemento con "next()". next(our_iterator) # => "uno" # Mantiene il suo stato mentro eseguiamo l'iterazione next(our_iterator) # => "due" next(our_iterator) # => "tre" # Dopo che un iteratore ha restituito tutti i suoi dati, genera # un'eccezione StopIteration next(our_iterator) # Raises StopIteration # Puoi prendere tutti gli elementi di un iteratore utilizzando list(). list(filled_dict.keys()) # => Returns ["one", "two", "three"] #################################################### ## 4. Funzioni #################################################### # Usa "def" per creare nuove funzioni def aggiungi(x, y): print("x è {} e y è {}".format(x, y)) // Scrive i valori formattati in una stringa return x + y # Restituisce la somma dei valori con il metodo return # Chiamare funzioni con parametri aggiungi(5, 6) # => scrive "x è 5 e y è 6" e restituisce 11 # Un altro modo per chiamare funzioni è con parole chiave come argomenti aggiungi(y=6, x=5) # In questo modo non è necessario rispettare l'ordine degli argomenti # Puoi definire funzioni che accettano un numero non definito di argomenti def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) # Puoi definire funzioni che accettano un numero variabile di parole chiave # come argomento, che saranno interpretati come un dizionario usando ** def keyword_args(**kwargs): return kwargs # Chiamiamola per vedere cosa succede keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} # Puoi farle entrambi in una volta, se ti va def all_the_args(*args, **kwargs): print(args) print(kwargs) """ all_the_args(1, 2, a=3, b=4) stampa: (1, 2) {"a": 3, "b": 4} """ # Quando chiami funzioni, puoi fare l'opposto di args/kwargs! # Usa * per sviluppare gli argomenti posizionale ed usa ** per # espandere gli argomenti parola chiave args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # equivalente a foo(1, 2, 3, 4) all_the_args(**kwargs) # equivalente a foo(a=3, b=4) all_the_args(*args, **kwargs) # equivalente a foo(1, 2, 3, 4, a=3, b=4) # Restituire valori multipli (with tuple assignments) def swap(x, y): return y, x # Restituisce valori multipli come tupla senza parentesi # (Nota: le parentesi sono state escluse ma possono essere messe) x = 1 y = 2 x, y = swap(x, y) # => x = 2, y = 1 # (x, y) = swap(x,y) # Le parentesi sono state escluse ma possono essere incluse. # Funzioni - Visibilità delle variabili (variable scope) x = 5 def set_x(num): # La variabile locale x non è la variabile globale x x = num # => 43 print(x) # => 43 def set_global_x(num): global x print(x) # => 5 x = num # la variabile globable x è ora 6 print(x) # => 6 set_x(43) set_global_x(6) # Python ha "first class functions" def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 # Ci sono anche funzioni anonime (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 # È possibile creare "mappe" e "filtri" list(map(add_10, [1, 2, 3])) # => [11, 12, 13] list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] # Possiamo usare le "list comprehensions" per mappe e filtri # Le "list comprehensions" memorizzano l'output come una lista che può essere # di per sé una lista annidata [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # Puoi fare anche la comprensione di set e dizionari {x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### ## 5. Modules #################################################### # Puoi importare moduli import math print(math.sqrt(16)) # => 4.0 # Puoi ottenere specifiche funzione da un modulo from math import ceil, floor print(ceil(3.7)) # => 4.0 print(floor(3.7)) # => 3.0 # Puoi importare tutte le funzioni da un modulo # Attenzione: questo non è raccomandato from math import * # Puoi abbreviare i nomi dei moduli import math as m math.sqrt(16) == m.sqrt(16) # => True # I moduli di Python sono normali file python. Ne puoi # scrivere di tuoi ed importarli. Il nome del modulo # è lo stesso del nome del file. # Potete scoprire quali funzioni e attributi # sono definiti in un modulo import math dir(math) # Se nella cartella corrente hai uno script chiamato math.py, # Python caricherà quello invece del modulo math. # Questo succede perchè la cartella corrente ha priorità # sulle librerie standard di Python # Se hai uno script Python chiamato math.py nella stessa # cartella del tua script, Python caricherà quello al posto del # comune modulo math. # Questo accade perché la cartella locale ha la priorità # sulle librerie built-in di Python. #################################################### ## 6. Classes #################################################### # Usiamo l'istruzione "class" per creare una classe class Human: # Un attributo della classe. E' condiviso tra tutte le istanze delle classe species = "H. sapiens" # Si noti che i doppi underscore iniziali e finali denotano gli oggetti o # attributi utilizzati da Python ma che vivono nel namespace controllato # dall'utente # Metodi, oggetti o attributi come: __init__, __str__, __repr__, etc. sono # chiamati metodi speciali (o talvolta chiamati "dunder methods"). # Non dovresti inventare tali nomi da solo. def __init__(self, name): # Assegna l'argomento all'attributo name dell'istanza self.name = name # Inizializza una proprietà self._age = 0 # Un metodo dell'istanza. Tutti i metodi prendo "self" come primo argomento def say(self, msg): print("{name}: {message}".format(name=self.name, message=msg)) # Un altro metodo dell'istanza def sing(self): return 'yo... yo... microphone check... one two... one two...' # Un metodo della classe è condiviso fra tutte le istanze # Sono chiamati con la classe chiamante come primo argomento @classmethod def get_species(cls): return cls.species # Un metodo statico è chiamato senza classe o istanza di riferimento @staticmethod def grunt(): return "*grunt*" # Una property è come un metodo getter. # Trasforma il metodo age() in un attributo in sola lettura, che ha # lo stesso nome # In Python non c'è bisogno di scrivere futili getter e setter. @property def age(self): return self._age # Questo metodo permette di modificare una property @age.setter def age(self, age): self._age = age # Questo metodo permette di cancellare una property @age.deleter def age(self): del self._age # Quando l'interprete Python legge un sorgente esegue tutto il suo codice. # Questo controllo su __name__ assicura che questo blocco di codice venga # eseguito solo quando questo modulo è il programma principale. if __name__ == '__main__': # Crea un'istanza della classe i = Human(name="Ian") i.say("hi") # "Ian: hi" j = Human("Joel") j.say("hello") # "Joel: hello" # i e j sono istanze del tipo Human, o in altre parole sono oggetti Human # Chiama un metodo della classe i.say(i.get_species()) # "Ian: H. sapiens" # Cambia l'attributo condiviso Human.species = "H. neanderthalensis" i.say(i.get_species()) # => "Ian: H. neanderthalensis" j.say(j.get_species()) # => "Joel: H. neanderthalensis" # Chiama un metodo statico print(Human.grunt()) # => "*grunt*" # Non è possibile chiamare il metodo statico con l'istanza dell'oggetto # poiché i.grunt() metterà automaticamente "self" (l'oggetto i) # come argomento print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given # Aggiorna la property (age) di questa istanza i.age = 42 # Leggi la property i.say(i.age) # => "Ian: 42" j.say(j.age) # => "Joel: 0" # Cancella la property del i.age i.age # => questo genererà un AttributeError #################################################### ## 6.1 Ereditarietà (Inheritance) #################################################### # L'ereditarietà consente di definire nuove classi figlio che ereditano metodi e # variabili dalla loro classe genitore. # Usando la classe Human definita sopra come classe base o genitore, possiamo # definire una classe figlia, Superhero, che erediterà le variabili di classe # come "species", "name" e "age", così come i metodi, come "sing" e "grunt", # dalla classe Human, ma potrà anche avere le sue proprietà uniche. # Per importare le funzioni da altri file usa il seguente formato # from "nomefile-senza-estensione" import "funzione-o-classe" from human import Human # Specificare le classi genitore come parametri della definizione della classe class Superhero(Human): # Se la classe figlio deve ereditare tutte le definizioni del genitore # senza alcuna modifica, puoi semplicemente usare la parola chiave "pass" # (e nient'altro) #Le classi figlio possono sovrascrivere gli attributi dei loro genitori species = 'Superhuman' # Le classi figlie ereditano automaticamente il costruttore della classe # genitore, inclusi i suoi argomenti, ma possono anche definire ulteriori # argomenti o definizioni e sovrascrivere i suoi metodi (compreso il # costruttore della classe). # Questo costruttore eredita l'argomento "nome" dalla classe "Human" e # aggiunge gli argomenti "superpowers" e "movie": def __init__(self, name, movie=False, superpowers=["super strength", "bulletproofing"]): # aggiungi ulteriori attributi della classe self.fictional = True self.movie = movie self.superpowers = superpowers # La funzione "super" ti consente di accedere ai metodi della classe # genitore che sono stati sovrascritti dalla classe figlia, # in questo caso il metodo __init__. # Il seguente codice esegue il costruttore della classe genitore: super().__init__(name) # Sovrascrivere il metodo "sing" def sing(self): return 'Dun, dun, DUN!' # Aggiungi un ulteriore metodo dell'istanza def boast(self): for power in self.superpowers: print("I wield the power of {pow}!".format(pow=power)) if __name__ == '__main__': sup = Superhero(name="Tick") # Controllo del tipo di istanza if isinstance(sup, Human): print('I am human') if type(sup) is Superhero: print('I am a superhero') # Ottieni il "Method Resolution search Order" usato sia da getattr () # che da super (). Questo attributo è dinamico e può essere aggiornato print(Superhero.__mro__) # => (, # => , ) # Esegui il metodo principale ma utilizza il proprio attributo di classe print(sup.get_species()) # => Superhuman # Esegui un metodo che è stato sovrascritto print(sup.sing()) # => Dun, dun, DUN! # Esegui un metodo di Human sup.say('Spoon') # => Tick: Spoon # Esegui un metodo che esiste solo in Superhero sup.boast() # => I wield the power of super strength! # => I wield the power of bulletproofing! # Attributo di classe ereditato sup.age = 31 print(sup.age) # => 31 # Attributo che esiste solo in Superhero print('Am I Oscar eligible? ' + str(sup.movie)) #################################################### ## 6.2 Ereditarietà multipla #################################################### # Un'altra definizione di classe # bat.py class Bat: species = 'Baty' def __init__(self, can_fly=True): self.fly = can_fly # Questa classe ha anche un metodo "say" def say(self, msg): msg = '... ... ...' return msg # E anche un suo metodo personale def sonar(self): return '))) ... (((' if __name__ == '__main__': b = Bat() print(b.say('hello')) print(b.fly) # Definizione di classe che eredita da Superhero e Bat # superhero.py from superhero import Superhero from bat import Bat # Definisci Batman come classe figlia che eredita sia da Superhero che da Bat class Batman(Superhero, Bat): def __init__(self, *args, **kwargs): # In genere per ereditare gli attributi devi chiamare super: # super(Batman, self).__init__(*args, **kwargs) # Ma qui abbiamo a che fare con l'ereditarietà multipla, e super() # funziona solo con la successiva classe nell'elenco MRO. # Quindi, invece, chiamiamo esplicitamente __init__ per tutti gli # antenati. L'uso di *args e **kwargs consente di passare in modo # pulito gli argomenti, con ciascun genitore che "sbuccia un # livello della cipolla". Superhero.__init__(self, 'anonymous', movie=True, superpowers=['Wealthy'], *args, **kwargs) Bat.__init__(self, *args, can_fly=False, **kwargs) # sovrascrivere il valore per l'attributo name self.name = 'Sad Affleck' def sing(self): return 'nan nan nan nan nan batman!' if __name__ == '__main__': sup = Batman() # Ottieni il "Method Resolution search Order" utilizzato da getattr() e super(). # Questo attributo è dinamico e può essere aggiornato print(Batman.__mro__) # => (, # => , # => , # => , ) # Esegui il metodo del genitore ma utilizza il proprio attributo di classe print(sup.get_species()) # => Superhuman # Esegui un metodo che è stato sovrascritto print(sup.sing()) # => nan nan nan nan nan batman! # Esegui un metodo da Human, perché l'ordine di ereditarietà è importante sup.say('I agree') # => Sad Affleck: I agree # Esegui un metodo che esiste solo nel 2o antenato print(sup.sonar()) # => ))) ... ((( # Attributo di classe ereditato sup.age = 100 print(sup.age) # => 100 # Attributo ereditato dal secondo antenato il cui valore predefinito # è stato ignorato. print('Can I fly? ' + str(sup.fly)) # => Can I fly? False #################################################### ## 7. Advanced #################################################### # I generatori ti aiutano a creare codice pigro (lazy code). # Codice che darà un risultato solo quando sarà "valutato" def double_numbers(iterable): for i in iterable: yield i + i # I generatori sono efficienti in termini di memoria perché caricano # solo i dati necessari per elaborare il valore successivo nell'iterabile. # Ciò consente loro di eseguire operazioni su intervalli di valori # altrimenti proibitivi. # NOTA: `range` sostituisce` xrange` in Python 3. for i in double_numbers(range(1, 900000000)): # `range` is a generator. print(i) if i >= 30: break # Proprio come è possibile creare una "list comprehension", è possibile # creare anche delle "generator comprehensions". values = (-x for x in [1,2,3,4,5]) for x in values: print(x) # prints -1 -2 -3 -4 -5 to console/terminal # Puoi anche trasmettere una "generator comprehensions" direttamente # ad un elenco. values = (-x for x in [1,2,3,4,5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] # Decoratori # In questo esempio "beg" avvolge/wrappa "say". # Se say_please è True, cambierà il messaggio restituito. from functools import wraps def beg(target_function): @wraps(target_function) def wrapper(*args, **kwargs): msg, say_please = target_function(*args, **kwargs) if say_please: return "{} {}".format(msg, "Per favore! Sono povero :(") return msg return wrapper @beg def say(say_please=False): msg = "Puoi comprarmi una birra?" return msg, say_please print(say()) # Puoi comprarmi una birra? print(say(say_please=True)) # Puoi comprarmi una birra? Per favore! Sono povero :( ``` ## Pronto per qualcosa di più? ### Gratis Online * [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) * [Ideas for Python Projects](http://pythonpracticeprojects.com) * [The Official Docs](http://docs.python.org/3/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/) * [Python Course](http://www.python-course.eu/index.php) * [First Steps With Python](https://realpython.com/learn/python-first-steps/) * [A curated list of awesome Python frameworks, libraries and software](https://github.com/vinta/awesome-python) * [Official Style Guide for Python](https://peps.python.org/pep-0008/) * [Python 3 Computer Science Circles](http://cscircles.cemc.uwaterloo.ca/) * [Dive Into Python 3](http://www.diveintopython3.net/index.html) ================================================ FILE: it/pythonlegacy.md ================================================ --- contributors: - ["Louie Dinh", "http://ldinh.ca"] - ["Amin Bandali", "http://aminbandali.com"] - ["Andre Polykanine", "https://github.com/Oire"] - ["evuez", "http://github.com/evuez"] translators: - ["Ale46", "http://github.com/Ale46/"] - ["Tommaso Pifferi", "http://github.com/neslinesli93/"] --- Python è stato creato da Guido Van Rossum agli inizi degli anni 90. Oggi è uno dei più popolari linguaggi esistenti. Mi sono innamorato di Python per la sua chiarezza sintattica. E' sostanzialmente pseudocodice eseguibile. Nota: questo articolo è riferito a Python 2.7 in modo specifico, ma dovrebbe andar bene anche per Python 2.x. Python 2.7 sta raggiungendo il "fine vita", ovvero non sarà più supportato nel 2020. Quindi è consigliato imparare Python utilizzando Python 3. Per maggiori informazioni su Python 3.x, dai un'occhiata al [tutorial di Python 3](../python/). E' possibile anche scrivere codice compatibile sia con Python 2.7 che con Python 3.x, utilizzando [il modulo `__future__`](https://docs.python.org/2/library/__future__.html) di Python. Il modulo `__future__` permette di scrivere codice in Python 3, che può essere eseguito utilizzando Python 2: cosa aspetti a vedere il tutorial di Python 3? ```python # I commenti su una sola linea iniziano con un cancelletto """ Più stringhe possono essere scritte usando tre ", e sono spesso usate come commenti """ #################################################### ## 1. Tipi di dati primitivi ed Operatori #################################################### # Hai i numeri 3 # => 3 # La matematica è quello che vi aspettereste 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7 # La divisione è un po' complicata. E' una divisione fra interi in cui viene # restituito in automatico il risultato intero. 5 / 2 # => 2 # Per le divisioni con la virgola abbiamo bisogno di parlare delle variabili floats. 2.0 # Questo è un float 11.0 / 4.0 # => 2.75 ahhh...molto meglio # Il risultato di una divisione fra interi troncati positivi e negativi 5 // 3 # => 1 5.0 // 3.0 # => 1.0 # funziona anche per i floats -5 // 3 # => -2 -5.0 // 3.0 # => -2.0 # E' possibile importare il modulo "division" (vedi la sezione 6 di questa guida, Moduli) # per effettuare la divisione normale usando solo '/'. from __future__ import division 11/4 # => 2.75 ...divisione normale 11//4 # => 2 ...divisione troncata # Operazione Modulo 7 % 3 # => 1 # Elevamento a potenza (x alla y-esima potenza) 2**4 # => 16 # Forzare le precedenze con le parentesi (1 + 3) * 2 # => 8 # Operatori Booleani # Nota "and" e "or" sono case-sensitive True and False #=> False False or True #=> True # Note sull'uso di operatori Bool con interi 0 and 2 #=> 0 -5 or 0 #=> -5 0 == False #=> True 2 == True #=> False 1 == True #=> True # nega con not not True # => False not False # => True # Uguaglianza è == 1 == 1 # => True 2 == 1 # => False # Disuguaglianza è != 1 != 1 # => False 2 != 1 # => True # Altri confronti 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # I confronti possono essere concatenati! 1 < 2 < 3 # => True 2 < 3 < 2 # => False # Le stringhe sono create con " o ' "Questa è una stringa." 'Anche questa è una stringa.' # Anche le stringhe possono essere sommate! "Ciao " + "mondo!" # => Ciao mondo!" # Le stringhe possono essere sommate anche senza '+' "Ciao " "mondo!" # => Ciao mondo!" # ... oppure moltiplicate "Hello" * 3 # => "HelloHelloHello" # Una stringa può essere considerata come una lista di caratteri "Questa è una stringa"[0] # => 'Q' # Per sapere la lunghezza di una stringa len("Questa è una stringa") # => 20 # Formattazione delle stringhe con % # Anche se l'operatore % per le stringe sarà deprecato con Python 3.1, e verrà rimosso # successivamente, può comunque essere utile sapere come funziona x = 'mela' y = 'limone' z = "La cesta contiene una %s e un %s" % (x,y) # Un nuovo modo per fomattare le stringhe è il metodo format. # Questo metodo è quello consigliato "{} è un {}".format("Questo", "test") "{0} possono essere {1}".format("le stringhe", "formattate") # Puoi usare delle parole chiave se non vuoi contare "{nome} vuole mangiare {cibo}".format(nome="Bob", cibo="lasagna") # None è un oggetto None # => None # Non usare il simbolo di uguaglianza "==" per comparare oggetti a None # Usa "is" invece "etc" is None # => False None is None # => True # L'operatore 'is' testa l'identità di un oggetto. Questo non è # molto utile quando non hai a che fare con valori primitivi, ma lo è # quando hai a che fare con oggetti. # Qualunque oggetto può essere usato nei test booleani # I seguenti valori sono considerati falsi: # - None # - Lo zero, come qualunque tipo numerico (quindi 0, 0L, 0.0, 0.j) # - Sequenze vuote (come '', (), []) # - Contenitori vuoti (tipo {}, set()) # - Istanze di classi definite dall'utente, che soddisfano certi criteri # vedi: https://docs.python.org/2/reference/datamodel.html#object.__nonzero__ # # Tutti gli altri valori sono considerati veri: la funzione bool() usata su di loro, ritorna True. bool(0) # => False bool("") # => False #################################################### ## 2. Variabili e Collections #################################################### # Python ha una funzione di stampa print "Sono Python. Piacere di conoscerti!" # => Sono Python. Piacere di conoscerti! # Un modo semplice per ricevere dati in input dalla riga di comando variabile_stringa_input = raw_input("Inserisci del testo: ") # Ritorna i dati letti come stringa variabile_input = input("Inserisci del testo: ") # Interpreta i dati letti come codice python # Attenzione: bisogna stare attenti quando si usa input() # Nota: In python 3, input() è deprecato, e raw_input() si chiama input() # Non c'è bisogno di dichiarare una variabile per assegnarle un valore una_variabile = 5 # Convenzionalmente si usa caratteri_minuscoli_con_underscores una_variabile # => 5 # Accedendo ad una variabile non precedentemente assegnata genera un'eccezione. # Dai un'occhiata al Control Flow per imparare di più su come gestire le eccezioni. un_altra_variabile # Genera un errore di nome # if può essere usato come un'espressione # E' l'equivalente dell'operatore ternario in C "yahoo!" if 3 > 2 else 2 # => "yahoo!" # Liste immagazzinano sequenze li = [] # Puoi partire con una lista pre-riempita altra_li = [4, 5, 6] # Aggiungi cose alla fine di una lista con append li.append(1) # li ora è [1] li.append(2) # li ora è [1, 2] li.append(4) # li ora è [1, 2, 4] li.append(3) # li ora è [1, 2, 4, 3] # Rimuovi dalla fine della lista con pop li.pop() # => 3 e li ora è [1, 2, 4] # Rimettiamolo a posto li.append(3) # li ora è [1, 2, 4, 3] di nuovo. # Accedi ad una lista come faresti con un array li[0] # => 1 # Assegna nuovo valore agli indici che sono già stati inizializzati con = li[0] = 42 li[0] # => 42 li[0] = 1 # Nota: è resettato al valore iniziale # Guarda l'ultimo elemento li[-1] # => 3 # Guardare al di fuori dei limiti è un IndexError li[4] # Genera IndexError # Puoi guardare gli intervalli con la sintassi slice (a fetta). # (E' un intervallo chiuso/aperto per voi tipi matematici.) li[1:3] # => [2, 4] # Ometti l'inizio li[2:] # => [4, 3] # Ometti la fine li[:3] # => [1, 2, 4] # Seleziona ogni seconda voce li[::2] # =>[1, 4] # Copia al contrario della lista li[::-1] # => [3, 4, 2, 1] # Usa combinazioni per fare slices avanzate # li[inizio:fine:passo] # Rimuovi arbitrariamente elementi da una lista con "del" del li[2] # li è ora [1, 2, 3] # Puoi sommare le liste li + altra_li # => [1, 2, 3, 4, 5, 6] # Nota: i valori per li ed altra_li non sono modificati. # Concatena liste con "extend()" li.extend(altra_li) # Ora li è [1, 2, 3, 4, 5, 6] # Rimuove la prima occorrenza di un elemento li.remove(2) # Ora li è [1, 3, 4, 5, 6] li.remove(2) # Emette un ValueError, poichè 2 non è contenuto nella lista # Inserisce un elemento all'indice specificato li.insert(1, 2) # li è di nuovo [1, 2, 3, 4, 5, 6] # Ritorna l'indice della prima occorrenza dell'elemento fornito li.index(2) # => 1 li.index(7) # Emette un ValueError, poichè 7 non è contenuto nella lista # Controlla l'esistenza di un valore in una lista con "in" 1 in li # => True # Esamina la lunghezza con "len()" len(li) # => 6 # Tuple sono come le liste ma immutabili. tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # Genera un TypeError # Puoi fare tutte queste cose da lista anche sulle tuple len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True # Puoi scompattare le tuple (o liste) in variabili a, b, c = (1, 2, 3) # a è ora 1, b è ora 2 and c è ora 3 d, e, f = 4, 5, 6 # puoi anche omettere le parentesi # Le tuple sono create di default se non usi le parentesi g = 4, 5, 6 # => (4, 5, 6) # Guarda come è facile scambiare due valori e, d = d, e # d è ora 5 ed e è ora 4 # Dizionari immagazzinano mappature empty_dict = {} # Questo è un dizionario pre-riempito filled_dict = {"uno": 1, "due": 2, "tre": 3} # Accedi ai valori con [] filled_dict["uno"] # => 1 # Ottieni tutte le chiavi come una lista con "keys()" filled_dict.keys() # => ["tre", "due", "uno"] # Nota - Nei dizionari l'ordine delle chiavi non è garantito. # Il tuo risultato potrebbe non essere uguale a questo. # Ottieni tutt i valori come una lista con "values()" filled_dict.values() # => [3, 2, 1] # Nota - Come sopra riguardo l'ordinamento delle chiavi. # Ottieni tutte le coppie chiave-valore, sotto forma di lista di tuple, utilizzando "items()" filled_dicts.items() # => [("uno", 1), ("due", 2), ("tre", 3)] # Controlla l'esistenza delle chiavi in un dizionario con "in" "uno" in filled_dict # => True 1 in filled_dict # => False # Cercando una chiave non esistente è un KeyError filled_dict["quattro"] # KeyError # Usa il metodo "get()" per evitare KeyError filled_dict.get("uno") # => 1 filled_dict.get("quattro") # => None # Il metodo get supporta un argomento di default quando il valore è mancante filled_dict.get("uno", 4) # => 1 filled_dict.get("quattro", 4) # => 4 # nota che filled_dict.get("quattro") è ancora => None # (get non imposta il valore nel dizionario) # imposta il valore di una chiave con una sintassi simile alle liste filled_dict["quattro"] = 4 # ora, filled_dict["quattro"] => 4 # "setdefault()" aggiunge al dizionario solo se la chiave data non è presente filled_dict.setdefault("five", 5) # filled_dict["five"] è impostato a 5 filled_dict.setdefault("five", 6) # filled_dict["five"] è ancora 5 # Sets immagazzina ... sets (che sono come le liste, ma non possono contenere doppioni) empty_set = set() # Inizializza un "set()" con un po' di valori some_set = set([1, 2, 2, 3, 4]) # some_set è ora set([1, 2, 3, 4]) # l'ordine non è garantito, anche se a volta può sembrare ordinato another_set = set([4, 3, 2, 2, 1]) # another_set è ora set([1, 2, 3, 4]) # Da Python 2.7, {} può essere usato per dichiarare un set filled_set = {1, 2, 2, 3, 4} # => {1, 2, 3, 4} # Aggiungere elementi ad un set filled_set.add(5) # filled_set è ora {1, 2, 3, 4, 5} # Fai intersezioni su un set con & other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} # Fai unioni su set con | filled_set | other_set # => {1, 2, 3, 4, 5, 6} # Fai differenze su set con - {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # Effettua la differenza simmetrica con ^ {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} # Controlla se il set a sinistra contiene quello a destra {1, 2} >= {1, 2, 3} # => False # Controlla se il set a sinistra è un sottoinsieme di quello a destra {1, 2} <= {1, 2, 3} # => True # Controlla l'esistenza in un set con in 2 in filled_set # => True 10 in filled_set # => False #################################################### ## 3. Control Flow #################################################### # Dichiariamo una variabile some_var = 5 # Questo è un controllo if. L'indentazione è molto importante in python! # stampa "some_var è più piccola di 10" if some_var > 10: print "some_var è decisamente più grande di 10." elif some_var < 10: # Questa clausola elif è opzionale. print "some_var è più piccola di 10." else: # Anche questo è opzionale. print "some_var è precisamente 10." """ I cicli for iterano sulle liste stampa: cane è un mammifero gatto è un mammifero topo è un mammifero """ for animale in ["cane", "gatto", "topo"]: # Puoi usare {0} per interpolare le stringhe formattate. (Vedi di seguito.) print "{0} è un mammifero".format(animale) """ "range(numero)" restituisce una lista di numeri da zero al numero dato stampa: 0 1 2 3 """ for i in range(4): print i """ "range(lower, upper)" restituisce una lista di numeri dal più piccolo (lower) al più grande (upper) stampa: 4 5 6 7 """ for i in range(4, 8): print i """ I cicli while vengono eseguiti finchè una condizione viene a mancare stampa: 0 1 2 3 """ x = 0 while x < 4: print x x += 1 # Forma compatta per x = x + 1 # Gestisci le eccezioni con un blocco try/except # Funziona da Python 2.6 in su: try: # Usa "raise" per generare un errore raise IndexError("Questo è un errore di indice") except IndexError as e: pass # Pass è solo una non-operazione. Solitamente vorrai fare un recupero. except (TypeError, NameError): pass # Eccezioni multiple possono essere gestite tutte insieme, se necessario. else: # Clausola opzionale al blocco try/except. Deve seguire tutti i blocchi except print "Tutto ok!" # Viene eseguita solo se il codice dentro try non genera eccezioni finally: # Eseguito sempre print "Possiamo liberare risorse qui" # Invece di try/finally per liberare risorse puoi usare il metodo with with open("myfile.txt") as f: for line in f: print line #################################################### ## 4. Funzioni #################################################### # Usa "def" per creare nuove funzioni def aggiungi(x, y): print "x è {0} e y è {1}".format(x, y) return x + y # Restituisce valori con il metodo return # Chiamare funzioni con parametri aggiungi(5, 6) # => stampa "x è 5 e y è 6" e restituisce 11 # Un altro modo per chiamare funzioni è con parole chiave come argomenti aggiungi(y=6, x=5) # Le parole chiave come argomenti possono arrivare in ogni ordine. # Puoi definire funzioni che accettano un numero variabile di argomenti posizionali # che verranno interpretati come tuple usando il * def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) # Puoi definire funzioni che accettano un numero variabile di parole chiave # come argomento, che saranno interpretati come un dizionario usando ** def keyword_args(**kwargs): return kwargs # Chiamiamola per vedere cosa succede keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} # Puoi farle entrambi in una volta, se ti va def all_the_args(*args, **kwargs): print args print kwargs """ all_the_args(1, 2, a=3, b=4) stampa: (1, 2) {"a": 3, "b": 4} """ # Quando chiami funzioni, puoi fare l'opposto di args/kwargs! # Usa * per sviluppare gli argomenti posizionale ed usa ** per espandere gli argomenti parola chiave args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # equivalente a foo(1, 2, 3, 4) all_the_args(**kwargs) # equivalente a foo(a=3, b=4) all_the_args(*args, **kwargs) # equivalente a foo(1, 2, 3, 4, a=3, b=4) # puoi passare args e kwargs insieme alle altre funzioni che accettano args/kwargs # sviluppandoli, rispettivamente, con * e ** def pass_all_the_args(*args, **kwargs): all_the_args(*args, **kwargs) print varargs(*args) print keyword_args(**kwargs) # Funzioni Scope x = 5 def set_x(num): # La variabile locale x non è uguale alla variabile globale x x = num # => 43 print x # => 43 def set_global_x(num): global x print x # => 5 x = num # la variabile globable x è ora 6 print x # => 6 set_x(43) set_global_x(6) # Python ha funzioni di prima classe def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 # Ci sono anche funzioni anonime (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 # Esse sono incluse in funzioni di alto livello map(add_10, [1, 2, 3]) # => [11, 12, 13] map(max, [1, 2, 3], [4, 2, 1]) # => [4, 2, 3] filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7] # Possiamo usare la comprensione delle liste per mappe e filtri [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # Puoi fare anche la comprensione di set e dizionari {x for x in 'abcddeef' if x in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### ## 5. Classi #################################################### # Usiamo una sottoclasse da un oggetto per avere una classe. class Human(object): # Un attributo della classe. E' condiviso da tutte le istanze delle classe species = "H. sapiens" # Costruttore base, richiamato quando la classe viene inizializzata. # Si noti che il doppio leading e gli underscore finali denotano oggetti # o attributi che sono usati da python ma che vivono nello spazio dei nome controllato # dall'utente. Non dovresti usare nomi di questo genere. def __init__(self, name): # Assegna l'argomento all'attributo name dell'istanza self.name = name # Inizializza una proprietà self.age = 0 # Un metodo dell'istanza. Tutti i metodi prendo "self" come primo argomento def say(self, msg): return "{0}: {1}".format(self.name, msg) # Un metodo della classe è condiviso fra tutte le istanze # Sono chiamate con la classe chiamante come primo argomento @classmethod def get_species(cls): return cls.species # Un metodo statico è chiamato senza una classe od una istanza di riferimento @staticmethod def grunt(): return "*grunt*" # Una proprietà è come un metodo getter. # Trasforma il metodo age() in un attributo in sola lettura, che ha lo stesso nome @property def age(self): return self._age # Questo metodo permette di modificare la proprietà @age.setter def age(self, age): self._age = age # Questo metodo permette di cancellare la proprietà @age.deleter def age(self): del self._age # Instanziare una classe i = Human(name="Ian") print i.say("hi") # stampa "Ian: hi" j = Human("Joel") print j.say("hello") # stampa "Joel: hello" # Chiamare metodi della classe i.get_species() # => "H. sapiens" # Cambiare l'attributo condiviso Human.species = "H. neanderthalensis" i.get_species() # => "H. neanderthalensis" j.get_species() # => "H. neanderthalensis" # Chiamare il metodo condiviso Human.grunt() # => "*grunt*" # Aggiorna la proprietà i.age = 42 # Ritorna il valore della proprietà i.age # => 42 # Cancella la proprietà del i.age i.age # => Emette un AttributeError #################################################### ## 6. Moduli #################################################### # Puoi importare moduli import math print math.sqrt(16) # => 4.0 # Puoi ottenere specifiche funzione da un modulo from math import ceil, floor print ceil(3.7) # => 4.0 print floor(3.7) # => 3.0 # Puoi importare tutte le funzioni da un modulo # Attenzione: questo non è raccomandato from math import * # Puoi abbreviare i nomi dei moduli import math as m math.sqrt(16) == m.sqrt(16) # => True # puoi anche verificare che le funzioni sono equivalenti from math import sqrt math.sqrt == m.sqrt == sqrt # => True # I moduli di Python sono normali file python. Ne puoi # scrivere di tuoi ed importarli. Il nome del modulo # è lo stesso del nome del file. # Potete scoprire quali funzioni e attributi # definiscono un modulo import math dir(math) # Se nella cartella corrente hai uno script chiamato math.py, # Python caricherà quello invece del modulo math. # Questo succede perchè la cartella corrente ha priorità # sulle librerie standard di Python #################################################### ## 7. Avanzate #################################################### # Generatori # Un generatore appunto "genera" valori solo quando vengono richiesti, # invece di memorizzarli tutti subito fin dall'inizio # Il metodo seguente (che NON è un generatore) raddoppia tutti i valori e li memorizza # dentro `double_arr`. Se gli oggetti iterabili sono grandi, il vettore risultato # potrebbe diventare enorme! def double_numbers(iterable): double_arr = [] for i in iterable: double_arr.append(i + i) # Eseguendo il seguente codice, noi andiamo a raddoppiare prima tutti i valori, e poi # li ritorniamo tutti e andiamo a controllare la condizione for value in double_numbers(range(1000000)): # `test_senza_generatore` print value if value > 5: break # Invece, potremmo usare un generatore per "generare" il valore raddoppiato non # appena viene richiesto def double_numbers_generator(iterable): for i in iterable: yield i + i # Utilizzando lo stesso test di prima, stavolta però con un generatore, ci permette # di iterare sui valori e raddoppiarli uno alla volta, non appena vengono richiesti dalla # logica del programma. Per questo, non appena troviamo un valore > 5, usciamo dal ciclo senza # bisogno di raddoppiare la maggior parte dei valori del range (MOLTO PIU VELOCE!) for value in double_numbers_generator(xrange(1000000)): # `test_generatore` print value if value > 5: break # Nota: hai notato l'uso di `range` in `test_senza_generatore` e `xrange` in `test_generatore`? # Proprio come `double_numbers_generator` è la versione col generatore di `double_numbers` # Abbiamo `xrange` come versione col generatore di `range` # `range` ritorna un array di 1000000 elementi # `xrange` invece genera 1000000 valori quando lo richiediamo/iteriamo su di essi # Allo stesso modo della comprensione delle liste, puoi creare la comprensione # dei generatori. values = (-x for x in [1,2,3,4,5]) for x in values: print(x) # stampa -1 -2 -3 -4 -5 # Puoi anche fare il cast diretto di una comprensione di generatori ad una lista. values = (-x for x in [1,2,3,4,5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] # Decoratori # in questo esempio beg include say # Beg chiamerà say. Se say_please è True allora cambierà il messaggio # ritornato from functools import wraps def beg(target_function): @wraps(target_function) def wrapper(*args, **kwargs): msg, say_please = target_function(*args, **kwargs) if say_please: return "{} {}".format(msg, "Per favore! Sono povero :(") return msg return wrapper @beg def say(say_please=False): msg = "Puoi comprarmi una birra?" return msg, say_please print say() # Puoi comprarmi una birra? print say(say_please=True) # Puoi comprarmi una birra? Per favore! Sono povero :( ``` ## Pronto per qualcosa di più? ### Gratis Online * [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) * [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) * [Dive Into Python](http://www.diveintopython.net/) * [The Official Docs](http://docs.python.org/2/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) * [Python Module of the Week](http://pymotw.com/2/) * [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182) * [First Steps With Python](https://realpython.com/learn/python-first-steps/) * [LearnPython](http://www.learnpython.org/) * [Fullstack Python](https://www.fullstackpython.com/) ### Libri cartacei * [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20) * [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20) * [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20) ================================================ FILE: it/qt.md ================================================ --- contributors: - ["Aleksey Kholovchuk", "https://github.com/vortexxx192"] translators: - ["Ale46", "https://gihub.com/ale46"] --- **Qt** è un framework ampiamente conosciuto per lo sviluppo di software multipiattaforma che può essere eseguito su varie piattaforme software e hardware con modifiche minime o nulle nel codice, pur avendo la potenza e la velocità delle applicazioni native. Sebbene **Qt** sia stato originariamente scritto in *C++*, ci sono diversi porting in altri linguaggi: *[PyQt](../pyqt/)*, *QtRuby*, *PHP-Qt*, etc. **Qt** è ottimo per la creazione di applicazioni con interfaccia utente grafica (GUI). Questo tutorial descrive come farlo in *C++*. ```c++ /* * Iniziamo classicamente */ // tutte le intestazioni dal framework Qt iniziano con la lettera maiuscola 'Q' #include #include int main(int argc, char *argv[]) { // crea un oggetto per gestire le risorse a livello di applicazione QApplication app(argc, argv); // crea un widget di campo di testo e lo mostra sullo schermo QLineEdit lineEdit("Hello world!"); lineEdit.show(); // avvia il ciclo degli eventi dell'applicazione return app.exec(); } ``` La parte relativa alla GUI di **Qt** riguarda esclusivamente *widget* e le loro *connessioni*. [LEGGI DI PIÙ SUI WIDGET](http://doc.qt.io/qt-5/qtwidgets-index.html) ```c++ /* * Creiamo un'etichetta e un pulsante. * Un'etichetta dovrebbe apparire quando si preme un pulsante. * * Il codice Qt parla da solo. */ #include #include #include #include #include int main(int argc, char *argv[]) { QApplication app(argc, argv); QDialog dialogWindow; dialogWindow.show(); // add vertical layout QVBoxLayout layout; dialogWindow.setLayout(&layout); QLabel textLabel("Grazie per aver premuto quel pulsante"); layout.addWidget(&textLabel); textLabel.hide(); QPushButton button("Premimi"); layout.addWidget(&button); // mostra l'etichetta nascosta quando viene premuto il pulsante QObject::connect(&button, &QPushButton::pressed, &textLabel, &QLabel::show); return app.exec(); } ``` Si noti la parte relativa a *QObject::connect*. Questo metodo viene utilizzato per connettere *SEGNALI* di un oggetto agli *SLOTS* di un altro. **I SEGNALI** vengono emessi quando certe cose accadono agli oggetti, come il segnale *premuto* che viene emesso quando l'utente preme sull'oggetto QPushButton. **Gli slot** sono *azioni* che potrebbero essere eseguite in risposta ai segnali ricevuti. [LEGGI DI PIÙ SU SLOT E SEGNALI](http://doc.qt.io/qt-5/signalsandslots.html) Successivamente, impariamo che non possiamo solo usare i widget standard, ma estendere il loro comportamento usando l'ereditarietà. Creiamo un pulsante e contiamo quante volte è stato premuto. A tale scopo definiamo la nostra classe *CounterLabel*. Deve essere dichiarato in un file separato a causa dell'architettura Qt specifica. ```c++ // counterlabel.hpp #ifndef COUNTERLABEL #define COUNTERLABEL #include class CounterLabel : public QLabel { Q_OBJECT // Macro definite da Qt che devono essere presenti in ogni widget personalizzato public: CounterLabel() : counter(0) { setText("Il contatore non è stato ancora aumentato"); // metodo di QLabel } public slots: // azione che verrà chiamata in risposta alla pressione del pulsante void increaseCounter() { setText(QString("Valore contatore: %1").arg(QString::number(++counter))); } private: int counter; }; #endif // COUNTERLABEL ``` ```c++ // main.cpp // Quasi uguale all'esempio precedente #include #include #include #include #include #include "counterlabel.hpp" int main(int argc, char *argv[]) { QApplication app(argc, argv); QDialog dialogWindow; dialogWindow.show(); QVBoxLayout layout; dialogWindow.setLayout(&layout); CounterLabel counterLabel; layout.addWidget(&counterLabel); QPushButton button("Premimi ancora una volta"); layout.addWidget(&button); QObject::connect(&button, &QPushButton::pressed, &counterLabel, &CounterLabel::increaseCounter); return app.exec(); } ``` Questo è tutto! Ovviamente, il framework Qt è molto più grande della parte che è stata trattata in questo tutorial, quindi preparatevi a leggere e fare pratica. ## Ulteriori letture - [Qt 4.8 tutorials](http://doc.qt.io/qt-4.8/tutorials.html) - [Qt 5 tutorials](http://doc.qt.io/qt-5/qtexamplesandtutorials.html) Buona fortuna e buon divertimento! ================================================ FILE: it/rst.md ================================================ --- contributors: - ["DamienVGN", "https://github.com/martin-damien"] - ["Andre Polykanine", "https://github.com/Oire"] translators: - ["Ale46", "https://github.com/Ale46"] - ["Chris54721", "https://chris54721.net"] --- RST (Restructured Text) è un formato di file inizialmente creato dalla comunità Python per la documentazione (per questo motivo appartiene a Docutils). I file RST sono semplici file di testo con una sintassi leggera (in confronto all'HTML). ## Installazione Per usare Restructured Text, sarà necessario installare [Python](http://www.python.org) ed il pacchetto `docutils`. `docutils` può essere installato da riga di comando: ```bash $ easy_install docutils ``` Oppure, se hai `pip` installato sul tuo sistema: ```bash $ pip install docutils ``` ## Sintassi del file Ecco un semplice esempio della sintassi RST: ```rst .. Le righe che iniziano con due punti sono comandi speciali. Ma se non è possibile trovare alcun comando, la riga viene considerata come un commento =============================================================================== I titoli principali sono scritti utilizzando caratteri di uguale, sopra e sotto =============================================================================== Si noti che devono esserci tanti caratteri di uguale quanti caratteri del titolo. Anche i titoli normali usano caratteri di uguale, ma solo sotto =============================================================== I sottotitoli usano i trattini ------------------------------ E i sotto-sottotitoli le tildi ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Puoi inserire il testo in *corsivo* o in **grassetto**, puoi "contrassegnare" il testo come codice con un doppio apice ``: `` print () ``. Le liste sono semplici come in Markdown: - primo articolo - Secondo elemento - Sottoelemento oppure * Primo elemento * Secondo elemento * Sottoelemento Le tabelle sono molto semplici da inserire: =========== ======== Stato Capitale =========== ======== Francia Parigi Giappone Tokio =========== ======== Anche le tabelle più complesse possono essere inserite facilmente (colonne e/o righe unite) ma ti suggerisco di leggere la documentazione completa per questo :) Esistono diversi modi per creare collegamenti: - Aggiungendo un underscore dopo una parola: GitHub_ e aggiungendo l'URL di destinazione dopo il testo (questo metodo ha il vantaggio di non inserire URL non necessari all'interno del testo leggibile). - Digitando un URL completo: https://github.com/ (verrà automaticamente convertito in un collegamento) - Utilizzando una sintassi simile a Markdown: `GitHub `_ . .. _GitHub https://github.com/ ``` ## Come usarlo RST viene fornito con docutils, che dispone di `rst2html`, per esempio: ```bash $ rst2html miofile.rst output.html ``` *Nota : In alcuni sistemi il comando potrebbe essere rst2html.py* Ma ci sono applicazioni più complesse che utilizzano il formato RST: - [Pelican](http://blog.getpelican.com/), un generatore di siti statici - [Sphinx](http://sphinx-doc.org/), un generatore di documentazione - e molti altri ## Letture - [Riferimento ufficiale rapido](http://docutils.sourceforge.net/docs/user/rst/quickref.html) ================================================ FILE: it/ruby-ecosystem.md ================================================ --- contributors: - ["Jon Smock", "http://github.com/jonsmock"] - ["Rafal Chmiel", "http://github.com/rafalchmiel"] translators: - ["Cristian Achille", "http://github.com/blackdev1l/"] --- Generalmente chi usa ruby ha l'esigenza di avere differenti versioni di Ruby installate, gestire le proprie gemme, e le loro dipendenze. ## Manager Ruby Alcune piattaforme hanno Ruby pre-installato o disponibile come pacchetto. Molti sviluppatori Ruby non usano questi pacchetti, o se lo fanno, li usano solo per installare dei manager Ruby, i quali permettono di installare e gestire più versioni di Ruby in base al progetto su cui si lavora. Di seguito i più famosi manager Ruby: * [RVM](https://rvm.io/) - Installa e permette di utilizzare diverse versioni di Ruby. RVM Ha anche il concetto di gemsets i quali isolano completamente l'ambiente di sviluppo del progetto. * [ruby-build](https://github.com/sstephenson/ruby-build) - Installa solamente multiple versioni di ruby. Usa questo se vuoi maggior controllo sull'installazione di Ruby. * [rbenv](https://github.com/sstephenson/rbenv) - Permette solo la scelta di quale versione Ruby utilizzare. Usato insieme a ruby-build. Utilizza questo per un maggior controllo su quale versione di Ruby utilizzare. * [chruby](https://github.com/postmodern/chruby) - Permette solo la scelta di quale Ruby utilizzare, simile a rbenv. ## Ruby Versions Ruby fu creato da Yukihiro "Matz" Matsumoto, il [BDFL](https://en.wikipedia.org/wiki/Benevolent_Dictator_for_Life), (acronimo inglese che sta per "Benevolo dittatore a vita") , seppur ultimamente non è più del tutto vera; l'implementazione di Ruby è detta MRI (Matz' Reference Implementation), e dunque quando si legge di una versione Ruby, essa si riferisce sempre al rilascio di una MRI Le tre maggiori versioni di Ruby in uso sono: * 2.0.0 - Rilasciata nel febbraio 2013. La maggior parte delle librerie e framework supportano la 2.0.0 * 1.9.3 - Rilasciata nel ottobre 2011. QUesta è la versione che molti svluppatori usano, il supporto è [concluso](https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended/) * 1.8.7 - Il supporto per Ruby 1.8.7 è [concluso](http://www.ruby-lang.org/en/news/2013/06/30/we-retire-1-8-7/). I cambiamenti tra la 1.8.7 a la 1.9.x sono maggiori di quelli tra la 1.9.3 a la 2.0.0. Per esempio, nella 1.9 vengono introdotti encodings e bytecode VM. Esistono ancora dei progetti basati sulla 1.8.7, ma stanno diventando una minoranza man mano che la community si trasferisce alle versioni 1.92 e 1.9.3 ## Ruby Implementations L'ecosistema Ruby gode di molte implementazioni differenti di Ruby, ognuna con particolari punti di forza, da chiarire che ogni implementazione è scritta con un linguaggio diverso, ma esse *sono tutte Ruby*. Ogni implementazione ha feature extra ma tutte esse possono eseguire file ruby. Per esempio, JRuby è scritto in Java, ma non devi conoscere java per usarlo. Implementazioni mature e compatibili: * [MRI](https://github.com/ruby/ruby) - Scritto in C, Questa è l'implementazione standard di Ruby, per definizione è 100% compatibile (con se stessa). Tutte le altre implemetazioni mantengono la compatibilità con MRI (vedere [Ruby Spec](#ruby-spec) sotto). * [JRuby](http://jruby.org/) - Scritto in Java e Ruby, Questa implementazione è molto veloce e robusta, la forza di JRuby consiste nell'interoperabilità tra JVM/Java, permettendo l'utilizzo di struemnti Java già esistenti, progetti e linguaggi * [Rubinius](http://rubini.us/) - Scritto principalmente in Ruby con un c++ bytecode VM, molto matura e veloce, permette alcune feature riguardo VM. Mediamente mature e compatibili: * [Maglev](http://maglev.github.io/) - Sviluppata sui Gemstone, è una Smalltalk VM, Smalltalk è degli strumenti molto utili, e questo progetto cerca di portare questi strumenti nello sviluppo Ruby. * [RubyMotion](http://www.rubymotion.com/) - Porta ruby nello sviluppo iOS. Poco mature e compatibili: * [Topaz](http://topazruby.com/) - Scritto in RPython (usando PyPy come toolchain) Topaz è un progetto ancora giovane e non compatibile, ha le possibilità di diventare una implementazione Ruby molto performante * [IronRuby](http://ironruby.net/) - Scritto in C# e prendendo di mira la piattaforma .NET, lo sviluppo sembra fermo da quando Microsoft ha rimosso il suo supporto. Le implementazioni Ruby possono avere una propria versione, ma hanno sempre come target una specifica versione di MRI. Molte implementazioni hanno l'abilità di selezionare una versione specifica di MRI. ## Ruby Spec La maggior parte delle implementazioni Ruby dipendono pesantemente su [Ruby Spec](https://github.com/ruby/spec). Ruby non ha una specifica ufficiale, quindi la community ha scritto una specifica eseguibile in Ruby per testare la compatibilità con MRI. ## RubyGems [RubyGems](http://rubygems.org/) è un package manager gestito dalla communtiy per Ruby. Rubygems viene installato con Ruby, quindi non c'è bisogno di scaricarlo separatamente. I pacchetti Ruby sono chiamate "gemme", e possono essere hostate dalla community su RubyGems.org . Ogni gemma contiene il codice sorgente e del metadata, tra cui la versione, le dipendenze, autor* e licenz*. ## Bundler [Bundler](http://bundler.io/) è un risolvitore di dipendenze, Esso usa il Gemfile di un progetto per cercare le dipendenze, dopo di che ottiene le dipendenze delle dipendenze ricorsivamente, Questo procedimento viene eseguito finchè tutte le dipendenze sono state risolte e scaricate, o si fermerà se un conflitto verrà trovato. Bundler genererà un error se troverà dipendenze in conflitto, Per esempio, se la gemma A richiede la versione 3 o maggiore della gemma Z, ma la gemma B richiede la versione 2, Bundler ti notificherà del conflitto. Questo diventa di aiuto nel momento in cui si hanno molte gemme nel progetto, il che porta a un grande grafo di dipendenza da risolvere. # Testing Il testing è un pezzo fondamentale della cultura Ruby, Ruby viene installato con il proprio testing framework chiamato minitest (O TestUnit per ruby 1.8.x). Esistono molte librerie con obiettivi differenti * [TestUnit](http://ruby-doc.org/stdlib-1.8.7/libdoc/test/unit/rdoc/Test/Unit.html) - Testing frameowrk rilasciato insieme a Ruby 1.8.x * [minitest](http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html) - Testing frameowrk rilasciato insieme a Ruby 1.9/2.0 * [RSpec](http://rspec.info/) - Un testing framework che si concentra nella chiarezza * [Cucumber](http://cukes.info/) - Un BDD testing framework che estrapola testo formattato in Gherkin ## Sii cordiale La community Ruby è orgogliosa di essere una communtiy aperta, accogliente e variegata. Matz stesso è estremamente amichevole, e la generosità degli sviluppatori Ruby è fantastica. ================================================ FILE: it/ruby.md ================================================ --- contributors: - ["David Underwood", "http://theflyingdeveloper.com"] - ["Joel Walden", "http://joelwalden.net"] - ["Luke Holder", "http://twitter.com/lukeholder"] - ["Tristan Hume", "http://thume.ca/"] - ["Nick LaMuro", "https://github.com/NickLaMuro"] - ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"] - ["Ariel Krakowski", "http://www.learneroo.com"] - ["Dzianis Dashkevich", "https://github.com/dskecse"] - ["Levi Bostian", "https://github.com/levibostian"] - ["Rahil Momin", "https://github.com/iamrahil"] - ["Gabriel Halley", "https://github.com/ghalley"] - ["Persa Zula", "http://persazula.com"] - ["Jake Faris", "https://github.com/farisj"] - ["Corey Ward", "https://github.com/coreyward"] translators: - ["abonte", "https://github.com/abonte"] --- ```ruby # Questo è un commento # In Ruby, (quasi) tutto è un oggetto. # Questo include i numeri... 3.class #=> Integer # ...stringhe... "Hello".class #=> String # ...e anche i metodi! "Hello".method(:class).class #=> Method # Qualche operazione aritmetica di base 1 + 1 #=> 2 8 - 1 #=> 7 10 * 2 #=> 20 35 / 5 #=> 7 2 ** 5 #=> 32 5 % 3 #=> 2 # Bitwise operators 3 & 5 #=> 1 3 | 5 #=> 7 3 ^ 5 #=> 6 # L'aritmetica è solo zucchero sintattico # per chiamare il metodo di un oggetto 1.+(3) #=> 4 10.* 5 #=> 50 100.methods.include?(:/) #=> true # I valori speciali sono oggetti nil # equivalente a null in altri linguaggi true # vero false # falso nil.class #=> NilClass true.class #=> TrueClass false.class #=> FalseClass # Uguaglianza 1 == 1 #=> true 2 == 1 #=> false # Disuguaglianza 1 != 1 #=> false 2 != 1 #=> true # nil è l'unico valore, oltre a false, che è considerato 'falso' !!nil #=> false !!false #=> false !!0 #=> true !!"" #=> true # Altri confronti 1 < 10 #=> true 1 > 10 #=> false 2 <= 2 #=> true 2 >= 2 #=> true # Operatori di confronto combinati (ritorna '1' quando il primo argomento è più # grande, '-1' quando il secondo argomento è più grande, altrimenti '0') 1 <=> 10 #=> -1 10 <=> 1 #=> 1 1 <=> 1 #=> 0 # Operatori logici true && false #=> false true || false #=> true # Ci sono versioni alternative degli operatori logici con meno precedenza. # Sono usati come costrutti per il controllo di flusso per concatenare # insieme statement finché uno di essi ritorna true o false. # `do_something_else` chiamato solo se `do_something` ha successo. do_something() and do_something_else() # `log_error` è chiamato solo se `do_something` fallisce. do_something() or log_error() # Interpolazione di stringhe placeholder = 'usare l\'interpolazione di stringhe' "Per #{placeholder} si usano stringhe con i doppi apici" #=> "Per usare l'interpolazione di stringhe si usano stringhe con i doppi apici" # E' possibile combinare le stringhe usando `+`, ma non con gli altri tipi 'hello ' + 'world' #=> "hello world" 'hello ' + 3 #=> TypeError: can't convert Fixnum into String 'hello ' + 3.to_s #=> "hello 3" "hello #{3}" #=> "hello 3" # ...oppure combinare stringhe e operatori 'ciao ' * 3 #=> "ciao ciao ciao " # ...oppure aggiungere alla stringa 'ciao' << ' mondo' #=> "ciao mondo" # Per stampare a schermo e andare a capo puts "Sto stampando!" #=> Sto stampando! #=> nil # Per stampare a schermo senza andare a capo print "Sto stampando!" #=> Sto stampando! => nil # Variabili x = 25 #=> 25 x #=> 25 # Notare che l'assegnamento ritorna il valore assegnato. # Questo significa che è possibile effettuare assegnamenti multipli: x = y = 10 #=> 10 x #=> 10 y #=> 10 # Per convenzione si usa lo snake_case per i nomi delle variabili snake_case = true # Usare nomi delle variabili descrittivi path_to_project_root = '/buon/nome/' m = '/nome/scadente/' # I simboli sono immutabili, costanti riusabili rappresentati internamente da # un valore intero. Sono spesso usati al posto delle stringhe per comunicare # specifici e significativi valori. :pendente.class #=> Symbol stato = :pendente stato == :pendente #=> true stato == 'pendente' #=> false stato == :approvato #=> false # Le stringhe possono essere convertite in simboli e viceversa: status.to_s #=> "pendente" "argon".to_sym #=> :argon # Arrays # Questo è un array array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] # Gli array possono contenere diversi tipi di elementi [1, 'hello', false] #=> [1, "hello", false] # Gli array possono essere indicizzati # Dall'inizio... array[0] #=> 1 array.first #=> 1 array[12] #=> nil # ...o dalla fine... array[-1] #=> 5 array.last #=> 5 # With a start index and length # ...o con un indice di inzio e la lunghezza... array[2, 3] #=> [3, 4, 5] # ...oppure con un intervallo. array[1..3] #=> [2, 3, 4] # Invertire l'ordine degli elementi di un array a = [1,2,3] a.reverse! #=> [3,2,1] # Come per l'aritmetica, l'accesso tramite [var] # è solo zucchero sintattico # per chiamare il metodo '[]'' di un oggetto array.[] 0 #=> 1 array.[] 12 #=> nil # Si può aggiungere un elemento all'array così array << 6 #=> [1, 2, 3, 4, 5, 6] # oppure così array.push(6) #=> [1, 2, 3, 4, 5, 6] # Controllare se un elemento esiste in un array array.include?(1) #=> true # Hash è un dizionario con coppie di chiave e valore # Un hash è denotato da parentesi graffe: hash = { 'colore' => 'verde', 'numero' => 5 } hash.keys #=> ['colore', 'numero'] # E' possibile accedere all'hash tramite chiave: hash['colore'] #=> 'verde' hash['numero'] #=> 5 # Accedere all'hash con una chiave che non esiste ritorna nil: hash['nothing here'] #=> nil # Quando si usano simboli come chiavi di un hash, si possono utilizzare # queste sintassi: hash = { :defcon => 3, :action => true } hash.keys #=> [:defcon, :action] # oppure hash = { defcon: 3, action: true } hash.keys #=> [:defcon, :action] # Controllare l'esistenza di una chiave o di un valore in un hash new_hash.key?(:defcon) #=> true new_hash.value?(3) #=> true # Suggerimento: sia gli array che gli hash sono enumerabili! # Entrambi possiedono metodi utili come each, map, count e altri. # Strutture di controllo #Condizionali if true 'if statement' elsif false 'else if, opzionale' else 'else, opzionale' end #Cicli # In Ruby, i tradizionali cicli `for` non sono molto comuni. Questi semplici # cicli, invece, sono implementati con un enumerable, usando `each`: (1..5).each do |contatore| puts "iterazione #{contatore}" end # Esso è equivalente a questo ciclo, il quale è inusuale da vedere in Ruby: for contatore in 1..5 puts "iterazione #{contatore}" end # Il costrutto `do |variable| ... end` è chiamato 'blocco'. I blocchi # sono simili alle lambda, funzioni anonime o closure che si trovano in altri # linguaggi di programmazione. Essi possono essere passati come oggetti, # chiamati o allegati come metodi. # # Il metodo 'each' di un intervallo (range) esegue il blocco una volta # per ogni elemento dell'intervallo. # Al blocco è passato un contatore come parametro. # E' possibile inglobare il blocco fra le parentesi graffe (1..5).each { |contatore| puts "iterazione #{contatore}" } # Il contenuto delle strutture dati può essere iterato usando "each". array.each do |elemento| puts "#{elemento} è parte dell'array" end hash.each do |chiave, valore| puts "#{chiave} è #{valore}" end # If you still need an index you can use 'each_with_index' and define an index # variable # Se comunque si vuole un indice, si può usare "each_with_index" e definire # una variabile che contiene l'indice array.each_with_index do |elemento, indice| puts "#{elemento} è il numero #{index} nell'array" end contatore = 1 while contatore <= 5 do puts "iterazione #{contatore}" contatore += 1 end #=> iterazione 1 #=> iterazione 2 #=> iterazione 3 #=> iterazione 4 #=> iterazione 5 # Esistono in Ruby ulteriori funzioni per fare i cicli, # come per esempio 'map', 'reduce', 'inject' e altri. # Nel caso di 'map', esso prende l'array sul quale si sta iterando, esegue # le istruzioni definite nel blocco, e ritorna un array completamente nuovo. array = [1,2,3,4,5] doubled = array.map do |elemento| elemento * 2 end puts doubled #=> [2,4,6,8,10] puts array #=> [1,2,3,4,5] # Costrutto "case" grade = 'B' case grade when 'A' puts 'Way to go kiddo' when 'B' puts 'Better luck next time' when 'C' puts 'You can do better' when 'D' puts 'Scraping through' when 'F' puts 'You failed!' else puts 'Alternative grading system, eh?' end #=> "Better luck next time" # 'case' può usare anche gli intervalli grade = 82 case grade when 90..100 puts 'Hooray!' when 80...90 puts 'OK job' else puts 'You failed!' end #=> "OK job" # Gestione delle eccezioni begin # codice che può sollevare un eccezione raise NoMemoryError, 'Esaurita la memoria.' rescue NoMemoryError => exception_variable puts 'NoMemoryError è stato sollevato.', exception_variable rescue RuntimeError => other_exception_variable puts 'RuntimeError è stato sollvato.' else puts 'Questo viene eseguito se nessuna eccezione è stata sollevata.' ensure puts 'Questo codice viene sempre eseguito a prescindere.' end # Metodi def double(x) x * 2 end # Metodi (e blocchi) ritornano implicitamente il valore dell'ultima istruzione double(2) #=> 4 # Le parentesi sono opzionali dove l'interpolazione è inequivocabile double 3 #=> 6 double double 3 #=> 12 def sum(x, y) x + y end # Gli argomenit dei metodi sono separati dalla virgola sum 3, 4 #=> 7 sum sum(3, 4), 5 #=> 12 # yield # Tutti i metodi hanno un implicito e opzionale parametro del blocco. # Esso può essere chiamato con la parola chiave 'yield'. def surround puts '{' yield puts '}' end surround { puts 'hello world' } # { # hello world # } # I blocchi possono essere convertiti in 'proc', il quale racchiude il blocco # e gli permette di essere passato ad un altro metodo, legato ad uno scope # differente o modificato. Questo è molto comune nella lista parametri del # metodo, dove è frequente vedere il parametro '&block' in coda. Esso accetta # il blocco, se ne è stato passato uno, e lo converte in un 'Proc'. # Qui la denominazione è una convenzione; funzionerebbe anche con '&ananas'. def guests(&block) block.class #=> Proc block.call(4) end # Il metodo 'call' del Proc è simile allo 'yield' quando è presente un blocco. # Gli argomenti passati a 'call' sono inoltrati al blocco come argomenti: guests { |n| "You have #{n} guests." } # => "You have 4 guests." # L'operatore splat ("*") converte una lista di argomenti in un array def guests(*array) array.each { |guest| puts guest } end # Destrutturazione # Ruby destruttura automaticamente gli array in assegnamento # a variabili multiple: a, b, c = [1, 2, 3] a #=> 1 b #=> 2 c #=> 3 # In alcuni casi si usa l'operatore splat ("*") per destrutturare # un array in una lista. classifica_concorrenti = ["John", "Sally", "Dingus", "Moe", "Marcy"] def migliore(primo, secondo, terzo) puts "I vincitori sono #{primo}, #{secondo}, e #{terzo}." end migliore *classifica_concorrenti.first(3) #=> I vincitori sono John, Sally, e Dingus. # The splat operator can also be used in parameters: def migliore(primo, secondo, terzo, *altri) puts "I vincitori sono #{primo}, #{secondo}, e #{terzo}." puts "C'erano altri #{altri.count} partecipanti." end migliore *classifica_concorrenti #=> I vincitori sono John, Sally, e Dingus. #=> C'erano altri 2 partecipanti. # Per convenzione, tutti i metodi che ritornano un booleano terminano # con un punto interrogativo 5.even? #=> false 5.odd? #=> true # Per convenzione, se il nome di un metodo termina con un punto esclamativo, # esso esegue qualcosa di distruttivo. Molti metodi hanno una versione con '!' # per effettuare una modifiche, e una versione senza '!' che ritorna # una versione modificata. nome_azienda = "Dunder Mifflin" nome_azienda.upcase #=> "DUNDER MIFFLIN" nome_azienda #=> "Dunder Mifflin" # Questa volta modifichiamo nome_azienda nome_azienda.upcase! #=> "DUNDER MIFFLIN" nome_azienda #=> "DUNDER MIFFLIN" # Classi # Definire una classe con la parola chiave class class Umano # Una variabile di classe. E' condivisa da tutte le istance di questa classe. @@specie = 'H. sapiens' # Inizializzatore di base def initialize(nome, eta = 0) # Assegna il valore dell'argomento alla variabile dell'istanza "nome" @nome = nome # Se l'età non è fornita, verrà assegnato il valore di default indicato # nella lista degli argomenti @eta = eta end # Metodo setter di base def nome=(nome) @nome = nome end # Metodo getter di base def nome @nome end # Le funzionalità di cui sopra posso essere incapsulate usando # il metodo attr_accessor come segue attr_accessor :nome # Getter/setter possono anche essere creati individualmente attr_reader :nome attr_writer :nome # Un metodo della classe usa 'self' per distinguersi dai metodi dell'istanza. # Può essere richimato solo dalla classe, non dall'istanza. def self.say(msg) puts msg end def specie @@specie end end # Instanziare una classe jim = Umano.new('Jim Halpert') dwight = Umano.new('Dwight K. Schrute') # Chiamiamo qualche metodo jim.specie #=> "H. sapiens" jim.nome #=> "Jim Halpert" jim.nome = "Jim Halpert II" #=> "Jim Halpert II" jim.nome #=> "Jim Halpert II" dwight.specie #=> "H. sapiens" dwight.nome #=> "Dwight K. Schrute" # Chiamare un metodo della classe Umano.say('Ciao') #=> "Ciao" # La visibilità della variabile (variable's scope) è determinata dal modo # in cui le viene assegnato il nome. # Variabili che iniziano con $ hanno uno scope globale $var = "Sono una variabile globale" defined? $var #=> "global-variable" # Variabili che inziano con @ hanno a livello dell'istanza @var = "Sono una variabile dell'istanza" defined? @var #=> "instance-variable" # Variabili che iniziano con @@ hanno una visibilità a livello della classe @@var = "Sono una variabile della classe" defined? @@var #=> "class variable" # Variabili che iniziano con una lettera maiuscola sono costanti Var = "Sono una costante" defined? Var #=> "constant" # Anche una classe è un oggetto in ruby. Quindi la classe può avere # una variabile dell'istanza. Le variabili della classe sono condivise # fra la classe e tutti i suoi discendenti. # Classe base class Umano @@foo = 0 def self.foo @@foo end def self.foo=(value) @@foo = value end end # Classe derivata class Lavoratore < Umano end Umano.foo #=> 0 Lavoratore.foo #=> 0 Umano.foo = 2 #=> 2 Lavoratore.foo #=> 2 # La variabile dell'istanza della classe non è condivisa dai discendenti. class Umano @bar = 0 def self.bar @bar end def self.bar=(value) @bar = value end end class Dottore < Umano end Umano.bar #=> 0 Dottore.bar #=> nil module EsempioModulo def foo 'foo' end end # Includere moduli vincola i suoi metodi all'istanza della classe. # Estendere moduli vincola i suoi metodi alla classe stessa. class Persona include EsempioModulo end class Libro extend EsempioModulo end Persona.foo #=> NoMethodError: undefined method `foo' for Person:Class Persona.new.foo #=> 'foo' Libro.foo #=> 'foo' Libro.new.foo #=> NoMethodError: undefined method `foo' # Callbacks sono eseguiti quand si include o estende un modulo module ConcernExample def self.included(base) base.extend(ClassMethods) base.send(:include, InstanceMethods) end module ClassMethods def bar 'bar' end end module InstanceMethods def qux 'qux' end end end class Something include ConcernExample end Something.bar #=> 'bar' Something.qux #=> NoMethodError: undefined method `qux' Something.new.bar #=> NoMethodError: undefined method `bar' Something.new.qux #=> 'qux' ``` ## Ulteriori risorse - [An Interactive Tutorial for Ruby](https://rubymonk.com/) - Imparare Ruby attraverso una serie di tutorial interattivi. - [Official Documentation](http://ruby-doc.org/core) - [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/) - [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - Una passata [edizione libera](http://ruby-doc.com/docs/ProgrammingRuby/) è disponibile online. - [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) - A community-driven Ruby coding style guide. - [Try Ruby](https://try.ruby-lang.org/) - Imparare le basi del linguaggio di programmazion Ruby, interattivamente nel browser. ================================================ FILE: it/rust.md ================================================ --- contributors: - ["Carlo Milanesi", "http://github.com/carlomilanesi"] filename: rust.rs --- Rust è un linguaggio di programmazione sviluppato da Mozilla Research. Rust combina il controllo a basso livello sulle prestazioni con alcune comodità ad alto livello e stringenti garanzie di sicurezza. Rust raggiunge questi obiettivi senza richiedere la garbage collection né una grossa libreria di supporto run-time, rendendo così possibile l'uso di librerie scritte in Rust come rimpiazzo di librerie scritte in C. La prima versione pubblica di Rust, la 0.1, è stata rilasciata nel gennaio 2012, e per 3 anni lo sviluppo è proceduto così rapidamente che l'utilizzo delle versioni stabili veniva scoraggiato, e piuttosto si consigliava di utilizzare le versioni notturne (nightly build). Il 15 maggio 2015, la versione 1.0 di Rust è stata rilasciata con la garanzia che nelle successive versioni 1.x non ci sarebbero state modifiche che avrebbero reso incompatibile il codice scritto per tale versione. Nelle nightly build sono attualmente disponibili migliorie al tempo di compilazione e ad altri aspetti del compilatore. Rust ha adottato un modello di rilascio a scaglioni con rilasci regolari ogni sei settimane. Per esempio, la versione 1.1 beta è stata resa disponibile contestualmente al rilascio della versione stabile 1.0. Sebbene Rust sia un linguaggio di livello relativamente basso, Rust ha alcuni concetti di programmazione funzionale che solitamente si trovano solo nei linguaggi di livello più alto. Ciò rende Rust non solo veloce, ma anche facile ed comodo da usare. ```rust // I commenti che stanno su una sola riga sono fatti così... /* ...mentre così sono fatti i commenti che richiedono più righe */ /////////////////// // 1. Fondamenti // /////////////////// // Funzioni // `i32` è il tipo per gli interi a 32-bit con segno fn add2(x: i32, y: i32) -> i32 { // return implicito (senza punto-e-virgola) x + y } // Funzione "main" fn main() { // Numeri // // Binding (ossia "variabili") immutabili let x: i32 = 1; // Suffissi intero/virgola mobile let y: i32 = 13i32; let f: f64 = 1.3f64; // Inferenza di tipo // La maggior parte delle volte, il compilatore Rust può inferire // di quale tipo sia l'espressione usata per inizializzare un binding, // e quindi non è necessario specificare esplicitamente il tipo. // In tutto questo tutorial, i tipi vengono specificati esplicitamente in molti posti, // ma solo a scopo dimostrativo. La maggior parte delle volte se ne potrebbe // fare a meno, grazie all'inferenza di tipo. let implicito_x = 1; let implicito_f = 1.3; // Aritmetica let somma = x + y + 13; // Variabile mutevole let mut mutevole = 1; mutevole = 4; mutevole += 2; // Stringhe // // Letterali di stringa let x: &str = "Ciao mondo!"; // Stampa println!("{} {}", f, x); // 1.3 Ciao mondo! // Una `String` – una stringa allocata nello heap let s: String = "Ciao mondo".to_string(); // Uno slice (fetta) di stringa – una vista immutabile // all'interno di un'altra stringa. // Uno slice è una coppia immutabile di puntatori al buffer contenuto // nella stringa - non contiene dei caratteri, solo dei puntatori a // un buffer statico o a un buffer contenuto in un altro oggetto (in questo caso, `s`) let s_slice: &str = &s; println!("{} - {}", s, s_slice); // Ciao mondo - Ciao mondo // Vettori/array // // Un array di lunghezza fissa let quattro_int: [i32; 4] = [1, 2, 3, 4]; // Un array dinamico (vettore) let mut vettore: Vec = vec![1, 2, 3, 4]; vettore.push(5); // Uno slice – una vista immutabile all'interno di un vettore o di un array // E' molto simile a uno slice di stringa, ma per i vettori let slice: &[i32] = &vettore; // Usa `{:?}` per stampare qualcosa a scopo di debugging println!("{:?} {:?}", vettore, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] // Tuple // // Una tupla è un insieme ordinato di dimensione fissa di valori aventi tipi eventualmente diversi let x: (i32, &str, f64) = (1, "ciao", 3.4); // Il `let` che destruttura let (a, b, c) = x; println!("{} {} {}", a, b, c); // 1 ciao 3.4 // Indicizzazione println!("{}", x.1); // ciao ///////////// // 2. Tipi // ///////////// // Strutture struct Punto { x: i32, y: i32, } let origine: Punto = Punto { x: 0, y: 0 }; // Una struct con campi senza nome, chiamata ‘tuple struct’ struct Punto2(i32, i32); let origine2 = Punto2(0, 0); // Enum basilare, analoga a quelle del linguaggio C enum Direzione { Sinistra, Destra, Su, Giu, } let su = Direzione::Su; // Enum con campi enum OpzionaleI32 { UnI32(i32), Niente, } let due: OpzionaleI32 = OpzionaleI32::UnI32(2); let niente = OpzionaleI32::Niente; // Generici // struct Foo { bar: T } // Questo è definito nella libreria standard come `Option` enum Opzionale { QualcheValore(T), NessunValore, } // Metodi // impl Foo { // I metodi di oggetto prendono un parametro `self` esplicito fn get_bar(self) -> T { self.bar } } let a_foo = Foo { bar: 1 }; println!("{}", a_foo.get_bar()); // 1 // I trait (tratti), noti come "interfacce" o "mixin" in altri linguaggi trait Maneggiamento { fn maneggia(self) -> Option; } impl Maneggiamento for Foo { fn maneggia(self) -> Option { Some(self.bar) } } let altro_foo = Foo { bar: 1 }; println!("{:?}", altro_foo.maneggia()); // Some(1) ///////////////////////// // 3. Pattern matching // ///////////////////////// let foo = OpzionaleI32::UnI32(1); match foo { OpzionaleI32::UnI32(n) => println!("E' un i32: {}", n), OpzionaleI32::Niente => println!("Non vale niente!"), } // Pattern matching avanzato struct FooBar { x: i32, y: OpzionaleI32 } let bar = FooBar { x: 15, y: OpzionaleI32::UnI32(32) }; match bar { FooBar { x: 0, y: OpzionaleI32::UnI32(0) } => println!("I numeri valgono zero!"), FooBar { x: n, y: OpzionaleI32::UnI32(m) } if n == m => println!("I numeri sono identici"), FooBar { x: n, y: OpzionaleI32::UnI32(m) } => println!("Numeri diversi: {} {}", n, m), FooBar { x: _, y: OpzionaleI32::Niente } => println!("Il secondo numbero non vale niente!"), } /////////////////////////////////////////// // 4. Flusso di controllo (Control flow) // /////////////////////////////////////////// // Ciclo/iterazione con `for` let array = [1, 2, 3]; for i in array { println!("{}", i); } // Range for i in 0u32..10 { print!("{} ", i); } println!(""); // Stampa `0 1 2 3 4 5 6 7 8 9 ` // `if` if 1 == 1 { println!("La matematica funziona!"); } else { println!("Oh no..."); } // `if` come espressione let value = if true { "bene" } else { "male" }; // Ciclo `while` while 1 == 1 { println!("L'universo sta funzionando regolarmente."); } // Ciclo infinito loop { println!("Ciao!"); } ///////////////////////////////////////////////// // 5. La sicurezza della memoria e i puntatori // ///////////////////////////////////////////////// // Puntatore posseduto (owned) – solamente una cosa sola per volta può ‘possedere’ questo puntatore // Ciò significa che quando il `Box` abbandona il suo scope, verrà automaticamente deallocato in sicurezza. let mut mio: Box = Box::new(3); *mio = 5; // dereference // Qui, `adesso_e_mio` acquisisce la proprietà di `mio`. In altre parole, `mio` viene spostato. let mut adesso_e_mio = mio; *adesso_e_mio += 2; println!("{}", adesso_e_mio); // 7 // println!("{}", mio); // questo non compilerebbe perché `adesso_e_mio` adesso possiede il puntatore // Riferimento (reference) – un puntatore immutabile che si riferisce ad altri dati // Quando un riferimento viene preso a un valore, diciamo che quel valore // è stato ‘preso in prestito’ (borrowed). // Mentre un valore è preso in prestito immutabilmente, non può venire mutato né spostato. // Un prestito dura fino alla fine dello scope in cui è stato creato. let mut var = 4; var = 3; let ref_var: &i32 = &var; println!("{}", var); // Diversamente da `mio`, `var` può ancora essere usato println!("{}", *ref_var); // var = 5; // questo non compilerebbe, perché `var` è stato preso in prestito // *ref_var = 6; // neanche questo, perché `ref_var` è un riferimento immutabile // Riferimento immutabile // Mentre un valore è preso in presto mutevolmente, non può essere acceduto in nessun modo. let mut var2 = 4; let ref_var2: &mut i32 = &mut var2; *ref_var2 += 2; // '*' serve a puntare al binding var2, preso in presto mutevolmente println!("{}", *ref_var2); // 6 // var2 non compilerebbe. ref_var2 è di tipo &mut i32, e quindi // immagazzina un riferimento a un i32, e non il valore stesso. // var2 = 2; // questo non compilerebbe, perché `var2` è stato preso in prestito } ``` ## Ulteriori letture C'è molto di più in Rust — questi sono solo i fondamenti di Rust, che servono a capire le cose più importanti. Purtroppo c'è pochissima documentazione in italiano, tra cui: [mozillaitalia.org/home/2015/05/30/primi-passi-con-rust/](https://www.mozillaitalia.org/home/2015/05/30/primi-passi-con-rust/) Però ce n'è parecchia in inglese. Per saperne di più, leggi [The Rust Programming Language](http://doc.rust-lang.org/book/index.html) e tieni d'occhio l'area di interesse di Reddit (subreddit) [/r/rust](http://reddit.com/r/rust). Puoi anche provare a programmare in varie versioni di Rust usando il compilatore online al sito ufficiale [Rust Playground](https://play.rust-lang.org). ================================================ FILE: it/solidity.md ================================================ --- contributors: - ["Nemil Dalal", "https://www.nemil.com"] - ["Joseph Chow", ""] - ["Bhoomtawath Plinsut", "https://github.com/varshard"] - ["Shooter", "https://github.com/liushooter"] - ["Patrick Collins", "https://gist.github.com/PatrickAlphaC"] translators: - ["Al", "http://github.com/al-ias"] --- Solidity permette di programmare su [Ethereum](https://www.ethereum.org/), una macchina virtuale basata sulla blockchain che consente la creazione e l'esecuzione degli smart contract senza che sia richiesta centralizzazione o fiducia negli attori coinvolti. Solidity è un linguaggio di programmazione di contratti tipizzato staticamente e ha molte cose in comune con JavaScript e C. Come per gli oggetti nella programmazione ad oggetti, ogni contratto contiene variabili di stato, funzioni e tipi di dato semplici. Tra le funzionalità specifiche dei contratti troviamo le clausole (guardie) dei modifier, gli event notifier per i listener, e le variabili globali custom. Come esempi di contratti su Ethereum troviamo sistemi di crowdfunding, voto, [finanza decentralizzata](https://defipulse.com/) e aste al buio. Compiere errori nel codice Solidity può portare a rischi e costi alti, quindi bisogna fare attenzione a testare e rilasciare le modifiche lentamente. A CAUSA DEI CONTINUI CAMBIAMENTI DI ETHEREUM È IMPROBABILE CHE QUESTO DOCUMENTO RESTI AGGIORNATO, QUINDI COSNIGLIAMO DI SEGUIRE LA CHAT ROOM DI SOLIDITY E IL BLOG DI ETHEREUM PER TENERSI AGGIORNATI. TUTTO IL CODICE QUI PRESENTE E' FORNITO COSÌ COM'È, CON ANNESSI RISCHI SOSTANZIALI DI ERRORI O PATTERN DI PROGRAMMAZIONE DEPRECATI. A differenza di altri linguaggi, potresti aver bisogno di usare pattern di pausing, deprecation e throttling usage per ridurre il rischio. Questo documento tratta principalmene la sintassi e quindi esclude molti design pattern in voga. Visto che Solidity e Ethereum sono in continuo sviluppo, le funzionalità sperimentali o beta sono evidenziate e soggette a cambiamenti. Ogni Pull Request è ben accetta. # Lavorare con Remix e Metamask Uno dei modi più semplici di scrivere, distribuire e testare il codice Solidity è usare : 1. [L'ambiente di sviluppo online Remix](https://remix.ethereum.org/) 2. [Il wallet Metamask](https://metamask.io/). Per cominciare, [scarichiamo l'estesione per browser di Metamask](https://metamask.io/). Una volta installata, potremo iniziare ad usare Remix. Il codice seguente è pre-inizializzato, ma prima di addentrarci, diamo un'occhiata a qualche trucchetto per iniziare ad usare Remix. Carica tutto il necessario [clickando su questo link](https://remix.ethereum.org/#version=soljson-v0.6.6+commit.6c089d02.js&optimize=false&evmVersion=null&gist=f490c0d51141dd0515244db40bbd0c17&runs=200). 1. Scegli il compilatore per Solidity ![Solidity-in-remix](/images/solidity/remix-solidity.png) 2. Apri il file che si caricherà su quel link ![Solidity-choose-file](/images/solidity/remix-choose-file.png) 3. Compila il file ![Solidity-compile](/images/solidity/remix-compile.png) 4. Fai il deploy ![Solidity-deploy](/images/solidity/remix-deploy.png) 5. Smanetta con i contratti ![Solidity-deploy](/images/solidity/remix-interact.png) Hai distribuito il tuo primo contratto! Congratulazioni! Potrai testarlo e smanettare con le funzioni già definite. Dai un'occhiata ai commenti per scoprire cosa fanno. ## Lavorare su una testnet Distribuire e testare su una testnet è il modo più accurato per mettere alla prova i tuoi smart contract in Solidity. Per farlo procuriamoci prima degli ETH di test dalla testnet Kovan. [Entra in questo Gitter Channel](https://gitter.im/kovan-testnet/faucet) e scrivici l'indirizzo del tuo wallet Metamask. Sul tuo Metamask, dovrai cambiare la testnet in `Kovan`. ![Solidity-in-remix](/images/solidity/metamask-kovan.png) Riceverai degli Ethereum di test gratuiti. Abbiamo bisogno di Ethereum per distribuire degli smart contract su una testnet. Nell'esempio precedente non avevamo usato una testnet, ma avevamo distribuito su un ambiente virtuale fittizio. Quando si lavora su una testnet, possiamo davvero monitorare e interagire con i nostri contratti in maniera persistente. Per distribuire su una testnet, allo step `#4 Fai il deploy`, cambia l'`environment` selezionato in `injected web3`. In questo modo verrà usato come network su cui fare il deploy qualsiasi network selezionato sul tuo Metamask. ![Solidity-in-remix](/images/solidity/remix-testnet.png) Per ora continua a usare la `JavaScript VM` a meno che non ti sia detto di cambiarla. Quando distribuisci su una testnet, Metamask aprirà un pop up che ti chiederà di "confermare" la transazione. Premi `yes` e dopo un certo lasso di tempo, ti apparirà la stessa interfaccia per il contratto nella parte inferiore dello schermo. ```solidity // Iniziamo con un semplice contratto su una Banca // Permette di depositare, prelevare e fare l'estratto conto // simple_bank.sol (nota l'estensione .sol) /* **** INIZIO DELL'ESEMPIO **** */ // Dichiara la versione del compilatore per il file sorgente pragma solidity ^0.6.6; // Inizia con il commento Natspec (i tre slash) // viene usato per la documentazione - e per i dati descrittivi per gli elementi // dell'interfaccia utente / azioni /// @title SimpleBank /// @author nemild /* 'contract' somiglia a 'class' in altri linguaggi (ha variabili di classe, ereditarietà, etc.) */ contract SimpleBank { // CapWords // Dichiariamo le variabili di stato fuori dalle funzioni, persisteranno // durante tutta la vita del contratto // i dizionari mappano gli indirizzi con i saldi // fai sempre attenzione agli overflow attack che sfruttano i numeri mapping (address => uint) private balances; // "private" significa che che altri contratti non possono leggere i // saldi ma le informazioni restano visibili ad altri attori sulla blockchain address public owner; // 'public' lo rende leggibile dall'esterno (ma non modificabile) dagli // utenti e dai contratti // Gli 'event' pubblicano le azioni in modo che siano ascoltabili da // listener esterni event LogDepositMade(address accountAddress, uint amount); // I 'constructor' possono ricevere uno o più parametri; Si può // dichiarare un solo costruttore constructor() public { // 'msg' fornisce i dettagli sul messaggio che è stato mandato al contratto // 'msg.sender' è chi invoca il contratto (l'indirizzo di chi lo crea) owner = msg.sender; } /// @notice Deposita ether nella banca /// @return Il saldo dell'utente dopo che è stato effettualto il deposito function deposit() public payable returns (uint) { // Usiamo 'require' per testare gli input dell'utente, 'assert' per gli // invarianti interni. Qui ci assicuriamo di non avere a che fare con // un overflow require((balances[msg.sender] + msg.value) >= balances[msg.sender]); balances[msg.sender] += msg.value; // Non servono "this." o "self." con le variabili di stato // Tutti i valori iniziali delle variabili sono impostati automaticamente // al valore di default per quel tipo di dato emit LogDepositMade(msg.sender, msg.value); // Fa scattare l'evento return balances[msg.sender]; } /// @notice Preleva ether dalla banca /// @dev Non restituisce gli ether inviati in eccesso /// @param withdrawAmount L'importo che si vuole ritirare /// @return remainingBal function withdraw(uint withdrawAmount) public returns (uint remainingBal) { require(withdrawAmount <= balances[msg.sender]); // Notiamo come per prima cosa scaliamo i soldi dal saldo, prima di // invarli. Ogni .transfer/.send in questo contratto può chiamare una // funzione esterna. Questa cosa potrebbe permettere a chi invoca la // funzione di richiedere un importo maggiore del suo saldo usando // una chiamata ricorsiva. Miriamo ad aggiornare lo stato prima che sia // chiamata una funzione esterna, incluse .transfer/.send balances[msg.sender] -= withdrawAmount; // Qui lancia automaticamente un errore se fallisce, il che implica // che il saldo (non più aggiornato) viene ripristinato a prima della // transazione msg.sender.transfer(withdrawAmount); return balances[msg.sender]; } /// @notice Recupera il saldo /// @return Il saldo dell'utente // 'view' (ex: constant) impedisce alle funzioni di modificare lo stato // delle variabili; consente alle le funzioni di essere disponibili in // locale/fuori dalla blockchain function balance() view public returns (uint) { return balances[msg.sender]; } } // ** FINE DELL'ESEMPIO ** // Passiamo alle basi di Solidity // 1. TIPI DI DATO E I LORO METODI // uint viene usato per gli importi in valuta (non ci sono double o float) // e per le date (in unix time) uint x; // int di 256 bit, non possono essere modificati dopo l'istanziazione int constant a = 8; int256 constant a = 8; // stesso effetto della riga prima, qui viene // dichiarato esplicitamente che è di 256 bit uint constant VERSION_ID = 0x123A1; // Una costante esadecimale // con 'constant', il compilatore rimpiazza ogni occorrenza con il valore // Tutte le variabili di stato (quelle fuori da una funzione) // sono 'interne' di default e accessibili SOLO dall'interno del contratto // e da tutti contratti che le ereditano // Bisogna usare esplicitamente 'public' per consentire l'accesso dai contratti // esterni int256 public a = 8; // Per int e uint possiamo esplicitamente assegnare una dimensione tra 8 e 256 // es. int8, int16, int24 uint8 b; int64 c; uint248 e; // Attenzione a non andare in overflow e a proteggersi dagli attacchi che lo fanno // Ad esempio per quanto rigrada l'addizione, conviene fare: uint256 c = a + b; assert(c >= a); // 'assert' testa gli invarianti interni; require viene usato // per gli input // Per altri esempi di problemi comuni con le operazioni aritmentiche, dai una // occhiata alla Zeppelin's SafeMath library // https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol // Non ci sono funzioni random built-in, puoi ottenere un numero pseudo-casuale // hashando l'ultimo blockhash, o ottenere un numero realmente casuale usando // qualcosa come Chainlink VRF. // https://docs.chain.link/docs/get-a-random-number // Conversione di tipo int x = int(b); bool b = true; // oppure 'var b = true;' per l'inferenza di tipo // Indirizzi - contengono indirizzi Ethereum di 20 byte/160 bit // Non sono consentite operazioni aritmetiche address public owner; // Tipi di account: // Contract account: l'indirizzo viene impostato quando lo si crea (funzione con // l'indirzzo di chi lo crea, il numero della transazione inviata) // External Account: (persona/enitità esterna): l'indirizzo viene creato dalla // chiave pubblica // Aggiungi il campo 'public' per indicare che è pubblico/accessibile dall'esterno // un getter viene creato automaticamente, ma NON un setter // Si possono mandare ether a tutti gli indirizzi owner.transfer(SOME_BALANCE); // fallisce e, in tal caso, ripristina // lo stato precedente // Possiamo anche usare la funzione di livello più basso .send, che restituisce // false se fallisce if (owner.send) {} // RICORDA: metti la send in un 'if' dato che gli indirizzi // usati nei contratti hanno delle funzioni, che vengono eseguite quando viene // fatta una send, che possono fallire. // Inoltre fai attenzione a scalare i saldi PRIMA di provare a fare una send, // dato il rischio di chiamate riscorsive che potrebbero prosciugare il contratto // Possiamo controllare il saldo owner.balance; // il saldo del propietario (utente o contratto) // I Byte sono disposibili in dimensioni da 1 a 32 byte a; // 'byte' è la stessa cosa di 'bytes1' bytes2 b; bytes32 c; // Byte con dimensione dinamica bytes m; // Un array particolare, la stessa cosa dell'array 'byte[]' (ma scritto stringato) // È più dispendioso di byte1-byte32, che di solito sono preferibili // come bytes, ma non permette di accedere alla lunghezza o all'indice (per ora) string n = "hello"; // salvato in UTF8, nota i doppi apici, non singoli // le utility function per le stringhe saranno aggiunte in futuro // sono preferibili bytes32/bytes, dato che UTF8 occupa più memoria // Inferenza di tipo // 'var' fa inferenza di tipo a seconda del primo assegnamento, // non può essere usata tra i parametri di una funzione var a = true; // da usare con cautela, può inferire un tipo errato // es. un int8 quando un contatore dev'essere un int16 // var può essere usata per assegnare una funzione ad una variabile function a(uint x) returns (uint) { return x * 2; } var f = a; f(22); // chiamata // di default, tutte le variabili sono impostate a 0 durante l'istanziazione // Delete può essere chiamato sulla maggior parte dei valori // (NON distrugge il valore, ma lo setta a 0, il valore did default) uint x = 5; // Destructuring/Tuple (x, y) = (2, 7); // assegna/scambia più valori // 2. STRUTTURE DATI // Array bytes32[5] nicknames; // array statico bytes32[] names; // array dinamico uint newLength = names.push("John"); // aggiungere un elemento restituisce // la nuova dimensione dell'array // Dimesione names.length; // ottenere la dimensione names.length = 1; // la dimensione può essere assegnata (solo per gli array nello storage) // array multidimensionali uint[][5] x; // array con 5 array dinamici (ordine opposto rispetto ad // altri linguaggi) // Dizionari (da un tipo qualsiasi a un tipo qualsiasi) mapping (string => uint) public balances; balances["charles"] = 1; // il risultato balances["ada"] è 0, tutte le chiavi non settate // restituiscono zero // 'public' permette che si possa fare questo da un altro contratto: contractName.balances("charles"); // restituisce 1 // 'public' ha creato getter (ma non un setter), come il seguente: function balances(string _account) returns (uint balance) { return balances[_account]; } // Mapping annidati mapping (address => mapping (address => uint)) public custodians; // Fare una delete delete balances["John"]; delete balances; // assegna 0 a tutti gli elementi // Diversamente da altri linguaggi NON si può iterare tra gli elementi di un // mapping senza conoscere le chiavi - ma si può costruire una struttura dati a monte // che lo faccia // Strutture dati struct Bank { address owner; uint balance; } Bank b = Bank({ owner: msg.sender, balance: 5 }); // oppure Bank c = Bank(msg.sender, 5); c.balance = 5; // imposta ad un nuovo valore delete b; // reimposta, imposta tutte le variabili della struttura a 0, tranne i mapping // Enumerazioni enum State { Created, Locked, Inactive }; // di solito si usano per gli automi a stati finiti State public state; // Dichiara una variabile da un enum state = State.Created; // Le enum possono essere convertite esplicitamente in int uint createdState = uint(State.Created); // 0 // Data location: Memory vs. storage vs. calldata - tutti i tipi complessi // (array, struct) hanno una data location // 'memory' non è persistente, 'storage' sì // Il default è 'storage' per varibili locali e di stato; // 'memory' per i parametri delle funzioni // Lo stack può contenere poche varaibili locali // Per la maggior parte dei tipi, si può impostare esplicitamente // quale data location usare // 3. Operatori semplici // Ci sono operatori logici, a bit e aritmetici // Potenza: ** // Or esclusivo: ^ // Negazione bitwise: ~ // 4. Variabili globali degne di nota // ** this ** this; // indirizzo del contratto // di solito si usa per trasferire altrove il saldo rimanente // al termine della vita del contratto this.balance; this.someFunction(); // invoca una funzione esterna tramite chiamata, // non attraverso un salto interno // ** msg - Il messaggio corrente ricevuto dal contratto ** msg.sender; // indirizzo di chi ha inviato msg msg.value; // l'importo di ether forniti a questo contratto espresso in "wei", // la funzione dovrebbe essere marcata come "payable" msg.data; // in bytes, tutti gli argomenti del messaggio msg.gas; // 'gas' restante // ** tx - Questa transazione ** tx.origin; // l'indirizzo di chi ha avviato questa transazione tx.gasprice; // il prezzo del "gas" per la transazione // ** block - Informazioni sul blocco attuale ** now; // ora corrente (approssimatamente), alias di block.timestamp (in Unix time) // Da notare come può essere manipolata dai miner, quindi da usare con cautela block.number; // numero del blocco attuale block.difficulty; // difficulty del blocco attuale block.blockhash(1); // restituisce un bytes32, funziona solo per i 256 blocchi // più recenti block.gasLimit(); // ** storage - Memoria persistente (in hash) ** storage['abc'] = 'def'; // mappa da parole di 256 bit a parole di 256 bit // 4. FUNZIONI E ALTRO // A. Funzioni // Una semplice funzione function increment(uint x) returns (uint) { x += 1; return x; } // Le funzioni possono restituire molti valori, // e visto che i valori di ritorno vengono dichiarati prima // non è richiesta un'instruzione return esplicita function increment(uint x, uint y) returns (uint x, uint y) { x += 1; y += 1; } // Chiama la funzione di cui sopra uint (a,b) = increment(1,1); // 'view' (un alias di 'constant') // indica che la funzione non cambia / non può cambiare le variabili persistenti // Le funzioni definite con view vengono eseguite localmente, non sulla blockchain // N.B. la keyword constant sarà presto deprecata uint y = 1; function increment(uint x) view returns (uint x) { x += 1; y += 1; // questa riga fallirebbe // y è una variabile di stato, e non può essere cambiata in una funzione di view } // 'pure' è più restrittivo di 'view' o 'constant', e non // permette nemmeno di leggere le varaibili di stato // In realtà è più complicato, per approfondire su // view/pure: // http://solidity.readthedocs.io/en/develop/contracts.html#view-functions // Modificatori di visibilità per le funzioni // Possono essere messi vicino a 'view' e includono: // public - visibile esternamente e internamente (di default per function) // external - visible solo esternamente (comprese le chiamate fatte con this.) // private - visibile solo dal contratto attuale // internal - visibile solo dal contratto attuale, e da quelli che ne derivano // Di solito è una buona idea marcare esplicitamente ogni funzione // Le funzioni sono hoisted e si può assegnare una funzione ad una variabile function a() { var z = b; b(); } function b() { } // Tutte le funzioni che ricevono ether devono essere dichiarate come 'payable' function depositEther() public payable { balances[msg.sender] += msg.value; } // I cicli sono da preferire alla ricorsione // (la profondità massima dello stack è 1024) // Inoltre, non impostare dei loop senza limiti, // perchè potresti raggiungere il limite per il gas // B. Eventi // Gli eventi notificano a terze parti; è facile ispezionare e // accedere agli eventi al di fuori della blockchain (con client leggeri); // Tipicamente si dichiarano dopo i parametri del contratto // Tipicamente, sono capitalized - si usa Log come prefisso per esplicitarli // meglio ed evitare che si confondano con una chiamata a funzione // Dichiarazione event LogSent(address indexed from, address indexed to, uint amount); // Da notare le prime lettere maiuscole // Chiamata LogSent(from, to, amount); /** Una terza parte esterna (entità o contratto), può osservare usando la libreria JavaScript Web3: // Quel che se segue è codice JavaScript, non Solidity Coin.LogSent().watch({}, '', function(error, result) { if (!error) { console.log("Trasferimento valuta: " + result.args.amount + " la valuta è stata mandata da " + result.args.from + " a " + result.args.to + "."); console.log("I saldi ora sono:\n" + "Mittente: " + Coin.balances.call(result.args.from) + "Destinatario: " + Coin.balances.call(result.args.to)); } } **/ // È prassi che un contratto dipenda da un altro (es. che dipenda // dai tassi di cambio forniti da un altro contratto) // C. Modifier // I modifier validano gli input per conto dele funzioni verificando ad esempio // il saldo minimo o l'autenticazione dell'utente; // sono simili alle calusole di guardia di altri linguaggi // '_' (underscore) viene spesso posizionato nell'ultima riga del body, e indica // che la funzione chiamata dev'essere posizionata lì modifier onlyAfter(uint _time) { require (now >= _time); _; } modifier onlyOwner { require(msg.sender == owner) _; } // usate comunemente negli automi a stati finiti modifier onlyIfStateA (State currState) { require(currState == State.A) _; } // Si dichiarano appena dopo la definizione di una funzione function changeOwner(newOwner) onlyAfter(someTime) onlyOwner() onlyIfState(State.A) { owner = newOwner; } // L'underscore può essere messo prima della fine del body, // ma un'istruzione di ritorno esplicita lo salterebbe, // quindi è da usare con cautela modifier checkValue(uint amount) { _; if (msg.value > amount) { uint amountToRefund = amount - msg.value; msg.sender.transfer(amountToRefund); } } // 6. ISTRUZIONI CONDIZIONALI E CICLI // Troviamo tutte le istruzioni condizionali di base - incluse if/else, for, // while, break, continue e return - ma non c'è lo switch // La sintassi è la stessa di JavaScript, ma non esiste la conversione di tipo // in booleano dai non booleani (bisogna usare gli operatori logici per // ottenere il valore boolean) // Bisogna stare attenti i loop che iterano in base al comportamento // dell'utente, dato che i contratti hanno un tetto massimo di gas // per blocco di codice e falliranno se lo superano // Ad esempio: for(uint x = 0; x < refundAddressList.length; x++) { refundAddressList[x].transfer(SOME_AMOUNT); } // Ci sono due errori nel codice precedente: // 1. Un fallimento su una transfer impedisce al loop di completare tutti // i cicli, bloccando dei soldi; // 2. Questo loop potrebbe essere arbitrariamente lungo (si basa sul numero // degli utenti che hanno diritto al rimborso), quindi potrebbe fallire sempre // se supera il tetto massimo di gas per blocco; // Come soluzione, si permette agli utenti di prelevare // individualmente dal loro subaccount e segnare il rimborso come riscosso // Ad es. preferire pull payments ai push payment // 7. OGGETTI/CONTRATTI // A. Invocare un contratto esterno contract InfoFeed { function info() payable returns (uint ret) { return 42; } } contract Consumer { InfoFeed feed; // punta ad un contratto sulla blockchain // Imposta il feed sull'istanza del contratto esistente function setFeed(address addr) { // fare attenzione alla conversione di tipo automatica; // il costruttore non viene invocato feed = InfoFeed(addr); } // Imposta il feed ad una nuova istanza del contratto function createNewFeed() { feed = new InfoFeed(); // viene creata una nuova istanza; // viene invocato il costruttore } function callFeed() { // le parentesi finali invocano il contratto, opzionalmente si può // specificare un importo custom di ether o di gas feed.info.value(10).gas(800)(); } } // B. ereditarietà // Conta l'ordine, l'ultimo contratto ereditato (es. 'def') può andare // in overriding su parti dei contratti precedentemente ereditati contract MyContract is abc, def("a custom argument to def") { // Funzione in overriding function z() { if (msg.sender == owner) { def.z(); // invoca la funzione overridden da def super.z(); // chiama la funzione overridden del padre } } } // Funzioni astratte function someAbstractFunction(uint x); // non possono essere compilate, vengono usate nei contratti base/astratti // e poi verranno implementate // C. Import import "filename"; import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol"; // 8. ALTRE KEYWORD // A. Selfdestruct // autodistrugge il contratto corrente, inviando i fondi ad un indirizzo // (di solito il creatore) selfdestruct(SOME_ADDRESS); // rimuove il codice e quanto in memoria dal blocco corrente e da tutti i blocchi futuri // aiuta ad alleggerire i client, ma le informazioni precedenti continueranno // a persistere sulla blockchain // È un pattern comune, permette al proprietario di terminare il contratto // e ricevere i fondi rimasti function remove() { if(msg.sender == creator) { // Solo il creatore del contratto può farlo selfdestruct(creator); // Cessa l'attività del contratto, trasferisce i fondi } } // Si potrebbe voler disattivare il contratto manualmente, anzichè usare una // selfdestruct (gli ether inviati ad un contratto dopo una selfdestruct // vengono persi) // 9. NOTE SUL DESIGN DEI CONTRATTI // A. Offruscamento // Tutte le variabili sono pubblicamente visibili sulla blockchain, quindi // qualsiasi informazione privata ha bisogno di essere offruscata (es. hash con una // chiave segreta) // Passi: 1. Impegnarsi pagare una certa cifra, 2. Rivelare l'impegno preso keccak256("una_puntata_d_asta", "un segreto"); // impegno // in futuro, l'invocazione della funzione rivelatrice del contratto // mostrerà la puntata con il segreto che produce lo SHA3 reveal(100, "ilMioSegreto"); // B. Ottimizzazione della memoria (storage) // Scrivere dati sulla blockchain può essere costoso visto che vengono // conservati per sempre; siamo incoraggati ad usare la memoria in maniera // scaltra (un giorno la compilazione migliorerà, ma per ora è vantaggioso // pianificare le strutture dati da usare - e conservarne il minimo possibile // sulla blockchain) // I costi per conservare cose come array multidimensionali sono spesso alti // (costa conservare dati - non dichiarare variabili parzialmente vuote) // C. Accesso ai dati sulla blockchain // Non si può impedire alle persone o ai computer di leggere il contenuto // o lo stato delle transazioni // Anche se 'private' non permette agli altri *contratti* di leggere alcune // informazioni direttamente, qualsiasi altro attore può leggerle // sulla blockchain // Tutti i dati, dall'inizio, vegono conservati sulla blockchain e // tutti possono accedere alle informazioni passate e ai cambiamenti futuri // D. Oracle e dati esterni // Gli oracle consentono di interagire con i tuoi smart contract // al di fuori della blockchain. // Vengono usati per ricevere informazioni dal mondo reale, mandare // richieste post al mondo reale o vice versa. // Anche le implementazioni che sfruttano l'ora vengono fatte attraverso // gli oracle, visto che i contratti devono essere chiamati direttamente e // non possono fare una "subscribe" a un certo orario. // Data la decentralizzazione degli smart contract, vorrai ricevere informazioni // in maniera decentralizzata, altrimenti rischi di ricreare l'accentramento // che la progettazione degli smart contract si prefigge di prevenire. // Il modo migliore di ottenere e usare dati decentralizzati già pronti // è attraverso i Chainlink Data Feeds // https://docs.chain.link/docs/get-the-latest-price // Possiamo fare riferimento a certe informazioni della blockchain // che sono già state aggregate da più fonti e ridistribuite on-chain, // usandole come "banche dati" di fonti di informazione. // Puoi vedere altri esempi che effettuano chiamate alle API qui: // https://docs.chain.link/docs/make-a-http-get-request // E ovviamente puoi costruire la tua rete di orace, ma assicurati di sapere // quant'è accentrata o decentralizzata la tua applicazione. // Mettere su una rete di oracle per conto tuo // E. Cron Job // I contratti devono essere chiamati manualmente per gestire lo scheduling // in base all'orario; si può creare un codice esterno che li pinghi reglarmente // oppure fornire degli incentivi (ether) a qualcun'altro che lo faccia // F. Pattern Observer // Un pattern observer permette di iscriversi come osservatore e // registrare una funzione che verrà chiamata dall'oracle // (N.B. l'oracolo paga perchè sia eseguita quest'azione) // Ci sono alcune somoglianze nella registrazione con Pub/sub // Questo è un contratto astratto che importano sia il client che il server // Il client dovrebbe implementarlo contract SomeOracleCallback { function oracleCallback(int _value, uint _time, bytes32 info) external; } contract SomeOracle { SomeOracleCallback[] callbacks; // array di tutti gli osservatori iscritti // Osservatori iscritti function addSubscriber(SomeOracleCallback a) { callbacks.push(a); } function notify(value, time, info) private { for(uint i = 0;i < callbacks.length; i++) { // tutti gli osservatori iscritti dovranno implementare la oracleCallback callbacks[i].oracleCallback(value, time, info); } } function doSomething() public { // Codice che fa qualcosa // Notifica a tutti gli iscritti notify(_value, _time, _info); } } // Il contratto client può aggiungersi agli iscritti (con addSubscriber) // del contratto SomeOracle, importando SomeOracleCallback // G. Automi a stati finiti // vedi l'esempio sotto che usa enum per lo stato e il modifier inState ``` Prova l'esempio completo qui sotto [usando remix e la `JavaScript VM`](https://remix.ethereum.org/#version=soljson-v0.6.6+commit.6c089d02.js&optimize=false&evmVersion=null&gist=3d12cd503dcedfcdd715ef61f786be0b&runs=200) ```solidity // *** ESEMPIO: Un esempio di crowdfunding (molto simile a Kickstarter) *** // ** START EXAMPLE ** // CrowdFunder.sol pragma solidity ^0.6.6; /// @title CrowdFunder /// @author nemild contract CrowdFunder { // Variabili impostate alla creazione dal creatore address public creator; address payable public fundRecipient; // il creatore può essere diverso // da chi riceve i fondi, che dev'essere payable uint public minimumToRaise; // è richiesto per chiedere il finanziamento, // altrimenti tutti ricevono un rimborso string campaignUrl; byte version = "1"; // Strutture dati enum State { Fundraising, ExpiredRefund, Successful } struct Contribution { uint amount; address payable contributor; } // Variabili di stato State public state = State.Fundraising; // inizializzato alla creazione uint public totalRaised; uint public raiseBy; uint public completeAt; Contribution[] contributions; event LogFundingReceived(address addr, uint amount, uint currentTotal); event LogWinnerPaid(address winnerAddress); modifier inState(State _state) { require(state == _state); _; } modifier isCreator() { require(msg.sender == creator); _; } // Aspetta 24 settimane dopo l'ultimo cambio di stato prima di consentire // che in contratto venga distrutto modifier atEndOfLifecycle() { require(((state == State.ExpiredRefund || state == State.Successful) && completeAt + 24 weeks < now)); _; } function crowdFund( uint timeInHoursForFundraising, string memory _campaignUrl, address payable _fundRecipient, uint _minimumToRaise) public { creator = msg.sender; fundRecipient = _fundRecipient; campaignUrl = _campaignUrl; minimumToRaise = _minimumToRaise; raiseBy = now + (timeInHoursForFundraising * 1 hours); } function contribute() public payable inState(State.Fundraising) returns(uint256 id) { contributions.push( Contribution({ amount: msg.value, contributor: msg.sender }) // usiamo un array per iterare ); totalRaised += msg.value; emit LogFundingReceived(msg.sender, msg.value, totalRaised); checkIfFundingCompleteOrExpired(); return contributions.length - 1; // restituisce l'id } function checkIfFundingCompleteOrExpired() public { if (totalRaised > minimumToRaise) { state = State.Successful; payOut(); // qui si può incentivare chi ha provocato il cambiamento di stato } else if ( now > raiseBy ) { state = State.ExpiredRefund; // ora i finanziatori possono avere // il rimborso chiamando getRefund(id) } completeAt = now; } function payOut() public inState(State.Successful) { fundRecipient.transfer(address(this).balance); LogWinnerPaid(fundRecipient); } function getRefund(uint256 id) inState(State.ExpiredRefund) public returns(bool) { require(contributions.length > id && id >= 0 && contributions[id].amount != 0 ); uint256 amountToRefund = contributions[id].amount; contributions[id].amount = 0; contributions[id].contributor.transfer(amountToRefund); return true; } function removeContract() public isCreator() atEndOfLifecycle() { selfdestruct(msg.sender); // il creatore riceve tutti i fondi che non sono stati riscossi } } // ** END EXAMPLE ** ``` Qualche altra funzionalità. ```solidity // 10. ATRE FUNZIONALITA' NATIVE // Unità di valuta // La valuta viene definita partendo dai wei, l'unità più piccola di Ether uint minAmount = 1 wei; uint a = 1 finney; // 1 ether == 1000 finney // Per altre unità, vedi: http://ether.fund/tool/converter // Unità temporali 1 == 1 second 1 minutes == 60 seconds // Le unità temporali si possono moltiplicare, visto che non vegono salvate // nelle variabili uint x = 5; (x * 1 days); // 5 giorni // Attenzione ad usare l'operatore di uguaglianza con i secondi/anni bisestili // (sono da preferire maggiore/minore di) // Crittografia // Tutte le stringhe che vengono passate vengono concatenate prima di // calcolare l'hash sha3("ab", "cd"); ripemd160("abc"); sha256("def"); // 11.SICUREZZA // I bug possono essere disastrosi per i contratti Ethereum e anche // i pattern comuni di Solidity potrebbero riverlarsi degli antipattern // Dai un'occhiata ai link sulla sicurezza alla fine di questo documento // 12. FUNZIONI DI BASSO LIVELLO // call - è di basso livello, non viene usata spesso, perchè non è type safe successBoolean = someContractAddress.call('function_name', 'arg1', 'arg2'); // callcode - Il codice all'indirizzo target viene eseguito *contestualmente* // alla chiamata del contratto // fornisce le stesse funzionalità di una libreria someContractAddress.callcode('function_name'); // 13. NOTE SULLO STILE // Basate sulla guida allo stile PEP8 di Python // Guida completa allo stile: http://solidity.readthedocs.io/en/develop/style-guide.html // Riassunto veloce: // 4 spazi per l'indentazione // Due righe per separare la dichiarazione dei contratti // (e altre dichirazioni top level) // Evitare spazi ai lati interni delle parentesi tonde // Si possono omettere le parentesi graffe per statement monolinea (if, for, etc) // L'else dovrebbe essere posizionato su una riga a se // 14. COMMENTI NATSPEC // usati per la documentazione, commenti e UI esterne // Natspec dei contratti - sempre sopra la definizione del contratto /// @title Titolo del contratto /// @author Nome dell'autore // Natspec delle funzioni /// @notice informazioni su quel che fa la funzione; mostrate quando la funzione viene eseguita /// @dev Documentazione della funzione per sviluppatori // Natspec dei parametri/valori di ritorno delle funzioni /// @param someParam Una descrizione di quel che fa il parametro /// @return Descrizione del valore di ritorno ``` ## Risorse Aggiuntive - [Documentazione di Solidity](https://solidity.readthedocs.org/en/latest/) - [Tutorial Chainlink per Principianti](https://docs.chain.link/docs/beginners-tutorial) - [Best Practice per Smart Contract](https://github.com/ConsenSys/smart-contract-best-practices) - [Superblocks Lab - Ambiente di sviluppo su browser per Solidity](https://lab.superblocks.com/) - [EthFiddle - Il JsFiddle di Solidity](https://ethfiddle.com/) - [Solidity Editor su Browser](https://remix.ethereum.org/) - [Chat Room Gitter su Solidity](https://gitter.im/ethereum/solidity) - [Stategie di Progettazione Modulare per Contratti Ethereum](https://docs.erisindustries.com/tutorials/solidity/) - [Documentazione Chainlink](https://docs.chain.link/docs/getting-started) ## Framework di Sviluppo per Smart Contract - [Hardhat](https://hardhat.org/) - [Brownie](https://github.com/eth-brownie/brownie) - [Truffle](https://www.trufflesuite.com/) ## Librerie importanti - [Zeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts): Librerie che offrono pattern comuni (crowdfuding, safemath, ecc) - [Chainlink](https://github.com/smartcontractkit/chainlink): Codice che permette di interagire con dati esterni ## Contratti di esempio - [Dapp Bin](https://github.com/ethereum/dapp-bin) - [Esempi Defi](https://github.com/PatrickAlphaC/chainlink_defi) - [Solidity per Contratti a Piccoli Passi](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts) - [Contratti ConsenSys](https://github.com/ConsenSys/dapp-store-contracts) - [Lo stato delle Dapp](http://dapps.ethercasts.com/) ## Sicurezza - [Pensando Alla Sicurezza Degli Smart Contract](https://blog.ethereum.org/2016/06/19/thinking-smart-contract-security/) - [Sicurezza Degli Smart Contract](https://blog.ethereum.org/2016/06/10/smart-contract-security/) - [Blog Distribuito di Hacking](http://hackingdistributed.com/) ## Stile - [Guida allo Stile di Solidity](http://solidity.readthedocs.io/en/latest/style-guide.html): La guida allo stile di Ethereum deriva in gran parte dalla guida allo stile [PEP 8](https://www.python.org/dev/peps/pep-0008/) di Python. ## Editor - [Remix](https://remix.ethereum.org/) - [Emacs Modalità Solidity](https://github.com/ethereum/emacs-solidity) - [Vim Solidity](https://github.com/tomlion/vim-solidity) - Snippet per gli Editor ([Ultisnips format](https://gist.github.com/nemild/98343ce6b16b747788bc)) ## Cose da fare in futuro - Nuove keyword: protected, inheritable - Lista dei design pattern comuni (throttling, RNG, upgrade di versione) -Anti patterns comuni sulla sicurezza Sentiti libero di mandare una pull request con qualsiasi modifica - o scrivi una mail a nemild -/at-/ gmail ================================================ FILE: it/sql.md ================================================ --- contributors: - ["Bob DuCharme", "http://bobdc.com/"] translators: - ["Christian Grasso", "https://grasso.io"] --- Structured Query Language (SQL) è un linguaggio standard ISO per la creazione e la gestione di database organizzati in un insieme di tabelle. Le diverse implementazioni aggiungono spesso le proprie estensioni al linguaggio base ([confronto tra le diverse implementazioni](http://troels.arvin.dk/db/rdbms/)) Le diverse implementazioni forniscono inoltre un prompt per inserire in modo interattivo i comandi o eseguire il contenuto di uno script. I comandi di seguito lavorano sul [database di esempio MySQL](https://dev.mysql.com/doc/employee/en/) disponibile su [GitHub](https://github.com/datacharmer/test_db). I file .sql contengono liste di comandi simili a quelli mostrati di seguito, che creano e riempiono delle tabelle con dati di un'azienda fittizia. Il comando per eseguire questi script può variare in base all'implementazione in uso. ```sql -- I commenti iniziano con due trattini. Ogni comando va terminato con il punto e virgola -- SQL è case-insensitive per quanto riguarda i comandi; in genere si -- preferisce scriverli in maiuscolo per distinguerli dai nomi di -- database, tabelle e colonne -- Crea ed elimina un database. I nomi di database e tabelle sono case-sensitive CREATE DATABASE someDatabase; DROP DATABASE someDatabase; -- Lista dei database disponibili SHOW DATABASES; -- Attiva uno specifico database USE employees; -- Seleziona tutte le righe e le colonne dalla tabella departments SELECT * FROM departments; -- Seleziona tutte le righe della tabella departments, -- ma solo le colonne dept_no e dept_name. -- È possibile suddividere i comandi su più righe. SELECT dept_no, dept_name FROM departments; -- Seleziona solo le prime 5 righe della tabella departments. SELECT * FROM departments LIMIT 5; -- Ottiene la colonna dept_name della tabella departments -- solo per le righe il cui valore di dept_name contiene 'en'. SELECT dept_name FROM departments WHERE dept_name LIKE '%en%'; -- Ottiene tutte le colonne della tabella departments -- solo per le righe che hanno un dept_name formato da una 'S' -- seguita esattamente da altri 4 caratteri SELECT * FROM departments WHERE dept_name LIKE 'S____'; -- Seleziona i valori di title dalla tabella titles eliminando i duplicati SELECT DISTINCT title FROM titles; -- Come sopra, ma i valori sono ordinati alfabeticamente SELECT DISTINCT title FROM titles ORDER BY title; -- Mostra il numero di righe della tabella departments SELECT COUNT(*) FROM departments; -- Mostra il numero di righe della tabella departments -- il cui valore di dept_name contiene 'en'. SELECT COUNT(*) FROM departments WHERE dept_name LIKE '%en%'; -- Un JOIN tra più tabelle: la tabella titles contiene gli -- incarichi lavorativi associati ad un certo numero di impiegato. -- Con il JOIN utilizziamo il numero di impiegato per ottenere -- le informazioni ad esso associate nella tabella employees. -- (Inoltre selezioniamo solo le prime 10 righe) SELECT employees.first_name, employees.last_name, titles.title, titles.from_date, titles.to_date FROM titles INNER JOIN employees ON employees.emp_no = titles.emp_no LIMIT 10; -- Mostra tutte le tabelle di tutti i database. -- Spesso le implementazioni forniscono degli shortcut per questo comando SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'; -- Crea una tabella tablename1, con due colonne, per il database in uso. -- Per le colonne specifichiamo il tipo di dato (stringa di max 20 caratteri) CREATE TABLE tablename1 (fname VARCHAR(20), lname VARCHAR(20)); -- Inserisce una riga nella tabella tablename1. I valori devono essere -- appropriati per la definizione della tabella INSERT INTO tablename1 VALUES('Richard','Mutt'); -- In tablename1, modifica il valore di fname a 'John' -- in tutte le righe che hanno come lname 'Mutt'. UPDATE tablename1 SET fname='John' WHERE lname='Mutt'; -- Elimina tutte le righe di tablename1 -- il cui lname inizia per 'M'. DELETE FROM tablename1 WHERE lname like 'M%'; -- Elimina tutte le righe della tabella tablename1 DELETE FROM tablename1; -- Elimina la tabella tablename1 DROP TABLE tablename1; ``` ================================================ FILE: it/toml.md ================================================ --- contributors: - ["Alois de Gouvello", "https://github.com/aloisdg"] translators: - ["Christian Grasso", "https://grasso.io"] --- TOML è l'acronimo di _Tom's Obvious, Minimal Language_. È un linguaggio per la serializzazione di dati, progettato per i file di configurazione. È un'alternativa a linguaggi come YAML e JSON, che punta ad essere più leggibile per le persone. Allo stesso tempo, TOML può essere utilizzato in modo abbastanza semplice nella maggior parte dei linguaggi di programmazione, in quanto è progettato per essere tradotto senza ambiguità in una hash table. Tieni presente che TOML è ancora in fase di sviluppo, e la sua specifica non è ancora stabile. Questo documento utilizza TOML 0.4.0. ```toml # I commenti in TOML sono fatti così. ################ # TIPI SCALARI # ################ # Il nostro oggetto root (corrispondente all'intero documento) sarà una mappa, # anche chiamata dizionario, hash o oggetto in altri linguaggi. # La key, il simbolo di uguale e il valore devono trovarsi sulla stessa riga, # eccetto per alcuni tipi di valori. key = "value" stringa = "ciao" numero = 42 float = 3.14 boolean = true data = 1979-05-27T07:32:00-08:00 notazScientifica = 1e+12 "puoi utilizzare le virgolette per la key" = true # Puoi usare " oppure ' "la key può contenere" = "lettere, numeri, underscore e trattini" ############ # Stringhe # ############ # Le stringhe possono contenere solo caratteri UTF-8 validi. # Possiamo effettuare l'escape dei caratteri, e alcuni hanno delle sequenze # di escape compatte. Ad esempio, \t corrisponde al TAB. stringaSemplice = "Racchiusa tra virgolette. \"Usa il backslash per l'escape\"." stringaMultiriga = """ Racchiusa da tre virgolette doppie all'inizio e alla fine - consente di andare a capo.""" stringaLiteral = 'Virgolette singole. Non consente di effettuare escape.' stringaMultirigaLiteral = ''' Racchiusa da tre virgolette singole all'inizio e alla fine - consente di andare a capo. Anche in questo caso non si può fare escape. Il primo ritorno a capo viene eliminato. Tutti gli altri spazi aggiuntivi vengono mantenuti. ''' # Per i dati binari è consigliabile utilizzare Base64 e # gestirli manualmente dall'applicazione. ########## # Interi # ########## ## Gli interi possono avere o meno un segno (+, -). ## Non si possono inserire zero superflui all'inizio. ## Non è possibile inoltre utilizzare valori numerici ## non rappresentabili con una sequenza di cifre. int1 = +42 int2 = 0 int3 = -21 ## Puoi utilizzare gli underscore per migliorare la leggibilità. ## Fai attenzione a non inserirne due di seguito. int4 = 5_349_221 int5 = 1_2_3_4_5 # VALIDO, ma da evitare ######### # Float # ######### # I float permettono di rappresentare numeri decimali. flt1 = 3.1415 flt2 = -5e6 flt3 = 6.626E-34 ########### # Boolean # ########### # I valori boolean (true/false) devono essere scritti in minuscolo. bool1 = true bool2 = false ############ # Data/ora # ############ data1 = 1979-05-27T07:32:00Z # Specifica RFC 3339/ISO 8601 (UTC) data2 = 1979-05-26T15:32:00+08:00 # RFC 3339/ISO 8601 con offset ###################### # TIPI DI COLLECTION # ###################### ######### # Array # ######### array1 = [ 1, 2, 3 ] array2 = [ "Le", "virgole", "sono", "delimitatori" ] array3 = [ "Non", "unire", "tipi", "diversi" ] array4 = [ "tutte", 'le stringhe', """hanno lo stesso""", '''tipo''' ] array5 = [ "Gli spazi vuoti", "sono", "ignorati" ] ########### # Tabelle # ########### # Le tabelle (o hash table o dizionari) sono collection di coppie key/value. # Iniziano con un nome tra parentesi quadre su una linea separata. # Le tabelle vuote (senza alcun valore) sono valide. [tabella] # Tutti i valori che si trovano sotto il nome della tabella # appartengono alla tabella stessa (finchè non ne viene creata un'altra). # L'ordine di questi valori non è garantito. [tabella-1] key1 = "una stringa" key2 = 123 [tabella-2] key1 = "un'altra stringa" key2 = 456 # Utilizzando i punti è possibile creare delle sottotabelle. # Ogni parte suddivisa dai punti segue le regole delle key per il nome. [tabella-3."sotto.tabella"] key1 = "prova" # Ecco l'equivalente JSON della tabella precedente: # { "tabella-3": { "sotto.tabella": { "key1": "prova" } } } # Gli spazi non vengono considerati, ma è consigliabile # evitare di usare spazi superflui. [a.b.c] # consigliato [ d.e.f ] # identico a [d.e.f] # Non c'è bisogno di creare le tabelle superiori per creare una sottotabella. # [x] queste # [x.y] non # [x.y.z] servono [x.y.z.w] # per creare questa tabella # Se non è stata già creata prima, puoi anche creare # una tabella superiore più avanti. [a.b] c = 1 [a] d = 2 # Non puoi definire una key o una tabella più di una volta. # ERRORE [a] b = 1 [a] c = 2 # ERRORE [a] b = 1 [a.b] c = 2 # I nomi delle tabelle non possono essere vuoti. [] # NON VALIDO [a.] # NON VALIDO [a..b] # NON VALIDO [.b] # NON VALIDO [.] # NON VALIDO ################## # Tabelle inline # ################## tabelleInline = { racchiuseData = "{ e }", rigaSingola = true } punto = { x = 1, y = 2 } #################### # Array di tabelle # #################### # Un array di tabelle può essere creato utilizzando due parentesi quadre. # Tutte le tabelle con questo nome saranno elementi dell'array. # Gli elementi vengono inseriti nell'ordine in cui si trovano. [[prodotti]] nome = "array di tabelle" sku = 738594937 tabelleVuoteValide = true [[prodotti]] [[prodotti]] nome = "un altro item" sku = 284758393 colore = "grigio" # Puoi anche creare array di tabelle nested. Le sottotabelle con doppie # parentesi quadre apparterranno alla tabella più vicina sopra di esse. [[frutta]] nome = "mela" [frutto.geometria] forma = "sferica" nota = "Sono una proprietà del frutto" [[frutto.colore]] nome = "rosso" nota = "Sono un oggetto di un array dentro mela" [[frutto.colore]] nome = "verde" nota = "Sono nello stesso array di rosso" [[frutta]] nome = "banana" [[frutto.colore]] nome = "giallo" nota = "Anche io sono un oggetto di un array, ma dentro banana" ``` Ecco l'equivalente JSON dell'ultima tabella: ```json { "frutta": [ { "nome": "mela", "geometria": { "forma": "sferica", "nota": "..."}, "colore": [ { "nome": "rosso", "nota": "..." }, { "nome": "verde", "nota": "..." } ] }, { "nome": "banana", "colore": [ { "nome": "giallo", "nota": "..." } ] } ] } ``` ### Altre risorse + [Repository ufficiale di TOML](https://github.com/toml-lang/toml) ================================================ FILE: it/typescript.md ================================================ --- contributors: - ["Philippe Vlérick", "https://github.com/pvlerick"] translators: - ["Christian Grasso", "https://grasso.io"] --- TypeScript è un linguaggio basato su JavaScript che punta a rendere il codice più scalabile introducendo concetti quali le classi, i moduli, le interface, e i generics. Poichè TypeScript è un superset di JavaScript, è possibile sfruttare le sue funzionalità anche in progetti esistenti: il codice JavaScript valido è anche valido in TypeScript. Il compilatore di TypeScript genera codice JavaScript. Questo articolo si concentrerà solo sulle funzionalità aggiuntive di TypeScript. Per testare il compilatore, puoi utilizzare il [Playground](https://www.typescriptlang.org/Playground), dove potrai scrivere codice TypeScript e visualizzare l'output in JavaScript. ```ts // TypeScript ha tre tipi di base let completato: boolean = false; let righe: number = 42; let nome: string = "Andrea"; // Il tipo può essere omesso se è presente un assegnamento a scalari/literal let completato = false; let righe = 42; let nome = "Andrea"; // Il tipo "any" indica che la variabile può essere di qualsiasi tipo let qualsiasi: any = 4; qualsiasi = "oppure una stringa"; qualsiasi = false; // o magari un boolean // Usa la keyword "const" per le costanti const numeroViteGatti = 9; numeroViteGatti = 1; // Errore // Per gli array, puoi usare l'apposito tipo o la versione con i generics let lista: number[] = [1, 2, 3]; let lista: Array = [1, 2, 3]; // Per le enumerazioni: enum Colore { Rosso, Verde, Blu }; let c: Colore = Colore.Verde; // Infine, "void" viene utilizzato per le funzioni che non restituiscono valori function avviso(): void { alert("Sono un piccolo avviso fastidioso!"); } // Le funzioni supportano la sintassi "a freccia" (lambda) e supportano la type // inference, cioè per scalari/literal non c'è bisogno di specificare il tipo // Tutte le seguenti funzioni sono equivalenti, e il compilatore genererà // lo stesso codice JavaScript per ognuna di esse let f1 = function (i: number): number { return i * i; } // Type inference let f2 = function (i: number) { return i * i; } // Sintassi lambda let f3 = (i: number): number => { return i * i; } // Sintassi lambda + type inference let f4 = (i: number) => { return i * i; } // Sintassi lambda + type inference + sintassi abbreviata (senza return) let f5 = (i: number) => i * i; // Le interfacce sono strutturali, e qualunque oggetto con le stesse proprietà // di un'interfaccia è compatibile con essa interface Persona { nome: string; // Proprietà opzionale, indicata con "?" anni?: number; // Funzioni saluta(): void; } // Oggetto che implementa l'interfaccia Persona // È una Persona valida poichè implementa tutta le proprietà non opzionali let p: Persona = { nome: "Bobby", saluta: () => { } }; // Naturalmente può avere anche le proprietà opzionali: let pValida: Persona = { nome: "Bobby", anni: 42, saluta: () => { } }; // Questa invece NON è una Persona, poichè il tipo di "anni" è sbagliato let pNonValida: Persona = { nome: "Bobby", anni: true }; // Le interfacce possono anche descrivere una funzione interface SearchFunc { (source: string, subString: string): boolean; } // I nomi dei parametri non sono rilevanti: vengono controllati solo i tipi let ricerca: SearchFunc; ricerca = function (src: string, sub: string) { return src.search(sub) != -1; } // Classi - i membri sono pubblici di default class Punto { // Proprietà x: number; // Costruttore - in questo caso la keyword "public" può generare in automatico // il codice per l'inizializzazione di una variabile. // In questo esempio, verrà creata la variabile y in modo identico alla x, ma // con meno codice. Sono supportati anche i valori di default. constructor(x: number, public y: number = 0) { this.x = x; } // Funzioni dist() { return Math.sqrt(this.x * this.x + this.y * this.y); } // Membri statici static origine = new Point(0, 0); } // Le classi possono anche implementare esplicitamente delle interfacce. // Il compilatore restituirà un errore nel caso in cui manchino delle proprietà. class PersonaDiRiferimento implements Persona { nome: string saluta() {} } let p1 = new Punto(10, 20); let p2 = new Punto(25); // y = 0 // Inheritance class Punto3D extends Punto { constructor(x: number, y: number, public z: number = 0) { super(x, y); // La chiamata esplicita a super è obbligatoria } // Sovrascrittura dist() { let d = super.dist(); return Math.sqrt(d * d + this.z * this.z); } } // Moduli - "." può essere usato come separatore per i sottomoduli module Geometria { export class Quadrato { constructor(public lato: number = 0) { } area() { return Math.pow(this.lato, 2); } } } let s1 = new Geometria.Quadrato(5); // Alias locale per un modulo import G = Geometria; let s2 = new G.Quadrato(10); // Generics // Classi class Tuple { constructor(public item1: T1, public item2: T2) { } } // Interfacce interface Pair { item1: T; item2: T; } // E funzioni let pairToTuple = function (p: Pair) { return new Tuple(p.item1, p.item2); }; let tuple = pairToTuple({ item1: "hello", item2: "world" }); // Interpolazione con le template string (definite con i backtick) let nome = 'Tyrone'; let saluto = `Ciao ${name}, come stai?` // Possono anche estendersi su più righe let multiriga = `Questo è un esempio di stringa multiriga.`; // La keyword "readonly" rende un membro di sola lettura interface Persona { readonly nome: string; readonly anni: number; } var p1: Persona = { nome: "Tyrone", anni: 42 }; p1.anni = 25; // Errore, p1.anni è readonly var p2 = { nome: "John", anni: 60 }; var p3: Person = p2; // Ok, abbiamo creato una versione readonly di p2 p3.anni = 35; // Errore, p3.anni è readonly p2.anni = 45; // Compila, ma cambia anche p3.anni per via dell'aliasing! class Macchina { readonly marca: string; readonly modello: string; readonly anno = 2018; constructor() { // Possiamo anche assegnare nel constructor this.marca = "Marca sconosciuta"; this.modello = "Modello sconosciuto"; } } let numeri: Array = [0, 1, 2, 3, 4]; let altriNumeri: ReadonlyArray = numbers; altriNumeri[5] = 5; // Errore, gli elementi sono readonly altriNumeri.push(5); // Errore, il metodo push non esiste (modifica l'array) altriNumeri.length = 3; // Errore, length è readonly numeri = altriNumeri; // Errore, i metodi di modifica non esistono ``` ## Altre risorse * [Sito ufficiale di TypeScript](https://www.typescriptlang.org/) * [TypeScript su GitHub](https://github.com/microsoft/TypeScript) ================================================ FILE: it/vim.md ================================================ --- category: tool name: Vim contributors: - ["RadhikaG", "https://github.com/RadhikaG"] - ["kaymmm", "https://github.com/kaymmm"] translators: - ["valerioandreachiodi", "https://github.com/valerioandreachiodi"] --- [Vim](http://www.vim.org) (Vi IMproved) è un clone del popolare editor vi per Unix... (e qui prosegui con tutto il testo tradotto che abbiamo fatto sopra) [Vim](http://www.vim.org) (Vi IMproved) è un clone del popolare editor vi per Unix. È un editor di testo progettato per la velocità e l'aumento della produttività, ed è ubiquo nella maggior parte dei sistemi basati su Unix. Ha numerosi scorciatoie da tastiera per una navigazione rapida in punti specifici del file e per un editing veloce. `vimtutor` è un'applicazione eccellente che ti insegna come usare `Vim`. Viene fornita con il pacchetto vim. Dovresti essere in grado di eseguire "vimtutor" dalla riga di comando per aprire questo tutor in italiano (se disponibile) o tramite il comando `$ vimtutor it`.Ti guiderà attraverso tutte le principali funzionalità di `vim`. ## Basi della navigazione in Vim ``` vim # Apre in vim :help # Apre la documentazione di aiuto integrata su :q # Esci da vim :w # Salva il file corrente :wq # Salva il file ed esci da vim :q! # Esci da vim senza salvare il file # ! *forza* l'esecuzione di :q, quindi esce senza salvare ZQ # Esci da vim senza salvare il file :x # Salva il file (solo se modificato) ed esci da vim ZZ # Salva il file (solo se modificato) ed esci da vim u # Annulla (Undo) CTRL+R # Ripristina (Redo) h # Muovi a sinistra di un carattere j # Muovi giù di una riga k # Muovi su di una riga l # Muovi a destra di un carattere Ctrl+B # Muovi indietro di una schermata intera Ctrl+F # Muovi avanti di una schermata intera Ctrl+D # Muovi avanti di 1/2 schermata Ctrl+U # Muovi indietro di 1/2 schermata # Muoversi all'interno della riga 0 # Muovi all'inizio della riga $ # Muovi alla fine della riga ^ # Muovi al primo carattere non vuoto della riga # Cercare nel testo /parola # Evidenzia tutte le occorrenze di parola dopo il cursore ?parola # Evidenzia tutte le occorrenze di parola prima del cursore n # Muove il cursore alla successiva occorrenza dopo la ricerca N # Muove il cursore alla precedente occorrenza :%s/foo/bar/g # Cambia 'foo' in 'bar' su ogni riga del file :s/foo/bar/g # Cambia 'foo' in 'bar' sulla riga corrente :%s/\n/\r/g # Sostituisce i caratteri di nuova riga con caratteri di nuova riga :'<,'>s/foo/bar/g # Cambia 'foo' in 'bar' su ogni riga della selezione visuale corrente # Saltare ai caratteri f # Salta avanti e atterra su t # Salta avanti e atterra subito prima di # Per esempio, f< # Salta avanti e atterra su < t< # Salta avanti e atterra subito prima di < # Muoversi per parola w # Muovi avanti di una parola b # Muovi indietro di una parola e # Muovi alla fine della parola corrente # Altri caratteri per muoversi gg # Vai all'inizio del file G # Vai alla fine del file :NUM # Vai alla riga numero NUM (NUM è un numero qualsiasi) H # Muovi all'inizio della schermata M # Muovi al centro della schermata L # Muovi alla fine della schermata ``` ## Documentazione di aiuto Vim ha una documentazione di aiuto integrata a cui si può accedere con `:help `. Per esempio `:help navigation` aprirà la documentazione su come navigare nel tuo spazio di lavoro! `:help` può anche essere usato senza opzioni. Questo aprirà un dialogo di aiuto predefinito che mira a rendere l'approccio iniziale a vim più semplice! ## Modalità Vim si basa sul concetto di **modalità**. * Modalità Normale (Normal Mode) - vim si avvia in questa modalità, usata per navigare e scrivere comandi * Modalità Inserimento (Insert Mode) - usata per apportare modifiche al file * Modalità Visuale (Visual Mode) - usata per evidenziare testo ed eseguire operazioni su di esso * Modalità Ex (Ex Mode) - usata per scendere in fondo con il prompt ':' per inserire comandi ``` i # Mette vim in modalità inserimento, prima della posizione del cursore a # Mette vim in modalità inserimento, dopo la posizione del cursore v # Mette vim in modalità visuale : # Mette vim in modalità ex # 'Esce' da qualunque modalità ti trovi, tornando in modalità Normale # Copiare e incollare testo # Le operazioni usano il registro di vim per impostazione predefinita # Pensalo come agli appunti privati di vim # Yank ~ copia il testo nel registro di vim y # Copia (Yank) tutto ciò che è selezionato yy # Copia la riga corrente # Delete ~ copia il testo e lo elimina dal file d # Elimina tutto ciò che è selezionato dd # Elimina la riga corrente p # Incolla il testo dal registro dopo la posizione corrente del cursore P # Incolla il testo dal registro prima della posizione corrente del cursore x # Elimina il carattere sotto la posizione corrente del cursore ``` ## La 'Grammatica' di vim Vim può essere pensato come un insieme di comandi in un formato 'Verbo-Modificatore-Soggetto', dove: * Verbo - la tua azione * Modificatore - come stai compiendo l'azione * Soggetto - l'oggetto su cui agisce la tua azione Alcuni esempi importanti di 'Verbi', 'Modificatori' e 'Soggetti': ``` # 'Verbi' d # Elimina (Delete) c # Cambia (Change) y # Copia (Yank) v # Seleziona visualmente # 'Modificatori' i # Dentro (Inside) a # Intorno (Around) NUM # Numero (NUM è un numero qualsiasi) f # Cerca qualcosa e ci atterra sopra t # Cerca qualcosa e si ferma prima / # Trova una stringa dal cursore in poi ? # Trova una stringa prima del cursore # 'Soggetti' w # Parola (Word) s # Frase (Sentence) p # Paragrafo (Paragraph) b # Blocco (Block) # Esempi di 'frasi' o comandi d2w # Elimina 2 parole cis # Cambia all'interno della frase yip # Copia all'interno del paragrafo (copia il paragrafo in cui ti trovi) ct< # Cambia fino alla parentesi aperta # Cambia il testo da dove sei fino alla prossima parentesi aperta d$ # Elimina fino alla fine della riga ``` ## Alcune scorciatoie e trucchi ``` > # Indenta la selezione di un blocco < # De-indenta la selezione di un blocco :earlier 15m # Riporta il documento a come era 15 minuti fa :later 15m # Inverte il comando precedente ddp # Scambia la posizione di righe consecutive, dd poi p . # Ripeti l'azione precedente :w !sudo tee % # Salva il file corrente come root :set syntax=c # Imposta l'evidenziazione della sintassi per 'c' :sort # Ordina tutte le righe :sort! # Ordina tutte le righe al contrario :sort u # Ordina tutte le righe e rimuovi i duplicati ~ # Inverte maiuscole/minuscole del testo selezionato u # Testo selezionato in minuscolo U # Testo selezionato in maiuscolo J # Unisce la riga corrente con la riga successiva # Piegare (Fold) il testo zf # Crea una piega dal testo selezionato zd # Elimina la piega sulla riga corrente zD # Elimina ricorsivamente le pieghe annidate o selezionate zE # Elimina tutte le pieghe nella finestra zo # Apri la piega corrente zO # Apri ricorsivamente le pieghe annidate o selezionate zc # Chiudi la piega corrente zC # Chiudi ricorsivamente le pieghe annidate o selezionate zR # Apri tutte le pieghe zM # Chiudi tutte le pieghe za # Alterna apertura/chiusura della piega corrente zA # Alterna ricorsivamente apertura/chiusura delle pieghe annidate [z # Muovi all'inizio della piega corrente ]z # Muovi alla fine della piega corrente zj # Muovi all'inizio della piega successiva zk # Muovi alla fine della piega precedente ``` ## Macro Le macro sono fondamentalmente azioni registrabili. Quando inizi a registrare una macro, questa registra **ogni** azione e comando che usi, finché non interrompi la registrazione. Richiamando una macro, questa applica esattamente la stessa sequenza di azioni e comandi di nuovo sulla selezione di testo. ``` qa # Inizia a registrare una macro chiamata 'a' q # Interrompi la registrazione @a # Riproduci la macro ``` ### Configurare ~/.vimrc Il file .vimrc può essere usato per configurare Vim all'avvio. Ecco un esempio di file ~/.vimrc: ```vim " Esempio ~/.vimrc " 2015.10 " Necessario perché vim sia iMproved set nocompatible " Determina il tipo di file dal nome per consentire l'auto-indentazione intelligente, ecc. filetype indent plugin on " Abilita l'evidenziazione della sintassi syntax on " Migliore completamento riga di comando set wildmenu " Usa la ricerca non sensibile alle maiuscole tranne quando si usano lettere maiuscole set ignorecase set smartcase " Quando si apre una nuova riga e non è attiva l'indentazione specifica del file, " mantieni la stessa indentazione della riga in cui ti trovi set autoindent " Visualizza i numeri di riga sulla sinistra set number " Opzioni di indentazione, modifica in base alla preferenza personale " Numero di spazi visuali per TAB set tabstop=4 " Numero di spazi nel TAB durante l'editing set softtabstop=4 " Numero di spazi indentati quando si usano le operazioni di ri-indentazione (>> e <<) set shiftwidth=4 " Converti i TAB in spazi set expandtab " Abilita tabulazione e spaziatura intelligente per indentazione e allineamento set smarttab ``` ### Riferimenti [Vim | Home](http://www.vim.org/index.php) Il manuale tradotto in italiano lo trovi [qui](https://sites.google.com/view/vimdoc-it/vim-9-1) `$ vimtutor` oppure se lo preferisci in italiano `$ vimtutor it` [A vim Tutorial and Primer](https://danielmiessler.com/study/vim/) in inglese ma molto bello #### qui sotto due riferimenti in inglese [Quali sono gli angoli bui di Vim che tua madre non ti ha mai detto? (discussione su Stack Overflow)](http://stackoverflow.com/questions/726894/what-are-the-dark-corners-of-vim-your-mom-never-told-you-about) [Arch Linux Wiki](https://wiki.archlinux.org/index.php/Vim) --- ================================================ FILE: it/zfs.md ================================================ --- contributors: - ["sarlalian", "http://github.com/sarlalian"] translators: - ["Christian Grasso","https://grasso.io"] --- [ZFS](http://open-zfs.org/wiki/Main_Page) è un sistema di storage che combina file system tradizionali e volume manager in un unico strumento. ZFS utilizza della terminologia specifica, diversa da quella usata da altri sistemi di storage, ma le sue funzioni lo rendono un ottimo tool per gli amministratori di sistema. ## Concetti base di ZFS ### Virtual Device Un VDEV è simile a un dispositivo gestito da una scheda RAID. Esistono diversi tipi di VDEV che offrono diversi vantaggi, tra cui ridondanza e velocità. In generale, i VDEV offrono una maggiore affidabilità rispetto alle schede RAID. Si sconsiglia di utilizzare ZFS insieme a RAID, poichè ZFS è fatto per gestire direttamente i dischi fisici. Tipi di VDEV: * mirror (mirror su più dischi) * raidz * raidz1 (parity a 1 disco, simile a RAID 5) * raidz2 (parity a 2 dischi, simile a RAID 6) * raidz3 (parity a 3 dischi) * disk * file (non consigliato in production poichè aggiunge un ulteriore filesystem) I dati vengono distribuiti tra tutti i VDEV presenti nella Storage Pool, per cui un maggior numero di VDEV aumenta le operazioni al secondo (IOPS). ### Storage Pool Le Storage Pool di ZFS sono un'astrazione del livello inferiore (VDEV) e consentono di separare il filesystem visibile agli utenti dal layout reale dei dischi. ### Dataset I dataset sono simili ai filesystem tradizionali, ma con molte più funzioni che rendono vantaggioso l'utilizzo di ZFS. I dataset supportano il [Copy on Write](https://en.wikipedia.org/wiki/Copy-on-write) gli snapshot, la gestione delle quota, compressione e deduplicazione. ### Limiti Una directory può contenere fino a 2^48 file, ognuno dei quali di 16 exabyte. Una storage pool può contenere fino a 256 zettabyte (2^78), e può essere distribuita tra 2^64 dispositivi. Un singolo host può avere fino a 2^64 storage pool. ## Comandi ### Storage Pool Azioni: * List (lista delle pool) * Status (stato) * Destroy (rimozione) * Get/Set (lettura/modifica proprietà) Lista delle zpool ```bash # Crea una zpool raidz $ zpool create zroot raidz1 gpt/zfs0 gpt/zfs1 gpt/zfs2 # Lista delle zpool $ zpool list NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT zroot 141G 106G 35.2G - 43% 75% 1.00x ONLINE - # Informazioni dettagliate su una zpool $ zpool list -v zroot NAME SIZE ALLOC FREE EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT zroot 141G 106G 35.2G - 43% 75% 1.00x ONLINE - gptid/c92a5ccf-a5bb-11e4-a77d-001b2172c655 141G 106G 35.2G - 43% 75% ``` Stato delle zpool ```bash # Informazioni sullo stato delle zpool $ zpool status pool: zroot state: ONLINE scan: scrub repaired 0 in 2h51m with 0 errors on Thu Oct 1 07:08:31 2015 config: NAME STATE READ WRITE CKSUM zroot ONLINE 0 0 0 gptid/c92a5ccf-a5bb-11e4-a77d-001b2172c655 ONLINE 0 0 0 errors: No known data errors # "Scrubbing" (correzione degli errori) $ zpool scrub zroot $ zpool status -v zroot pool: zroot state: ONLINE scan: scrub in progress since Thu Oct 15 16:59:14 2015 39.1M scanned out of 106G at 1.45M/s, 20h47m to go 0 repaired, 0.04% done config: NAME STATE READ WRITE CKSUM zroot ONLINE 0 0 0 gptid/c92a5ccf-a5bb-11e4-a77d-001b2172c655 ONLINE 0 0 0 errors: No known data errors ``` Proprietà delle zpool ```bash # Proprietà di una zpool (gestite dal sistema o dall'utente) $ zpool get all zroot NAME PROPERTY VALUE SOURCE zroot size 141G - zroot capacity 75% - zroot altroot - default zroot health ONLINE - ... # Modifica di una proprietà $ zpool set comment="Dati" zroot $ zpool get comment NAME PROPERTY VALUE SOURCE tank comment - default zroot comment Dati local ``` Rimozione di una zpool ```bash $ zpool destroy test ``` ### Dataset Azioni: * Create * List * Rename * Delete * Get/Set (proprietà) Creazione dataset ```bash # Crea un dataset $ zfs create zroot/root/data $ mount | grep data zroot/root/data on /data (zfs, local, nfsv4acls) # Crea un sottodataset $ zfs create zroot/root/data/stuff $ mount | grep data zroot/root/data on /data (zfs, local, nfsv4acls) zroot/root/data/stuff on /data/stuff (zfs, local, nfsv4acls) # Crea un volume $ zfs create -V zroot/win_vm $ zfs list zroot/win_vm NAME USED AVAIL REFER MOUNTPOINT zroot/win_vm 4.13G 17.9G 64K - ``` Lista dei dataset ```bash # Lista dei dataset $ zfs list NAME USED AVAIL REFER MOUNTPOINT zroot 106G 30.8G 144K none zroot/ROOT 18.5G 30.8G 144K none zroot/ROOT/10.1 8K 30.8G 9.63G / zroot/ROOT/default 18.5G 30.8G 11.2G / zroot/backup 5.23G 30.8G 144K none zroot/home 288K 30.8G 144K none ... # Informazioni su un dataset $ zfs list zroot/home NAME USED AVAIL REFER MOUNTPOINT zroot/home 288K 30.8G 144K none # Lista degli snapshot $ zfs list -t snapshot zroot@daily-2015-10-15 0 - 144K - zroot/ROOT@daily-2015-10-15 0 - 144K - zroot/ROOT/default@daily-2015-10-15 0 - 24.2G - zroot/tmp@daily-2015-10-15 124K - 708M - zroot/usr@daily-2015-10-15 0 - 144K - zroot/home@daily-2015-10-15 0 - 11.9G - zroot/var@daily-2015-10-15 704K - 1.42G - zroot/var/log@daily-2015-10-15 192K - 828K - zroot/var/tmp@daily-2015-10-15 0 - 152K - ``` Rinominare un dataset ```bash $ zfs rename zroot/root/home zroot/root/old_home $ zfs rename zroot/root/new_home zroot/root/home ``` Eliminare un dataset ```bash # I dataset non possono essere eliminati se hanno degli snapshot $ zfs destroy zroot/root/home ``` Lettura/modifica proprietà ```bash # Tutte le proprietà di un dataset $ zfs get all zroot/usr/home NAME PROPERTY VALUE SOURCE zroot/home type filesystem - zroot/home creation Mon Oct 20 14:44 2014 - zroot/home used 11.9G - zroot/home available 94.1G - zroot/home referenced 11.9G - zroot/home mounted yes - ... # Proprietà specifica $ zfs get compression zroot/usr/home NAME PROPERTY VALUE SOURCE zroot/home compression off default # Modifica di una proprietà $ zfs set compression=lz4 zroot/lamb # Specifiche proprietà per tutti i dataset $ zfs list -o name,quota,reservation NAME QUOTA RESERV zroot none none zroot/ROOT none none zroot/ROOT/default none none zroot/tmp none none zroot/usr none none zroot/home none none zroot/var none none ... ``` ### Snapshot Gli snapshot sono una delle funzioni più importanti di ZFS: * Lo spazio occupato è la differenza tra il filesystem e l'ultimo snapshot * Il tempo di creazione è di pochi secondi * Possono essere ripristinati alla velocità di scrittura del disco * Possono essere automatizzati molto semplicemente Azioni: * Create * Delete * Rename * Access * Send / Receive * Clone Creazione di uno snapshot ```bash # Crea uno snapshot di un singolo dataset zfs snapshot zroot/home/sarlalian@now # Crea uno snapshot di un dataset e dei suoi sottodataset $ zfs snapshot -r zroot/home@now $ zfs list -t snapshot NAME USED AVAIL REFER MOUNTPOINT zroot/home@now 0 - 26K - zroot/home/sarlalian@now 0 - 259M - zroot/home/alice@now 0 - 156M - zroot/home/bob@now 0 - 156M - ... ``` Eliminazione di uno snapshot ```bash # Elimina uno snapshot $ zfs destroy zroot/home/sarlalian@now # Elimina uno snapshot ricorsivamente $ zfs destroy -r zroot/home/sarlalian@now ``` Rinominare uno snapshot ```bash $ zfs rename zroot/home/sarlalian@now zroot/home/sarlalian@today $ zfs rename zroot/home/sarlalian@now today $ zfs rename -r zroot/home@now @yesterday ``` Accedere ad uno snapshot ```bash # Utilizzare il comando cd come per una directory $ cd /home/.zfs/snapshot/ ``` Invio e ricezione ```bash # Backup di uno snapshot su un file $ zfs send zroot/home/sarlalian@now | gzip > backup_file.gz # Invia uno snapshot ad un altro dataset $ zfs send zroot/home/sarlalian@now | zfs recv backups/home/sarlalian # Invia uno snapshot ad un host remoto $ zfs send zroot/home/sarlalian@now | ssh root@backup_server 'zfs recv zroot/home/sarlalian' # Invia l'intero dataset e i suoi snapshot ad un host remoto $ zfs send -v -R zroot/home@now | ssh root@backup_server 'zfs recv zroot/home' ``` Clonare gli snapshot ```bash # Clona uno snapshot $ zfs clone zroot/home/sarlalian@now zroot/home/sarlalian_new # Rende il clone indipendente dallo snapshot originale $ zfs promote zroot/home/sarlalian_new ``` ### Letture aggiuntive (in inglese) * [BSDNow's Crash Course on ZFS](http://www.bsdnow.tv/tutorials/zfs) * [FreeBSD Handbook on ZFS](https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/zfs.html) * [BSDNow's Crash Course on ZFS](http://www.bsdnow.tv/tutorials/zfs) * [Oracle's Tuning Guide](http://www.oracle.com/technetwork/articles/servers-storage-admin/sto-recommended-zfs-settings-1951715.html) * [OpenZFS Tuning Guide](http://open-zfs.org/wiki/Performance_tuning) * [FreeBSD ZFS Tuning Guide](https://wiki.freebsd.org/ZFSTuningGuide) ================================================ FILE: ja/asciidoc.md ================================================ --- contributors: - ["Ryan Mavilia", "http://unoriginality.rocks/"] - ["Abel Salgado Romero", "https://twitter.com/abelsromero"] translators: - ["Ryota Kayanuma", "https://github.com/PicoSushi"] --- AsciiDocはMarkdownに似たマークアップ言語で、書籍の執筆からブログを書くことまでなんでも使うことができます。2002年、Stuart RackhamによりAsciiDocは作成され、シンプルでありつつも沢山のカスタマイズを可能にしています。 文書のヘッダー ヘッダーはオプションで、空行を含むことはできません。本文から1行以上の改行を開ける必要があります。 タイトルのみの例 ``` = 文章タイトル 文書の最初の行 ``` タイトルと著者 ``` = 文書タイトル 文書 太郎 文書の開始 ``` 複数の著者 ``` = 文書タイトル John Doe ; Jane Doe; Black Beard 複数の著者による文書の始まり。 ``` 版(著者の行を必要とします) ``` = 第一版のタイトル 芋男 v1.0, 2016-01-13 このポテトについての文書は面白いです。 ``` 段落 ``` 段落は特別なことは不要です。 空行を段落の間に入れることで、段落を分けることができます。 折り返しをしたい場合、+ を書くことで折り返せます! ``` 文書の整形 ``` _アンダースコアで斜体になります。_ *アスタリスクで太字になります。* *_組み合わせると楽しい_* `バッククォートで固定幅になります。` `*太字の固定幅*` ``` 節タイトル ``` = Level 0 (文書のヘッダーにのみ使用してください) == Level 1

=== Level 2

==== Level 3

===== Level 4

``` リスト 箇条書きリストを作るには、アスタリスクを使用してください。 ``` * foo * bar * baz ``` 番号付きリストを作るには、ピリオドを使用してください。 ``` . item 1 . item 2 . item 3 ``` リストはアスタリスクやピリオドを追加することで5段階まで入れ子にできます。 ``` * foo 1 ** foo 2 *** foo 3 **** foo 4 ***** foo 5 . foo 1 .. foo 2 ... foo 3 .... foo 4 ..... foo 5 ``` ## 補足資料 AsciiDocの文書を処理するツールは2種類あります。 1. [AsciiDoc](http://asciidoc.org/): オリジナルのPython実装で、Linuxで利用可能です。現在は開発されておらず、メンテナンスのみの状態です。 2. [Asciidoctor](http://asciidoctor.org/): Rubyによる別実装で、JavaやJavaScriptでも利用可能です。AsciiDocに新しい機能や出力形式を追加するため、現在活発に開発されています。 以下のリンクは `AsciiDoctor` 実装関連のものです。 * [Markdown - AsciiDoc syntax comparison](http://asciidoctor.org/docs/user-manual/#comparison-by-example): Common MarkdownとAsciidocの要素を並べて比較しています。 * [Getting started](http://asciidoctor.org/docs/#get-started-with-asciidoctor): インストールから簡潔な文書を作るための簡単なガイドです。 * [Asciidoctor User Manual](http://asciidoctor.org/docs/user-manual/): 文法のリファレンス、例、描画ツール、その他を含む完全なドキュメントです。 ================================================ FILE: ja/bash.md ================================================ --- contributors: - ["Max Yankov", "https://github.com/golergka"] - ["Darren Lin", "https://github.com/CogBear"] - ["Alexandre Medeiros", "http://alemedeiros.sdf.org"] - ["Denis Arh", "https://github.com/darh"] translators: - ["akirahirose", "https://twitter.com/akirahirose"] --- Bash はunixシェルの1つです。GNUオペレーションシステムのシェルとして配布されています。 LinuxやMac OS Xの、デフォルトシェルにもなっています。 以下にある例は、ほぼ全部シェルスクリプトの一部として使えます。また、一部はそのままシェルから実行できます。 ```bash #!/bin/bash # 最初の行はShebang(シェバング、シバン)というもので、システムに対して何を使って実行するのかを教えるためのものです # ちゃんとした説明、こちらをどうぞ: http://en.wikipedia.org/wiki/Shebang_(Unix) # 既にお気づきのように、コメント行は#で始まります. Shebangもコメントです # まずは Hello world です echo Hello world! # コマンド毎に改行を入れるか、セミコロンで区切ります echo 'This is the first line'; echo 'This is the second line' # 変数の宣言はこのようにやります VARIABLE="Some string" # が、以下のようにやってはダメです VARIABLE = "Some string" # このように(空白を入れて)書くと、Bash はVARIABLEを実行するべきコマンドとみなし、実行します。 # そして、VARIABLEというコマンドはない(はずな)ので、エラーになります # 変数の使い方 echo $VARIABLE echo "$VARIABLE" echo '$VARIABLE' # 変数の値(中身)を使わず、変数名だけを使うとき(代入するときや渡すときなど)は、$なしで変数名を書いてください # 変数の値(中身)を使うときは、$をつけます # 上記例の最後にある、' (シングルクォート) で囲んだ場合は、変数の値は表示されません! # 変数値の文字列置換 echo ${VARIABLE/Some/A} # 最初に出てくる "Some" を "A" で置換します # 変数値の一部を取り出します echo ${VARIABLE:0:7} # 最初の7文字だけを取り出します # デフォルトの変数値設定(訳注:シェル実行時に引数で変数値を設定できるが、設定しなかった場合の値を指定できる) echo ${FOO:-"DefaultValueIfFOOIsMissingOrEmpty"} # 上記は、FOO番目の引数がnullだったとき(FOO番目=)や、空文字が指定されたとき(FOO番目="")に、変数に0を入れます # ( 当然ですが、引数に0を指定したとき(FOO番目=0) も、0は入ります) # 組込み変数 # 以下のような便利な組込み変数があります echo "Last program return value: $?" echo "Script's PID: $$" echo "Number of arguments: $#" echo "Scripts arguments: $@" echo "Scripts arguments separated in different variables: $1 $2..." # 入力値の読み込み echo "What's your name?" read NAME # 新しく変数を宣言する必要はないことに注意 echo Hello, $NAME! # 普通のif文も使えます # 利用できる判定条件については、'man test' で参照してください if [ $NAME -ne $USER ] then echo "Your name is your username" else echo "Your name isn't your username" fi # 他にも、条件判定ができます echo "Always executed" || echo "Only executed if first command fails" echo "Always executed" && echo "Only executed if first command does NOT fail" # 数式は以下のように書きます echo $(( 10 + 5 )) # 他のプログラム言語とは違ってbashはシェルなので、現在いるディレクトリ位置が異なると、異なる結果になります # lsコマンドで、現在いるディレクトリにあるファイルと、ディレクトリのリストが取得できます ls # これらのコマンドには、実行オプションがいろいろあります ls -l # ファイルとディレクトリのリストを行に分けて表示します # あるコマンド実行による返値を、次のコマンドの入力値としてつかえます # 例えばですが、lsコマンドの返値を、grepコマンドによって指定したルールに基づいてフィルタできます。 # 以下は、現在いるディレクトリにある、.txtファイルのリストを表示する例です ls -l | grep "\.txt" # コマンドに対する入力元や出力先、またエラー出力先などを変更できます python2 hello.py < "input.in" python2 hello.py > "output.out" python2 hello.py 2> "error.err" # 出力先として指定したファイルが既に存在する場合は、上書きされます # もしもファイルに追記したい場合は、代わりに">>" を使ってください # コマンド文中で、$()内に別コマンドを入れると、その別コマンドの返値をコマンド文の一部として使う事ができます # 次のコマンドは、現在いるディレクトリにあるファイルの数を表示します echo "There are $(ls | wc -l) items here." # バッククォート(backticks) `` でも同じことができますが、入れ子にはできません # そのため、$()がお勧めです echo "There are `ls | wc -l` items here." # BashはJavaやC++のように、case文による分岐ができます case "$VARIABLE" in #分岐条件として使いたいパターンを並べてください 0) echo "There is a zero.";; 1) echo "There is a one.";; *) echo "It is not null.";; esac # 指定した回数、処理を繰り返し # 変数の値 $VARIABLE が3回表示されます for VARIABLE in {1..3} do echo "$VARIABLE" done # while ループです while [true] do echo "loop body here..." break done # 関数の定義もできます function foo () { echo "Arguments work just like script arguments: $@" echo "And: $1 $2..." echo "This is a function" return 0 } # 以下のように、もっと簡単な書き方もあります bar () { echo "Another way to declare functions!" return 0 } # 自作関数を呼びます foo "My name is" $NAME # 他にもいろいろと、知っておくと便利なコマンドがあります # file.txtの最後10行を表示します tail -n 10 file.txt # file.txtの最初10行を表示します head -n 10 file.txt # file.txt's の行を並び替えます sort file.txt # 重複している行を表示するか、削除できます。-dオプションをつけると、表示します uniq -d file.txt # 1行ごとに、','が最初に出てくる前の部分を表示します cut -d ',' -f 1 file.txt ``` [ちゃんとした説明は、こちらをどうぞ](https://www.gnu.org/software/bash/manual/bashref.html) ================================================ FILE: ja/c.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"] - ["Jakub Trzebiatowski", "http://cbs.stgn.pl"] - ["Marco Scannadinari", "https://marcoms.github.io"] - ["Zachary Ferguson", "https://github.io/zfergus2"] - ["himanshu", "https://github.com/himanshu81494"] - ["Joshua Li", "https://github.com/JoshuaRLi"] - ["Dragos B. Chirila", "https://github.com/dchirila"] - ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"] translators: - ["Kenryu Shibata", "https://github.com/kenryuS"] --- え、C? あぁ、**未だに**モダンで高パフォーマンスを実現できるあの言語のことだな。 Cはほとんどのプログラマが最低水準言語として使われているが、その特徴は実行速度の速さだけ ではないのだ。CはPythonなどの高水準言語とは異なり、メモリの自動管理機能がなく、 プログラマーの手で管理する必要があり、これが初学者を苦しめる要素となるが、うまく使えば、 ロボットなどで実行速度やメモリの使用率などを大幅に最適化できる。 ```c // 行コメントは//で始まる (C99より前のC標準では使えない) // Cに限ったことではないが、ソースコードで日本語コメントを書くときにはファイルを // UTF-8で保存することをおすすめします。なぜならgccなど特定のコンパイラでは // 文字コード変換の影響で意図しないコメントアウトが引き起こされる可能性があります。 // 例: // forループで似たコードの繰り返しを解消することが可能 // このコメントを消すと何故か動かない for (int i = 0; i < 100; i++) { printf("%d\n", i); } // 解説:shift-jisで「能」は 94 5c で、標準ASCIIでは 5c は"\"でLinux gccでは // 次の行もコメントアウトされる仕様で、この例ではforループの最初の定義が // コメントアウトされエラーとなります。 /* 複数行コメント、C89標準でも使える。 */ /* 複数行コメントはネストできないので/*注意*/ // コメントはここで終わり、 */ // ここのコメント終了は扱われない。 // 定数・マクロ:#define <定数名(英数字のみ)> // 定数はすべて大文字で定義することをおすすめします。 #define DAYS_IN_YEAR 365 // 列挙体も定数を定義する方法の一つです。 // すべてのコード行は半角英数字で書き、セミコロン「;」で終わる必要があります。 enum days {SUN, MON, TUE, WED, THU, FRI, SAT}; // SUNは0、MONは1、TUEは2、などと続く。 // 列挙体の値は別の値にできますが、数字が大きくなるようにする必要があります。 enum days {SUN = 1, MON, TUE, WED = 99, THU, FRI, SAT}; // MONは自動的に2、TUEは3、と続き、WEDで99、THUは100、FRIは101、などと続く。 // #include でヘッダーファイルをインポートできる。 #include #include #include // <アングルブラケット>で囲まれたファイル名はヘッダーファイルをシステムライブラリから // 探すことをコンパイラに伝え、自分で書いたヘッダーファイルを使うときには ”引用符” で //そのファイルのパスを囲みます。 #include "my_header.h" // ローカルファイル #include "../my_lib/my_lib_header.h" // 相対パス // 予め関数を .h (ヘッダー)ファイルで宣言するか、 // .c (ソースコード)ファイルの上方に書いて宣言してください。 void function_1(); int function_2(void); // 関数を使用する前に、最低でも、関数プロトタイプを宣言しなければなりません。 // プロトタイプは関数定義の前に書くのが一般的です。 int add_two_ints(int x1, int x2); // 関数プロトタイプ // 上記の書き方でも問題ありませんが(引数の連番)、引数にはコード保守を // 容易にするためになるべくちゃんとした名前をつけてあげましょう。 // 関数プロトタイプはその関数を使う前に定義を書いておけば必要ありません。 // しかし、関数プロトタイプをヘッダーファイルに記述し、ソースコードの上方に#includeを // 使ってインポートすれば、コンパイラにまだ定義されていない関数を呼び出すことを防ぎ、 // ヘッダーファイルにどんな関数が定義されるのかが分かるのでプログラムの保守性も上がります。 // プログラムが最初に実行する関数はエントリーポイントといい、Cではmain()関数となります。 // 返り値はどんな型でも良いですが、Windowsなどの大抵のOSはエラーコードを検知・処理するために // 関数はint型(整数型)を返すことが定められています。 int main(void) { // プログラムはここへ } // コマンドライン引数はプログラムの挙動やオプションを実行時に設定することができます。 // argcは引数の数を表し、プログラム名もカウントされるので常に1以上の値が入ります。 // argvは引数文字列の配列を表し、プログラム名含むすべての引数が入るます。 // argv[0]はプログラム名を、argv[1]は最初の引数などです。 int main (int argc, char** argv) { // コンソールに文字などを表示するときにはprintf関数を使います。 // printfは”print format”のことで、書式に沿って値を表示させます。 // %dには整数が入り、\nは新しい行("n"ew line)へ移動します。 printf("%d\n", 0); // => 0が表示される // scanf関数はコンソールからユーザの入力を受け付けます。 // 変数の前の'&'記号はメモリ上の変数の住所(address)を求める一種の演算子です。 // この例では整数型の値をinput変数の住所に値を代入します。 int input; scanf("%d", &input); /////////////////////////////////////// // 型 /////////////////////////////////////// // C99標準の互換性がないコンパイラでは、そのスコープで使用するすべての変数は // スコープの一番上に宣言する必要があります。C99標準互換のコンパイラは、使用する前なら // スコープ内のどこでも宣言可能です。このチュートリアルでは、C99標準に統一して書いていきます。 // int型は大抵の場合整数を4バイトのメモリで格納しますが、古いCPUでは2バイトで格納します。 // sizeof演算子を使えば、その型が何バイト使うか確認できます。 int x_int = 0; // short型は2バイトで整数を格納。 short x_short = 0; // char型は大抵のプロセッサーでは、最小のサイズで、 // 1バイトのサイズで整数またはASCII文字一つを格納できます。 // この型のサイズはプロセッサーによって異なり、2バイト以上の物もあります。 // (例:TIからリリースされたTMS320は2バイトで格納される。) char x_char = 0; char y_char = 'y'; // ASCII文字リテラルは''で囲まれる。 // long型は4~8バイトで整数を格納します。long long型は常に8バイトであることが保証されます。 long x_long = 0; long long x_long_long = 0; // float型は32ビットの単精度浮遊少数を格納します。 float x_float = 0.0f; // 'f'はその数字リテラルが単精度浮遊少数であることを示します。 // double型は64ビットの倍精度浮遊少数を格納します。 double x_double = 0.0; // 実数のあとに何もつかない数字リテラルは倍精度浮遊少数として扱います。 // 整数型はunsignedをつけることで0以上の正の数のみを格納させることができます。 unsigned short ux_short; unsigned int ux_int; unsigned long long ux_long_long; // char型に格納されている文字はASCIIなどの文字コードに対応する整数でもあります。 '0'; // => ASCIIで48を表す。 'A'; // => ASCIIで65を表す。 // sizeof(T)でその型のサイズをバイトで返す(Tには型名が入る。) // sizeof(obj)はその値の型のサイズを返す。(objには定数、変数、生の値が入る。) printf("%zu\n", sizeof(int)); // => 4 (on most machines with 4-byte words) // もしsizeof演算子の引数が式だった場合、VLA(可変長配列、Variable Length Array)でない限り、 // その式は評価されません。この場合の引数の値はコンパイル時定数である。 int a = 1; // size_t型は変数などの型サイズを表す2バイト以上の非負の整数を格納します。 size_t size = sizeof(a++); // a++ は評価されない。 printf("sizeof(a++) = %zu where a = %d\n", size, a); // prints "sizeof(a++) = 4 where a = 1" (32ビット環境での場合) // 配列は定義時にサイズを決める必要があります。 char my_char_array[20]; // この配列は 1 * 20 = 20 バイト使います int my_int_array[20]; // この配列は 4 * 20 = 80 バイト使います // (4バイト整数環境であると仮定した場合) // 次の定義では整数配列を20個の0で埋めた状態で初期値が与えられます。 int my_array[20] = {0}; // "{0}"は配列初期化子です。 // 初期化子に含まれる要素以外の要素は、(もしあれば)すべて0に初期化されます: int my_array[5] = {1, 2}; // 上記の定義ではmy_arrayは5つの要素があり、最初の2つ以外は0に初期化されています: // [1, 2, 0, 0, 0] // 配列定義のときに明示的に初期化を行えば、要素数を決める必要がなくなります: int my_array[] = {0}; // サイズを指定しないで定義すると配列初期化子の要素数がそのまま自動的に決めまれます。 // よって"{0}"で初期化した場合、配列のサイズは1となり、"[0]"が代入されます。 // 実行時に配列の要素数を調べるには、配列のサイズを1つの要素のサイズで割れば良いのです。 size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]); // 注意;この操作は配列ごとに、かつ関数に渡す前に実行することを勧めします。なぜなら // 関数に配列を渡すと、ポインター(メモリ上の場所を表す単なる整数)に変換され、 // 関数内で同じ操作を行うと、間違った結果につながる恐れがあるからです。 // 要素へアクセスするときは他の言語と同じようにできます。 // 正しく言えば、Cに似た言語です。 my_array[0]; // => 0 // 配列は変更可能です。 my_array[1] = 2; printf("%d\n", my_array[1]); // => 2 // C99標準以降(C11では任意選択)では、可変長配列(VLA)が使用可能で、コンパイル時に // 定数による要素数指定をしなくても、変数などによる指定ができるようになります。 printf("Enter the array size: "); // ユーザーに要素数を入力してもらう。 int array_size; fscanf(stdin, "%d", &array_size); int var_length_array[array_size]; // VLAを宣言する。 printf("sizeof array = %zu\n", sizeof var_length_array); // 例: // > Enter the array size: 10 // > sizeof array = 40 // 文字列はヌル文字(0x00, '\0')で終わる配列でもあります。 // 文字列リテラルを使用する場合はコンパイラが末尾に塗る文字を追加するので明示的に // 入れなくても良いです。 char a_string[20] = "This is a string"; printf("%s\n", a_string); // %s フォーマットで文字列を表示 printf("%d\n", a_string[16]); // => 0 // 例, 17番目のバイトは0 (18, 19, 20番目も同様) // シングルクォーテーションで囲まれた文字は文字リテラルです。これはchar型*ではなく*、 // int型です。(これには歴史的背景があります。) int cha = 'a'; // OK char chb = 'a'; // これもOK (intからcharへの暗黙的型変換) // 多次元配列: int multi_array[2][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 0} }; // 要素の取得: int array_int = multi_array[0][2]; // => 3 /////////////////////////////////////// // 演算子 /////////////////////////////////////// // 複数の同一型変数の略記法: int i1 = 1, i2 = 2; float f1 = 1.0, f2 = 2.0; int b, c; b = c = 0; // 四則演算は直感的にかけます: i1 + i2; // => 3 i2 - i1; // => 1 i2 * i1; // => 2 i1 / i2; // => 0 (0.5だが、0に繰り下げられている) // 結果を少数にするにはどちらか一方の変数をfloat型へキャスティングする必要がある。 (float)i1 / i2; // => 0.5f i1 / (double)i2; // => 0.5 // double型でも同様の操作ができる f1 / f2; // => 0.5, プラスマイナス計算機イプシロン(その型が表せる最小の少数) // 浮動小数点数はIEEE 754の仕様で定義されているので、コンピューターは正確な // 数をメモリ上で保存できない。よって意図しない数になることがある。例えば、0.1は // 0.099999999999、0.3は0.300000000001として保存されているかもしれません。 (0.1 + 0.1 + 0.1) != 0.3; // => 1 (真) // なのでこれは上記の理由でこの真偽式は真になりません。 1 + (1e123 - 1e123) != (1 + 1e123) - 1e123; // => 1 (真) // こちらは科学的表記法です : 1e123 = 1*10^123 // ほとんどのシステムはIEEE 754に基づいて浮動小数点数を定義していることを // 知っておくことが重要になってきます。科学演算で多用されるPythonでも最終的に // IEEE 754を使うCを呼び出すことになります。この注意書きはCの浮動小数点数の // 仕様が悪く使うべきではないということをほのめかすのではなく、こういった誤差 // (イプシロン)を考慮した上で比較するというのを頭に入れておくために書かれました。 // 剰余演算もありますが、負の値を計算するときには注意してください: 11 % 3; // => 2 (11 = 2 + 3*x (x=3)) (-11) % 3; // => -2 (-11 = -2 + 3*x (x=-3)) 11 % (-3); // => 直感に反し被除数と同じ符号になる、2 (11 = 2 + (-3)*x (x=-3)) // 比較演算は親しみがあるかもしれませんが、Cには真偽型がなく、 // 代わりに整数型が使われます。(C99以降は _Bool型がstdbool.hで // 提供されました。) 0は偽を表し、それ以外はすべて真として扱います。 // 比較演算を使用する際は必ず0か1を返します。 3 == 2; // => 0 (偽) 等しい 3 != 2; // => 1 (真) 等しくない 3 > 2; // => 1 より大きい 3 < 2; // => 0 より小さい 2 <= 2; // => 1 以下 2 >= 2; // => 1 以上 // CはPythonではないので、演算子の連鎖はできません。 // 下記の例では問題なくコンパイルしますが、`0 < a < 2`は`(0 < a) < 2`になり、 // `(0 < a)`の結果が真でも偽でも結局`0 < 2`または`1 < 2`となるので常に真となります。 int between_0_and_2 = 0 < a < 2; // 代わりにこう書きます: int between_0_and_2 = 0 < a && a < 2; // 整数に対する論理演算子: !3; // => 0 (否定) !0; // => 1 1 && 1; // => 1 (論理積) 0 && 1; // => 0 0 || 1; // => 1 (論理和) 0 || 0; // => 0 // 条件付き三元式 ( ? : ) int e = 5; int f = 10; int z; z = (e > f) ? e : f; // => 10 "もし(e > f)が真ならばeを、偽ならばfを返す。" // 加算・減算演算子: int j = 0; int s = j++; // jを返してからjを1増やす (s = 0, j = 1) s = ++j; // jを1増やしてからjを返す (s = 2, j = 2) // 減算演算子 j-- と --j でも同様 // ビット演算子 // 整数などのデータは0と1の2進数で表されておりそれぞれをビットといいます。 // これらの演算子は各ビットに論理演算を適用します。 ~0x0F; // => 0xFFFFFFF0 (ビット単位NOT、補数、32ビット16進数整数での例) 0x0F & 0xF0; // => 0x00 (ビット単位AND) 0x0F | 0xF0; // => 0xFF (ビット単位OR) 0x04 ^ 0x0F; // => 0x0B (ビット単位XOR) 0x01 << 1; // => 0x02 (算術左シフト (1ビット幅)) 0x02 >> 1; // => 0x01 (算術右シフト (1ビット幅)) // 正負のついた整数に対するビットシフトには注意してください - これらの操作は未定義です: // - 符号ビットへのビットシフト (int a = 1 << 31) // - 負の整数を左シフトする (int a = -1 << 2) // - 型のビットサイズ以上の幅でシフト: // int a = 1 << 32; // 32ビット幅の整数の場合では未定義の動作 /////////////////////////////////////// // 制御構造 /////////////////////////////////////// // 条件文 if (0) { printf("I am never run\n"); } else if (0) { printf("I am also never run\n"); } else { printf("I print\n"); } // whileループ文 int ii = 0; while (ii < 10) { // 10以下の整数がこの条件を満たす printf("%d, ", ii++); // ii++ が値を使用してから1加算される。 } // => "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "が出力される printf("\n"); // do-whileループ文 int kk = 0; do { printf("%d, ", kk); } while (++kk < 10); // ++kk が値を使用する*前*に1加算される. // => "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "が出力される printf("\n"); // forループ文 int jj; for (jj=0; jj < 10; jj++) { printf("%d, ", jj); } // => "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "が出力される printf("\n"); // *****注*****: // ループ文、関数には最低でも一つの命令・文が必要になります: int i; for (i = 0; i <= 5; i++) { ; // セミコロン単体で何もしないという命令を作れる(ヌル命令) } // 別の表記法: for (i = 0; i <= 5; i++); // switch文(if文より高速) switch (a) { case 0: // caseレーベルにはint型や列挙型やchar型等の整数で表せるものに限定されます。 printf("Hey, 'a' equals 0!\n"); break; // ブレイク文がなければ後続のcaseレーベルも実行されてしまいます。 case 1: printf("Huh, 'a' equals 1!\n"); break; // break文がそのcaseレーベルになければ、break文があるレーベルまですべて実行されます。 case 3: case 4: printf("Look at that.. 'a' is either 3, or 4\n"); break; default: // 上記の条件がすべて合致しなければdefaultレーベル下の命令が実行されます。 fputs("Error!\n", stderr); exit(-1); break; } // goto文 typedef enum { false, true } bool; // C99より前のC標準ではブール値が標準で定義されていません。 bool disaster = false; int i, j; for(i=0; i<100; ++i) for(j=0; j<100; ++j) { if((i + j) >= 150) disaster = true; if(disaster) goto error; // 両方のforループから抜ける } error: // goto error;"で"error"レーベルまで「ジャンプ」します。 printf("Error occurred at i = %d & j = %d.\n", i, j); /* この例の出所: https://ideone.com/GuPhd6 "Error occurred at i = 51 & j = 99."が出力されます。 */ /* ほとんどの場合、goto文を使うのは、そのコードが何をするかわかっていない限り、 良くないとされています。詳細は https://ja.wikipedia.org/wiki/スパゲッティプログラム#goto文の濫用 を読んでください。 */ /////////////////////////////////////// // 型キャスティング(型変換) /////////////////////////////////////// // すべての値には型がありますが、これらは、互換性がある別の型にキャスティングすることができます。 int x_hex = 0x01; // 16進数リテラルで変数を定義できます。 // 2進数リテラルにはコンパイラごとに差があります。 // (GCCではx_bin = 0b0010010110) // 型キャスティングを行うとその値を保持しようとします。 printf("%d\n", x_hex); // => 1 printf("%d\n", (short) x_hex); // => 1 printf("%d\n", (char) x_hex); // => 1 // キャスティング先の型のサイズより大きい値をキャストすると警告なしに値が丸められます。 printf("%d\n", (unsigned char) 257); // => 1 (8ビット長のunsigned char型が保持できる最大値は255) // char, signed char, unsigned char型の最大値はそれぞれ、で提供される // CHAR_MAX, SCHAR_MAX, UCHAR_MAXマクロを使用できます。 // 整数型と浮動小数点数型は双方向にキャスティング可能です。 printf("%f\n", (double) 100); // %f はdouble型と printf("%f\n", (float) 100); // float型をフォーマットします。 printf("%d\n", (char)100.0); /////////////////////////////////////// // ポインター /////////////////////////////////////// // ポインターはメモリ上のアドレスを保持する整数の変数であり、型と共に宣言・定義されます。 // 変数から直接アドレスを取得できることができます。 int x = 0; printf("%p\n", (void *)&x); // &を用いて変数のアドレスを取得します。 // (%p は void *型の値をフォーマットします。) // => 結果: 変数が保持されているメモリーアドレスが表示される // ポインターは型名の直後にまたは変数名の直前に * を書いて宣言・定義します。 int *px, not_a_pointer; // px はint型の値を指すポインター px = &x; // pxにxのアドレスを代入する。 printf("%p\n", (void *)px); // => &xと同様の結果が出力されるはずです。 printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); // => 64ビット環境では"8, 4"が出力されます。 // ポインターから指示しているメモリー領域の値を取得(ディレファレンス)するには // ポインター宣言と同じようにポインター名の前に * を書きます。 printf("%d\n", *px); // => xの値である0を出力 // この機能を用いて、ポインターが指示している値を変更することができます。 // 加算演算子はディレファレンス演算子より優先順位が高いので数学同様ディレファレンス操作を // 丸括弧で括ります。 (*px)++; // pxが指しているxの値を1加算する printf("%d\n", *px); // => 1 printf("%d\n", x); // => 1 // 配列は連続したメモリー領域を確保するのに有効です。 int x_array[20]; // 長さ20の不可変長配列を宣言 int xx; for (xx = 0; xx < 20; xx++) { x_array[xx] = 20 - xx; } // x_arrayの値を 20, 19, 18,... 2, 1 と一括初期化する。 // int型の値を指し示すポインターを宣言し、x_arrayのアドレスで初期化する int* x_ptr = x_array; // x_ptrは整数20個の配列の最初の要素を指しています。 // この場合配列は代入時に最初の要素へのポインターへ変換されます。 // 関数に配列を渡す際にも暗黙的にポインターに変換されます。 // 例外:`&`を配列に適用した場合、その配列のアドレスが返り、要素の型ではなく、 // 配列型のポインターが使用されます: int arr[10]; int (*ptr_to_arr)[10] = &arr; // &arr は `int *`型ではない! // これは「(10個の整数の)配列へのポインター」型です。 // もう一つの例外には文字列リテラルをchar型配列に代入する場合: char otherarr[] = "foobarbazquirk"; // または、`sizeof`, `alignof`演算子を使用した場合: int arraythethird[10]; int *ptr = arraythethird; // equivalent with int *ptr = &arr[0]; printf("%zu, %zu\n", sizeof(arraythethird), sizeof(ptr)); // "40, 4" または "40, 8" が出力されます。 // ポインター型の値を加算・減算するとその方に応じて操作できます。 // この操作のことをポインター演算といいます。 printf("%d\n", *(x_ptr + 1)); // => 19 printf("%d\n", x_array[1]); // => 19 // 標準ライブラリ関数の一つであるmallocを使えば連続したメモリ領域を動的に確保できます。 // malloc関数は確保するバイト数を設定するsize_t型の引数が一つあります。 // (確保するのは大抵の場合ヒープ領域に確保されますが、組み込みデバイスなどでは // 挙動が異なる場合があります。このことはC標準では説明されていません。) int *my_ptr = malloc(sizeof(*my_ptr) * 20); for (xx = 0; xx < 20; xx++) { *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx } // メモリー領域を整数型配列として初期化する [20, 19, 18 ... 1] // mallocで確保されたメモリー領域へのデータの書き込みには注意してください。 // 安全性を保証するには、確保すると同時にそのメモリー領域をすべて0で埋め尽くすcalloc関数を使用してください。 int* my_other_ptr = calloc(20, sizeof(int)); // Cには動的配列のサイズをその場で求める方法はほとんどなく、関数などに渡すときに要素数を記録する別の変数が // 必要になることがよくあります。詳細は次の関数についてのセクションを読んでください。 size_t size = 10; int *my_arr = calloc(size, sizeof(int)); // 要素を追加する size++; my_arr = realloc(my_arr, sizeof(int) * size); // realloc関数で配列のサイズを更新する。 if (my_arr == NULL) { // mallocやreallocなどを使う際には領域確保に異常がない確認するために // ヌルチェックをすることをおすすめします。 return } my_arr[10] = 5; // 確保されていないメモリー領域へアクセスは予測不可能な結果を招く可能性があります。 printf("%d\n", *(my_ptr + 21)); // => who-knows-what? が出力される**かも**、クラッシュするかもしれない。 // メモリー領域の使用を終えたら必ずfree関数を使ってその領域を解放しなければなりません。 // 解放しなければ、プログラムが終了しても他のプログラムからそのメモリー領域を再利用できず、 // システム全体で使用できる容量が減ってしまいます。このことをメモリーリークと呼びます。 free(my_ptr); // my_ptrでポイントされてるメモリー領域を解放する。 // 文字列はchar型の配列で表せますが、よく使用されるのは文字列の最初の文字を指すcharポインターです。 // もし、単に文字列リテラルを使用するだけならば"const char*"を使い、変更不能にしておくことが推奨されています。 // なぜならば、本来文字列リテラルのデータは変更すべきではないからです。 // なので、" foo[0] = 'a' "といった操作はできません。 const char *my_str = "This is my very own string literal"; printf("%c\n", *my_str); // => 'T' // char型の配列で定義されている場合は別で、文字列リテラルで初期化できますが、 // 各要素は変更可能です。例に: char foo[] = "foo"; foo[0] = 'a'; // この操作は許されており、"aoo" に変更される。 function_1(); } // main 関数の終わり /////////////////////////////////////// // 関数 /////////////////////////////////////// // 関数定義の構文: // <戻り値の型> <関数名>(<引数>) int add_two_ints(int x1, int x2) { return x1 + x2; // returnで値を返す。 } /* 関数は値によって呼び出されます。関数が呼ばれると、引数として渡した値はコピーされ、 関数内で値を変更したとしても、渡した引数の値は変わりません。(配列はこれに従わない。) 関数内で引数の値を変更したい場合はポインターとして渡す必要があり、配列も渡すときに自動的にポインターになります。 例:即興文字列反転 */ // void型関数は値を返さない void str_reverse(char *str_in) { char tmp; size_t ii = 0; size_t len = strlen(str_in); // `strlen()` はC標準ライブラリ関数です。 // NOTE: `strlen` で返される文字列の長さは終端文字の // ヌルバイト('\0')を含んでいない状態です。 // C99標準以降では、ループ定義の中にループ制御変数が定義できます。 // 例:`for (size_t ii = 0; ...` for (ii = 0; ii < len / 2; ii++) { tmp = str_in[ii]; str_in[ii] = str_in[len - ii - 1]; // 後ろから ii 番目の要素 を 前から ii 番目の要素にする str_in[len - ii - 1] = tmp; } } //NOTE: string.h のヘッダーファイルを#includeしないとstrlen()関数が使用できません。 /* char c[] = "This is a test."; str_reverse(c); printf("%s\n", c); // => ".tset a si sihT" */ /* 一つの変数を変更することができるように、 ポインター渡しで複数の変数を変更できます。 */ void swapTwoNumbers(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } /* int first = 10; int second = 20; printf("first: %d\nsecond: %d\n", first, second); swapTwoNumbers(&first, &second); printf("first: %d\nsecond: %d\n", first, second); // 変数の値が交換される */ // 一度に複数の値を返す // Cではreturn文を使って複数の値を返すことができません。一度に複数の値を返すには、 // 引数にそれぞれの戻り値を格納する変数へのポインターを設定しなければなりません。 int return_multiple( int *array_of_3, int *ret1, int *ret2, int *ret3) { if(array_of_3 == NULL) return 0; //エラーコードを返す (偽) //値を変更するためにポインターをディレファレンスする。 *ret1 = array_of_3[0]; *ret2 = array_of_3[1]; *ret3 = array_of_3[2]; return 1; //エラーコードを返す (真) } /* 引数に配列型を使用するときは、配列は必ずポインターに変換されることに注意してください。これは malloc関数で動的に確保したものでも、静的に定義した配列でも同じことが起きます。繰り返しになるが、 Cでは引数として渡された動的配列の長さを標準仕様で知ることができません。 */ // 引数として配列のサイズを渡してください。 // でなければ、渡された配列の長さを知る術がありません。 void printIntArray(int *arr, size_t size) { int i; for (i = 0; i < size; i++) { printf("arr[%d] is: %d\n", i, arr[i]); } } /* int my_arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int size = 10; printIntArray(my_arr, size); // "arr[0] is: 1" などが出力される。 */ // 関数外で定義されている変数へアクセスするにはexternキーワードを使用します。 int i = 0; void testFunc() { extern int i; //この変数iは外部変数iとして使用できる } // 外部変数を他のソースファイルから見えないようにする: static int j = 0; // testFunc2()を使用する他のファイルは変数jに直接アクセスできない。 void testFunc2() { extern int j; } // staticキーワードはコンパイルユニット外での変数のアクセスを禁じ、プライベートにします。 // (大抵のシステムでのコンパイルユニットとは .c ソースコードのことを指す。) // このstaticキーワードは(コンパイルユニットの)グローバルスコープと関数スコープどちらでも使用できますが、 // 関数スコープで使用すると挙動が変わり、アクセス制限をするのではなく、変数の寿命がプログラム終了まで延長されます。 // これはその変数が関数の実行が終了したあともメモリーにとどまり、グローバル変数と同じように // 値を保持し続けることができるようになります。グローバル変数とは違って、変数は定義された関数のスコープ内のみで使用できます。 // 更に、staticで宣言された変数は初期値が与えられてなくても必ず0で初期化されます。 // **関数をstatic宣言することで変数と同じようにプライベートにすることができます。** /////////////////////////////////////// // ユーザー定義の型と構造体 /////////////////////////////////////// // typedefキーワードを使えば型の別名をつけることができます typedef int my_type; // my_type は int型の別名になった。 my_type my_type_var = 0; // int my_type_var = 0; と等しい // 構造体は複数のデータを一つにまとめたものであり、上から下の順で定義されたメンバーがメモリーに割り当てられる: struct rectangle { int width; int height; }; // この構造体のサイズは必ずしも // sizeof(struct rectangle) == sizeof(int) + sizeof(int) // にならない、なぜならコンパイル時にシステムがメモリーを割り当てやすい位置にパッディングするからである。[1] void function_1() { struct rectangle my_rec = { 1, 2 }; // メンバーは定義時に初期化できる // "." で個別のメンバーへアクセスできる my_rec.width = 10; my_rec.height = 20; // 構造体へのポインターも定義できる: struct rectangle *my_rec_ptr = &my_rec; // ディレファレンスしてからメンバーの値をセットするのも良いが... (*my_rec_ptr).width = 30; // 可読性を高めるために"->"を使ってポインターから直接メンバーへアクセスすることもできる。 my_rec_ptr->height = 10; // (*my_rec_ptr).height = 10; と同じ } // 毎回structを打たなくてもいいように構造体に別名をつけることができます typedef struct rectangle rect; // rect = struct rectangle int area(rect r) { return r.width * r.height; } // typedefは構造体定義と同時に使えます: typedef struct { int width; int height; } rect; // 無名構造体にrectと名付けている。 // これで struct rectangle r; // を打たなくても rect r; // と楽に宣言・定義できる // サイズが大きい構造体は値渡しの代わりにポインター渡しでコピー作成の時間・メモリー使用量増大を避けることができます: int areaptr(const rect *r) { return r->width * r->height; } /////////////////////////////////////// // 関数ポインター /////////////////////////////////////// /* 実行時には、関数はプログラムに決められたメモリーアドレスにあります。関数ポインターは他のポインターとほとんど変わりません。 違うところは、ポインターを使って関数を呼び出せることです。これにより、関数の引数として他の関数をコールバックとしてわすことができます。 難しいところは、他の変数へのポインターとは表記法が違ってくることです。 例:str_reverse関数をポインターとして使う */ void str_reverse_through_pointer(char *str_in) { // 戻り値がvoid型fの名前がついた関数ポインターを宣言する。 void (*f)(char *); // 引数も一緒に書きますが、指している関数と同じ戻り値と引数の型でなければなりません(引数名は入れずにただ型を列挙する)。 f = &str_reverse; // 関数のアドレスを代入する(アドレスは実行時に決定される)。 // f = str_reverse; これも正しくコンパイルできる - 配列同様ポインターに変換される (*f)(str_in); // 関数ポインターから実行する // f(str_in); // この表記法でも正しく実行できる } /* 同じ戻り値型と引数である限り、どの関数でも使えます。 可読性と単純性を実現するために、typedefが使われます。 */ typedef void (*my_fnp_type)(char *); // 下記で直背ポインター変数を宣言できます: // ... // my_fnp_type f; ///////////////////////////////////// // printf()を用いて文字などを出力する ///////////////////////////////////// //特殊文字: /* '\a'; // 警告 (ベル) 文字 '\n'; // 改行文字 '\t'; // タブ文字 (左揃えテキスト) '\v'; // 垂直タブ文字 '\f'; // (フォームフィードの)新規ページ '\r'; // 復帰文字 '\b'; // バックスペース文字 '\0'; // ヌル文字 - Cでは文字列終端文字として使用される。 // hello\n\0. \0が明示的に文字列の終わりを表している。 '\\'; // バックスラッシュ '\?'; // 疑問符 '\''; // シングルクォーテーションマーク '\"'; // ダブルクォーテーションマーク '\xhh'; // 文字コード(16進数) 例: '\xb' = 垂直タブ文字 '\0oo'; // 文字コード(8進数) 例: '\013' = 垂直タブ文字 // printf等で使われるフォーマティング: "%d"; // 整数 "%3d"; // 整数最低3桁表示 (右揃え) "%s"; // 文字列 "%f"; // 浮動小数点 "%ld"; // 長整数 "%3.2f"; // 小数点以下2桁、小数点以上最低3桁で表示される浮動小数点 "%7.4s"; // (文字列としての浮動小数点でも同じことができる) "%c"; // 文字(単一) "%p"; // ポインター 注:ポインターを渡すときには (void*) 型へ // 変換しなければならない。 "%x"; // 整数16進数表示 "%o"; // 整数8進数表示 "%%"; // "%" を挿入する */ /////////////////////////////////////// // 評価順序 /////////////////////////////////////// // 順位は上から下へ、一番上は優先順位が最も高い //------------------------------------------------------// // 演算子 | 優先順位 // //------------------------------------------------------// // () [] -> . | 左から右 // // ! ~ ++ -- + - *(型) sizeof | 右から左 // // * % | 左から右 // // + - | 左から右 // // << >> | 左から右 // // < <= > >= | 左から右 // // == != | 左から右 // // & | 左から右 // // ^ | 左から右 // // | | 左から右 // // && | 左から右 // // || | 左から右 // // ? : | 右から左 // // = += -= *= /= %= &= ^= |= <<= >>= | 右から左 // // , | 左から右 // //------------------------------------------------------// /******************************* ヘッダーファイル ********************************** ヘッダーファイルはC言語の重要な役割で、ソースファイル間の依存関係の管理を 容易にすることや関数などの宣言を他のファイルに分けることができます。 ヘッダーファイル内は通常のC言語と変わりませんが、ファイル拡張子が ".h" になっており、 同じディレクトリー(フォルダー)に存在するなら` #include "ファイル名.h" `で ヘッダーファイルで宣言した関数、定数などをソースファイルで使用できます。 */ /* セーフガードは#includeマクロを使用する際に、複数回宣言されるのを防ぎます。 特に互いを参照しあってしまう相互依存の場合に有効です。 */ #ifndef EXAMPLE_H /* もし EXAMPLE_H が定義されていないならば、*/ #define EXAMPLE_H /* マクロ EXAMPLE_H を定義する。*/ // ヘッダーファイル内で他のヘッダーファイルを #include することができます。 #include /* 通常と同じように、マクロを用いて定数を定義できます。これは ヘッダーファイルとそれを#includeしたソースファイルで使用できます。 */ #define EXAMPLE_NAME "Dennis Ritchie" // 関数マクロも定義できます #define ADD(a, b) ((a) + (b)) /* 引数である変数の周りに丸括弧がありますが、これはマクロの展開時に評価順序が 意図しないものにならないようにするためです。(例:関数 MUL(x, y) (x * y); があるとします。MUL(1 + 2, 3) は(1 + 2 * 3)と展開され、間違った答えが帰ってきます。) */ // struct, typedefも同じように定義できます。 typedef struct Node { int val; struct Node *next; } Node; // 列挙体も同じく、 enum traffic_light_state {GREEN, YELLOW, RED}; /* 関数プロトタイプもヘッダーファイルで宣言できます。ヘッダーファイルで定義を 書くのはよろしくないとされており、定義はソースファイルで記述することを 強く勧めます。 */ Node createLinkedList(int *vals, int len); /* これ以外の要素はソースファイルに残します。過剰な#includeや定義は1つの ヘッダーファイルには入れず、別の複数のヘッダーファイルかソースファイルに 分けてください。 */ #endif // if系列マクロの終わり ``` ## 関連記事、教材(一部英語) [CS50 日本語版](https://cs50.jp/) はハーバード大学が無料で公開しているコンピューターサイエンスコースで 字幕付きの動画と一緒にC, Python, SQL, HTML, CSS, JavaScriptなどの言語を使った素晴らしいコースです。 C言語を学ぶ者は第1-5週目を受けることをおすすめします。 [Learn C The Hard Way](http://learncodethehardway.org/c/) は有料だが、良い英語での教材です。 質問があるならば、[compl.lang.c Frequently Asked Questions](http://c-faq.com) を見るのが良い。 インデンテーションや空白の使い方はどこでも一定であることが望まれています。たとえそのコードが画期的で実行速度が速くとも、 可読性が確保できなければ保守性に欠けます。良いコーディングスタイルの一つには[Linuxカーネル](https://www.kernel.org/doc/Documentation/process/coding-style.rst)のものがあります。 それでも分からんことがあったら、GPTにかける前にググってこい。 Googleは友達だからな。 [1] [【C言語】構造体を作る上でのアライメントのお話。そもそもアライメントとは...](https://creepfablic.site/2019/09/16/clangu-alignment-padding/) ================================================ FILE: ja/css.md ================================================ --- contributors: - ["Mohammad Valipour", "https://github.com/mvalipour"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["Geoffrey Liu", "https://github.com/g-liu"] - ["Connor Shea", "https://github.com/connorshea"] - ["Deepanshu Utkarsh", "https://github.com/duci9y"] - ["Brett Taylor", "https://github.com/glutnix"] - ["Tyler Mumford", "https://tylermumford.com"] translators: - ["Kenryu Shibata", "https://github.com/kenryuS"] --- ウェブサイトはHTMLでページの構造を指定します。 CSS (カスケーディングスタイルシート) はページの**見た目**を指定する別の言語です。 CSSは単純な*ルール*で構成されています。それぞれが1つ以上の*セレクター*の視覚的*要素*を 指定した*値*にします。 この解説ページではCSS 2で書かれいていますが、CSS 3でより拡張性のある、 より新しい機能を使うことが出来ます。 **注釈:** CSSは視覚的な情報として出力するので、[dabblet](http://dabblet.com/)の様な、 CSSをすぐに試せる環境で学習することを勧めます。 この解説ページの主な目的は構文と小技の紹介です。 ## 構文 ```css /* コメントはスラッシュ・アスタリスクの中に書きます。 1行コメントはありません。*/ /* #################### ## セレクター ## #################### */ /* セレクターはページにある要素を指定します。 */ selector { property: value; /* その他のプロパティ...*/ } /* 例となる要素:
*/ /* 一つのクラスでセレクトする */ .class1 { } /* または、両方を使う */ .class1.class2 { } /* または、要素名だけで */ div { } /* または、ID名で */ #anID { } /* または、属性名で */ [attr] { font-size:smaller; } /* または、指定された値を持つ属性で */ [attr='value'] { font-size:smaller; } /* 指定した値で始まる属性 (CSS 3) */ [attr^='val'] { font-size:smaller; } /* または、値で終わる属性 (CSS 3) */ [attr$='ue'] { font-size:smaller; } /* または、半角スペースで分けられた値の持つどれかの属性 */ [otherAttr~='foo'] { } [otherAttr~='bar'] { } /* または、ダッシュで区切られた値のどれかの属性 例: "-" (U+002D) */ [otherAttr|='en'] { font-size:smaller; } /* 様々なセレクターを組み合わせることで限定されたセレクターを作ることができます。 その場合は、間に半角スペースを入れないでください。*/ div.some-class[attr$='ue'] { } /* 他の要素の子要素を指定することができます。*/ div.some-parent > .class-name { } /* または、要素の子孫を指定できます。子要素は親要素の直接的な子孫です。 (親要素からインデンテーション一回分)子孫は親要素からすべての インデンテーションされた階を含みます。*/ div.some-parent .class-name { } /* 注意:半角スペースのない同じセレクターは別の意味になります。 なんだと思いますか。*/ div.some-parent.class-name { } /* 一個前の要素を選択することもできます。*/ .i-am-just-before + .this-element { } /* または、その要素の前のすべての要素をすべて選択できます。*/ .i-am-any-element-before ~ .this-element { } /* いくつかのセレクターには擬似クラスがあり、要素が特定の状態のときだけ 適用するスタイルを指定できます。*/ /* 例えば、マウスカーソルが要素の上にホバーしている状態のスタイルを 指定するときは、*/ selector:hover { } /* リンク先にすでに訪れている状態を指定する場合は、*/ selector:visited { } /* または訪れていない場合は、*/ selected:link { } /* 要素が選択されている場合は、*/ selected:focus { } /* 親要素内の最初の子要素を指定する場合は、*/ selector:first-child {} /* 最後の要素を指定する場合は、*/ selector:last-child {} /* 擬似クラスのように、疑似子要素を使えば、特定の部分のスタイルを 指定できます。*/ /* 選択された要素の最初の疑似子要素を指定する。*/ selector::before {} /* 選択された要素の最後の疑似子要素を指定する。*/ selector::after {} /* アスタリスクを適切な場所に記述すれば、 ワイルドカードとしてすべての要素を指定することができます。 */ * { } /* すべての要素 */ .parent * { } /* すべての子孫要素 */ .parent > * { } /* すべての子要素 */ /* セレクタを一度にグループで複数選択して同じスタイルを 適用することができます。*/ selector1, selector2 { } /* #################### ## プロパティー ## #################### */ selector { /* 長さの単位は画面の大きさに対して相対的か絶対的なものを選べます */ /* 相対的単位 */ width: 50%; /* 親要素の幅に対する割合で指定する */ font-size: 2em; /* フォントサイズの何倍かで指定する */ font-size: 2rem; /* か、ルート要素のフォントサイズを元にする */ font-size: 2vw; /* ビューポートの幅1パーセントの何倍かで指定する (CSS 3) */ font-size: 2vh; /* ビューポートの高さでの指定 */ font-size: 2vmin; /* vhかvwのどちらかの小さい方を選びます */ font-size: 2vmax; /* または、大きい方 */ /* 絶対的単位 */ width: 200px; /* ピクセル */ font-size: 20pt; /* ポイント */ width: 5cm; /* センチメートル */ min-width: 50mm; /* ミリメートル */ max-width: 5in; /* インチ */ /* 色 */ color: #F6E; /* 省略された六進法値での色 */ color: #FF66EE; /* 六進法値での色 */ color: tomato; /* 名前の付いた色 */ color: rgb(255, 255, 255); /* rgb値での色 */ color: rgb(10%, 20%, 50%); /* rgbの割合での色 */ color: rgba(255, 0, 0, 0.3); /* rgba値での色(CSS3) 値は0 <= a <= 1 */ color: transparent; /* アルファ値を0にするのと同じ効果 */ color: hsl(0, 100%, 50%); /* hsl割合(CSS 3)での色 */ color: hsla(0, 100%, 50%, 0.3); /* アルファ値を含んだhsl割合での色 */ /* ボーダー */ border-width:5px; /* 幅を指定*/ border-style:solid; /* 線のスタイルを指定 */ border-color:red; /* 背景色を指定するときと似たようなこと */ border: 5px solid red; /* 上記の3つのプロパティーを一つのプロパティーで書く */ border-radius:20px; /* CSS3での新しいプロパティーです(ボーダー角半径) */ /* 画像を要素の背景として使う */ background-image: url(/img-path/img.jpg); /* url()内のクォーテーションは必須ではありません */ /* フォント */ font-family: Arial; /* フォント名に半角空白がある場合にはクォーテーションで囲む必要があります。 */ font-family: "Courier New"; /* もしフォントが存在しないなら、ブラウザが定義されたフォントを探します。 */ font-family: "Courier New", Trebuchet, Arial, sans-serif; } ``` ## 使い方 CSSファイルを`.css`拡張子で保存する. ```html
``` ## 順序と数珠繋ぎ性質 ある要素が複数のセレクタの対象となり、複数のプロパティが設定されることがあります。 このような場合、いずれかのルールが他よりも優先されます。より具体的なセレクタを持つルールは 具体的でないセレクタより優先され、スタイルシートの後で使用されるルールは前のものを上書きします。 (これは、リンクされた二つの異なるスタイルシートがある要素に対するルールを含み、 ルールが同じ具体性を持つ場合、リンクの順序が優先され、一番最初にリンクしたシートが スタイルを決定する、ということでもあります)。 この性質がキャスケーディング(数珠繋ぎ)と呼ばれ、CSSの名前もこの言葉からきています。 このようなCSSを考慮する: ```css /* A */ p.class1[attr='value'] /* B */ p.class1 { } /* C */ p.class2 { } /* D */ p { } /* E */ p { property: value !important; } ``` そしてこのようなHTML: ```html

``` スタイルの優先順位は次の通りです。 優先順位はブロック全体ではなく、 それぞれの**プロパティ**に対してであることを忘れないでください。 * `E`は、`!important`というキーワードがあるため、最も優先順位が高いです。 ただし、その使用は避けることが推奨されます。 * `F` はインラインスタイルなので、その次です。 * `A` は、他の何よりも「具体的」であるため、その次になります。 これは3つの指定子を持っています: 要素名 `p`、クラス名 `class1`、 属性名 `attr='value'` です。 * `C` は、`B` と同じ具体性を持っているにも関わらず優先され、次になり ます。これは `B` よりも後ろに書かれている事に起因します。 * `B`が次で、 * `D` が最後になります。 ## メディアクエリ CSSメディアクエリとは、CSS 3の機能で、印刷時や、特定の寸法やピクセル密度の画面上で、特定のCSSルールを適用する際の条件を指定できるものです。 セレクタの具体性を高めるものではありません。 ```css /* すべてのデバイスで使われるルール */ h1 { font-size: 2em; color: white; background-color: black; } /* 印刷するときにh1タグの印刷に使われるインクの量を減らす。 */ @media print { h1 { color: black; background-color: white; } } /* 画面の幅が480ピクセルより小さいときにフォントサイズを大きくする。 */ @media screen and (min-width: 480px) { h1 { font-size: 3em; font-weight: normal; } } ``` メディアクエリには次の機能があります: `width`, `height`, `device-width`, `device-height`, `orientation`, `aspect-ratio`, `device-aspect-ratio`, `color`, `color-index`, `monochrome`, `resolution`, `scan`, `grid` `min-` や `max-`は多くの機能名に前置することができます。 `resolution`機能は古いデバイスでは対応しておらず、`device-pixel-ratio`を代わりに使います。 多くのスマホやタブレットはウェブページに`viewport`メタタグをつけない限り、デスクトップに表示されるサイズで表示します。 ```html ``` ## 互換性 大抵のCSS2(または多くのCSS3)の機能はすべてのブラウザやデバイスで機能します。 しかしそれでも、1度ちゃんと新しい機能が動作するかを確認するのが無難です。 ## その他の資料(英語) * [CanIUse](http://caniuse.com) (互換性に関する細かい情報) * [Dabblet](http://dabblet.com/) (CSS テスター) * [Mozilla Developer Network's CSS documentation](https://developer.mozilla.org/en-US/docs/Web/CSS) (チュートリアルとレファレンス) * [Codrops' CSS Reference](http://tympanus.net/codrops/css_reference/) (レファレンス) * [DevTips' CSS Basics](https://www.youtube.com/playlist?list=PLqGj3iMvMa4IOmy04kDxh_hqODMqoeeCy) (チュートリアル) ## 関連記事(英語) * [Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade](http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/) * [Selecting elements using attributes](https://css-tricks.com/almanac/selectors/a/attribute/) * [QuirksMode CSS](http://www.quirksmode.org/css/) * [Z-Index - The stacking context](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context) * [SASS](http://sass-lang.com/) と [LESS](http://lesscss.org/) でCSSプリプロセッシング。 * [CSS-Tricks](https://css-tricks.com) ================================================ FILE: ja/elixir.md ================================================ --- contributors: - ["Joao Marques", "https://github.com/mrshankly"] - ["Dzianis Dashkevich", "https://github.com/dskecse"] - ["Ryan Plant", "https://github.com/ryanplant-au"] - ["Ev Bogdanov", "https://github.com/evbogdanov"] translators: - ["itepechi", "https://github.com/itepechi"] --- Elixirは、Erlang VM上で動作するモダンな関数型言語です。Erlangと完全な互換性があ りますが、より一般的な構文を持っているほか、機能も大きく拡張されています。 ```elixir # 1行コメントはシャープで始まります。 # 複数行コメントはありませんが、 # コメントを連続して書くことはできます。 # Elixirシェルを利用するには`iex`コマンドを使用します。 # モジュールをコンパイルするには`elixirc`コマンドを使用します。 # Elixirが正しくインストールされている場合、両コマンドはPATHに入っています。 ## --------------------------- ## -- 基本的な型 ## --------------------------- # これらは数字です 3 # 整数 0x1F # 整数 3.0 # 浮動小数点数 # アトムは自身の名前を値として持つ定数です。基本的に`:`で始まります。 :hello # アトム # タプルはメモリーの中に連続して格納されます。 {1,2,3} # タプル # `elem`関数を使うことで、タプルの要素にアクセスできます elem({1, 2, 3}, 0) #=> 1 # リストは連結リストとして実装されています。 [1,2,3] # リスト # リストのヘッドとテールは次の形でアクセスできます [head | tail] = [1,2,3] head #=> 1 tail #=> [2,3] # ElixirではErlangと同様、`=`は代入ではなくパターンマッチを表します。 # # 言い換えれば、右側の内容を左側のパターンを当てはめる指示を意味します。 # # 上記の例でヘッドとテールに正しくアクセスできるカラクリはここにあります。 # パターンマッチはそれぞれの内容がマッチしない場合、失敗します。 # この例では、それぞれのタプルのサイズが一致していません。 # {a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2} # 値にはバイナリーもあります <<1,2,3>> # バイナリー # 文字列と文字リスト "hello" # 文字列 'hello' # 文字リスト # 複数行文字列もあります """ 私は複数行 文字列です。 """ #=> "私は複数行\n文字列です。\n" # 文字列はすべてUTF-8でエンコードされています "héllò" #=> "héllò" # 文字列の実態はバイナリーで、文字リストはただのリストです。 <> #=> "abc" [?a, ?b, ?c] #=> 'abc' # Elixirでは、`?a`は`a`のASCIIコード整数を返します ?a #=> 97 # リストをつなげるには`++`を、バイナリーをつなげるには`<>`を使います [1,2,3] ++ [4,5] #=> [1,2,3,4,5] 'hello ' ++ 'world' #=> 'hello world' <<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>> "hello " <> "world" #=> "hello world" # レンジは`start..end`の形で表現されます(両端を含む) 1..10 #=> 1..10 lower..upper = 1..10 # レンジにもパターンマッチを適用できます [lower, upper] #=> [1, 10] # マップはそれぞれのキーと値を集めたものです genders = %{"david" => "male", "gillian" => "female"} genders["david"] #=> "male" # 次の例ではアトムをキーとして使用しています genders = %{david: "male", gillian: "female"} genders.gillian #=> "female" ## --------------------------- ## -- 演算子 ## --------------------------- # 単純な計算 1 + 1 #=> 2 10 - 5 #=> 5 5 * 2 #=> 10 10 / 2 #=> 5.0 # Elixirでは、`/`演算子は必ず浮動小数点数を返します。 # 整数として除算する場合は`div`を使用します div(10, 2) #=> 5 # 余りを計算するには`rem`を使用します rem(10, 3) #=> 1 # `or`、`and`や`not`など、ブーリアン演算子も存在します。 # これらの演算子は第一引数(左側)としてブーリアンを期待します。 true and true #=> true false or true #=> true # 1 and true #=> ** (BadBooleanError) expected a boolean on left-side of "and", got: 1 # さらに、Elixirにはあらゆる型に対応した`||`、`&&`、`!`演算子が存在します。 # `false`と`nil`を除いたあらゆる値は真値として扱われます。 1 || true #=> 1 false && 1 #=> false nil && 20 #=> nil !true #=> false # `==`、`!=`、`===`、`!==`、`<=`、`>=`、`<`、`>`を使うことで比較ができます 1 == 1 #=> true 1 != 1 #=> false 1 < 2 #=> true # `===`と`!==`は、整数と浮動小数点数を厳格に区別して比較します 1 == 1.0 #=> true 1 === 1.0 #=> false # Elixirの演算子は基本的に厳格ですが、異なる型を受け取る比較演算子は例外です 1 < :hello #=> true # これにより異なる型の集まりも作成できるようになります ["string", 123, :atom] # 異なる型同士にも順序は定義されています。ここでは詳しい順序を説明する代わりに # 「どのような順序であるかは重要ではない。何らかの順序が定義されているという # 事実自体が重要なのだ」というジョー・アームストロングの言葉を引用します。 ## --------------------------- ## -- 制御フロー ## --------------------------- # `if`式 if false do "ここには到達しません" else "ここにはします" end # パターンマッチは覚えていますか?Elixirの制御フローでたくさん登場します。 # `case`では値を複数のパターンに対して比較できます case {:one, :two} do {:four, :five} -> "これはマッチしません" {:one, x} -> "これはマッチし、`x`に`:two`をバインドします" _ -> "これはどんな値もマッチします" end # 内容に興味がない場合、`_`に値をバインドするのが一般的です。 # たとえば、リストの一番最初の要素のみを取り出したい時は [head | _] = [1,2,3] head #=> 1 # 可読性を高めたい場合はこのように書くこともできます [head | _tail] = [:a, :b, :c] head #=> :a # `cond`では複数の条件を同時に比較できます。 # `if`式を重ねるよりも、`cond`を優先して使いましょう。 cond do 1 + 1 == 3 -> "ここには到達しません" 2 * 5 == 12 -> "ここにもしません" 1 + 2 == 3 -> "ここにはします" end # 一般的には、常にマッチする条件を設定するため`true`を最後に置きます。 cond do 1 + 1 == 3 -> "ここには到達しません" 2 * 5 == 12 -> "ここにもしません" true -> "ここにはします(事実上のelse)" end # スローされた値をキャッチするには`try/catch`を使います。 # キャッチの有無を問わず実行される`after`句もサポートされています。 try do throw(:hello) catch message -> "#{message}を得ました。" after IO.puts("ここがafter句です。") end #=> ここがafter句です。 # ":helloを得ました。" ## --------------------------- ## -- モジュールと関数 ## --------------------------- # 無名関数(ドットに注目) square = fn(x) -> x * x end square.(5) #=> 25 # 句やガードは複数回指定できます。 # ガードは`when`キーワードで示され、パターンマッチの調整に利用されます f = fn x, y when x > 0 -> x + y x, y -> x * y end f.(1, 3) #=> 4 f.(-1, 3) #=> -3 # Elixirはさまざまなビルトイン関数を提供しています。 # 例として、これらの関数が現在のスコープで呼び出せます。 is_number(10) #=> true is_list("hello") #=> false elem({1,2,3}, 0) #=> 1 # 関数はモジュールとしてまとめることもできます。 # モジュール内では`def`を使用して関数を定義します。 defmodule Math do def sum(a, b) do a + b end def square(x) do x * x end end Math.sum(1, 2) #=> 3 Math.square(3) #=> 9 # 今回定義したMathモジュールをコンパイルするには`math.ex`として保存してから、 # ターミナルで`elixirc`を呼び出します。例:elixirc math.ex # モジュール内では`def`を使い関数を定義できるのと同様に、`defp`を使うことで # プライベート関数を定義できます。`def`で定義された関数は他のモジュールからも # 呼び出せますが、プライベート関数は同一のモジュール内からのみ呼び出せます。 defmodule PrivateMath do def sum(a, b) do do_sum(a, b) end defp do_sum(a, b) do a + b end end PrivateMath.sum(1, 2) #=> 3 # PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError) # 関数は複数回定義できるほか、ガードもサポートされています。 # 複数回定義された関数を呼び出すと、条件を満たす最初の関数が実行されます。 # 例:area({:circle, 3})は上のarea関数ではなく、2番目の関数を呼び出します defmodule Geometry do def area({:rectangle, w, h}) do w * h end def area({:circle, r}) when is_number(r) do 3.14 * r * r end end Geometry.area({:rectangle, 2, 3}) #=> 6 Geometry.area({:circle, 3}) #=> 28.25999999999999801048 # Geometry.area({:circle, "not_a_number"}) #=> ** (FunctionClauseError) no function clause matching in Geometry.area/1 # Elixirは原則的に不変であるため、再起が多く活用されます defmodule Recursion do def sum_list([head | tail], acc) do sum_list(tail, acc + head) end def sum_list([], acc) do acc end end Recursion.sum_list([1,2,3], 0) #=> 6 # Elixirのモジュールには属性を関連付けられます。ビルトインの属性に限らず、 # あなた独自のカスタム属性も指定できます。 defmodule MyMod do @moduledoc """ これはサンプルのモジュールのビルトイン属性です。 """ @my_data 100 # これはカスタム属性です。 IO.inspect(@my_data) #=> 100 end # パイプ演算子 |> を使うと、式の結果を次の関数の第一引数に渡すことができます。 Range.new(1,10) |> Enum.map(fn x -> x * x end) |> Enum.filter(fn x -> rem(x, 2) == 0 end) #=> [4, 16, 36, 64, 100] ## --------------------------- ## -- 構造体と例外 ## --------------------------- # 構造体はマップの拡張で、初期値、コンパイル時保証、ポリモーフィズムをElixir # に導入します。 defmodule Person do defstruct name: nil, age: 0, height: 0 end joe_info = %Person{ name: "Joe", age: 30, height: 180 } #=> %Person{age: 30, height: 180, name: "Joe"} # nameの値にアクセス joe_info.name #=> "Joe" # ageの値を更新 older_joe_info = %{ joe_info | age: 31 } #=> %Person{age: 31, height: 180, name: "Joe"} # 例外を扱うには`try`ブロックと`rescue`キーワードを組み合わせます try do raise "何かしらのエラー" rescue RuntimeError -> "ランタイムエラーをレスキューしました" _error -> "こちらは任意のエラーをレスキューします" end #=> "ランタイムエラーをレスキューしました" # あらゆる例外はメッセージを持ちます try do raise "何かしらのエラー" rescue x in [RuntimeError] -> x.message end #=> "何かしらのエラー" ## --------------------------- ## -- 並行性 ## --------------------------- # Elixirは並行性を実現するために、アクターモデルを採用しています。Elixirで # 並行処理を実現するために必要なものは、プロセスのスポーン、メッセージの送信、 # メッセージの受信の3つです。 # プロセスを開始するには、関数を引数として受け取る`spawn`関数を使用します。 f = fn -> 2 * 2 end #=> #Function spawn(f) #=> #PID<0.40.0> # `spawn`が返すpid(プロセスID)を使うことで、プロセスにメッセージを送る # ことができます。メッセージを送るには、`send`演算子を使います。しかし、 # メッセージは受け取らなければ意味がありません。`receive`を使って、これを # 実現しましょう # メッセージを受け取り、処理するためには`receive do`ブロックを使用します。 # ただし、`receive do`ブロックは基本的に単一のメッセージのみを処理します。 # 複数のメッセージを処理するには、`receive do`ブロックを持つ関数を再帰的に # 呼び出すことで、`receive do`ブロックを繰り返し評価する必要があります。 defmodule Geometry do def area_loop do receive do {:rectangle, w, h} -> IO.puts("Area = #{w * h}") area_loop() {:circle, r} -> IO.puts("Area = #{3.14 * r * r}") area_loop() end end end # モジュールをコンパイルし、`area_loop`をシェル内で実行します pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0> # 他の書き方もあります pid = spawn(Geometry, :area_loop, []) # recieve文のパターンに合致するメッセージを`pid`に送信します send pid, {:rectangle, 2, 3} #=> Area = 6 # {:rectangle,2,3} send pid, {:circle, 2} #=> Area = 12.56000000000000049738 # {:circle,2} # シェルそれ自身もプロセスで、`self`を使えばpidを取得できます self() #=> #PID<0.27.0> ## --------------------------- ## -- エージェント ## --------------------------- # エージェントは変化する値をトラッキングするプロセスです # `Agent.start_link`でエージェントを作成し、関数を入力します # この関数の戻り値がエージェントの初期状態になります {:ok, my_agent} = Agent.start_link(fn -> ["red", "green"] end) # `Agent.get`はエージェント名と現在の状態を受け取る`fn`を引数に取ります # この`fn`によって返される値が最終的な戻り値になります Agent.get(my_agent, fn colors -> colors end) #=> ["red", "green"] # 同じ方法でエージェントの状態を更新できます Agent.update(my_agent, fn colors -> ["blue" | colors] end) ``` ## リファレンス * [Getting started guide](https://elixir-lang.org/getting-started/introduction.html), [Elixir website](https://elixir-lang.org)より * [Elixir Documentation](https://elixir-lang.org/docs.html) * ["Programming Elixir"](https://pragprog.com/book/elixir/programming-elixir), Dave Thomas著 * [Elixir Cheat Sheet](https://media.pragprog.com/titles/elixir/ElixirCheat.pdf) * ["Learn You Some Erlang for Great Good!"](https://learnyousomeerlang.com/), Fred Hebert著 * ["Programming Erlang: Software for a Concurrent World"](https://pragprog.com/book/jaerlang2/programming-erlang), Joe Armstrong著 * [Introduction to Elixir](https://learn-elixir.com/) ================================================ FILE: ja/julia.md ================================================ --- contributors: - ["Leah Hanson", "http://leahhanson.us"] translators: - ["Yuichi Motoyama", "https://github.com/yomichi"] --- Julia は科学技術計算向けに作られた、同図像性を持った(homoiconic) プログラミング言語です。 マクロによる同図像性や第一級関数などの抽象化機能の恩恵を受けつつ、低階層をも扱えますが、 それでいてPython 並に学習しやすく、使いやすい言語となっています。 この文章は、Julia の2013年10月18日現在の開発バージョンを元にしています。 ```julia # ハッシュ(シャープ)記号から改行までは単一行コメントとなります。 #= 複数行コメントは、 '#=' と '=#' とで囲むことで行えます。 #= 入れ子構造にすることもできます。 =# =# #################################################### ## 1. 基本的な型と演算子 #################################################### # Julia ではすべて式となります。 # 基本となる数値型がいくつかあります。 3 # => 3 (Int64) 3.2 # => 3.2 (Float64) 2 + 1im # => 2 + 1im (Complex{Int64}) 2//3 # => 2//3 (Rational{Int64}) # 一般的な中置演算子が使用可能です。 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 5 / 2 # => 2.5 # 整数型同士の割り算の結果は、浮動小数点数型になります div(5, 2) # => 2 # 整数のまま割り算するには、 div を使います 5 \ 35 # => 7.0 2 ^ 2 # => 4 # べき乗です。排他的論理和ではありません 12 % 10 # => 2 # 丸括弧で演算の優先順位をコントロールできます (1 + 3) * 2 # => 8 # ビット演算 ~2 # => -3 # ビット反転 3 & 5 # => 1 # ビット積 2 | 4 # => 6 # ビット和 2 $ 4 # => 6 # ビット排他的論理和 2 >>> 1 # => 1 # 右論理シフト 2 >> 1 # => 1 # 右算術シフト 2 << 1 # => 4 # 左シフト # bits 関数を使うことで、数の二進表現を得られます。 bits(12345) # => "0000000000000000000000000000000000000000000000000011000000111001" bits(12345.0) # => "0100000011001000000111001000000000000000000000000000000000000000" # ブール値が用意されています true false # ブール代数 !true # => false !false # => true 1 == 1 # => true 2 == 1 # => false 1 != 1 # => false 2 != 1 # => true 1 < 10 # => true 1 > 10 # => false 2 <= 2 # => true 2 >= 2 # => true # 比較演算子をつなげることもできます 1 < 2 < 3 # => true 2 < 3 < 2 # => false # 文字列は " で作れます "This is a string." # 文字リテラルは ' で作れます 'a' # 文字列は文字の配列のように添字アクセスできます "This is a string"[1] # => 'T' # Julia では添字は 1 から始まります # ただし、UTF8 文字列の場合は添字アクセスではうまくいかないので、 # イテレーションを行ってください(map 関数や for ループなど) # $ を使うことで、文字列に変数や、任意の式を埋め込めます。 "2 + 2 = $(2 + 2)" # => "2 + 2 = 4" # 他にも、printf マクロを使うことでも変数を埋め込めます。 @printf "%d is less than %f" 4.5 5.3 # 5 is less than 5.300000 # 出力も簡単です println("I'm Julia. Nice to meet you!") #################################################### ## 2. 変数と配列、タプル、集合、辞書 #################################################### # 変数の宣言は不要で、いきなり変数に値を代入・束縛できます。 some_var = 5 # => 5 some_var # => 5 # 値に束縛されていない変数を使おうとするとエラーになります。 try some_other_var # => ERROR: some_other_var not defined catch e println(e) end # 変数名は数字や記号以外の文字から始めます。 # その後は、数字やアンダースコア(_), 感嘆符(!)も使えます。 SomeOtherVar123! = 6 # => 6 # Unicode 文字も使えます。 ☃ = 8 # => 8 # ギリシャ文字などを使うことで数学的な記法が簡単にかけます。 2 * π # => 6.283185307179586 # Julia における命名習慣について: # # * 変数名における単語の区切りにはアンダースコアを使っても良いですが、 # 使わないと読みにくくなる、というわけではない限り、 # 推奨はされません。 # # * 型名は大文字で始め、単語の区切りにはキャメルケースを使います。 # # * 関数やマクロの名前は小文字で書きます。 # 単語の分かち書きにはアンダースコアをつかわず、直接つなげます。 # # * 内部で引数を変更する関数は、名前の最後に ! をつけます。 # この手の関数は、しばしば「破壊的な関数」とか「in-place な関数」とか呼ばれます。 # 配列は、1 から始まる整数によって添字付けられる、値の列です。 a = Int64[] # => 0-element Int64 Array # 一次元配列(列ベクトル)は、角括弧 [] のなかにカンマ , 区切りで値を並べることで作ります。 b = [4, 5, 6] # => 3-element Int64 Array: [4, 5, 6] b[1] # => 4 b[end] # => 6 # 二次元配列は、空白区切りで作った行を、セミコロンで区切ることで作ります。 matrix = [1 2; 3 4] # => 2x2 Int64 Array: [1 2; 3 4] # 配列の末尾に値を追加するには push! を、 # 他の配列を結合するには append! を使います。 push!(a,1) # => [1] push!(a,2) # => [1,2] push!(a,4) # => [1,2,4] push!(a,3) # => [1,2,4,3] append!(a,b) # => [1,2,4,3,4,5,6] # 配列の末尾から値を削除するには pop! を使います。 pop!(b) # => 6 and b is now [4,5] # 一旦元に戻しておきましょう。 push!(b,6) # b is now [4,5,6] again. a[1] # => 1 # Julia では添字は0 ではなく1 から始まること、お忘れなく! # end は最後の添字を表す速記法です。 # 添字を書く場所ならどこにでも使えます。 a[end] # => 6 # 先頭に対する削除・追加は shift!, unshift! です。 shift!(a) # => 1 and a is now [2,4,3,4,5,6] unshift!(a,7) # => [7,2,4,3,4,5,6] # ! で終わる関数名は、その引数を変更するということを示します。 arr = [5,4,6] # => 3-element Int64 Array: [5,4,6] sort(arr) # => [4,5,6]; arr is still [5,4,6] sort!(arr) # => [4,5,6]; arr is now [4,5,6] # 配列の範囲外アクセスをすると BoundsError が発生します。 try a[0] # => ERROR: BoundsError() in getindex at array.jl:270 a[end+1] # => ERROR: BoundsError() in getindex at array.jl:270 catch e println(e) end # エラーが発生すると、どのファイルのどの行で発生したかが表示されます。 # 標準ライブラリで発生したものでもファイル名と行数が出ます。 # ソースからビルドした場合など、標準ライブラリのソースが手元にある場合は # base/ ディレクトリから探し出して見てください。 # 配列は範囲オブジェクトから作ることもできます。 a = [1:5] # => 5-element Int64 Array: [1,2,3,4,5] # 添字として範囲オブジェクトを渡すことで、 # 配列の部分列を得ることもできます。 a[1:3] # => [1, 2, 3] a[2:end] # => [2, 3, 4, 5] # 添字を用いて配列から値の削除をしたい場合は、splice! を使います。 arr = [3,4,5] splice!(arr,2) # => 4 ; arr is now [3,5] # 配列の結合は append! です。 b = [1,2,3] append!(a,b) # Now a is [1, 2, 3, 4, 5, 1, 2, 3] # 配列内に指定した値があるかどうかを調べるのには in を使います。 in(1, a) # => true # length で配列の長さを取得できます。 length(a) # => 8 # 変更不可能 (immutable) な値の組として、タプルが使えます。 tup = (1, 2, 3) # => (1,2,3) # an (Int64,Int64,Int64) tuple. tup[1] # => 1 try: tup[1] = 3 # => ERROR: no method setindex!((Int64,Int64,Int64),Int64,Int64) catch e println(e) end # 配列に関する関数の多くが、タプルでも使えます。 length(tup) # => 3 tup[1:2] # => (1,2) in(2, tup) # => true # タプルから値をばらして(unpack して) 複数の変数に代入できます。 a, b, c = (1, 2, 3) # => (1,2,3) # a is now 1, b is now 2 and c is now 3 # 丸括弧なしでもタプルになります。 d, e, f = 4, 5, 6 # => (4,5,6) # ひとつの値だけからなるタプルは、その値自体とは区別されます。 (1,) == 1 # => false (1) == 1 # => true # 値の交換もタプルを使えば簡単です。 e, d = d, e # => (5,4) # d is now 5 and e is now 4 # 辞書 (Dict) は、値から値への変換の集合です。 empty_dict = Dict() # => Dict{Any,Any}() # 辞書型リテラルは次のとおりです。 filled_dict = ["one"=> 1, "two"=> 2, "three"=> 3] # => Dict{ASCIIString,Int64} # [] を使ったアクセスができます。 filled_dict["one"] # => 1 # すべての鍵(添字)は keys で得られます。 keys(filled_dict) # => KeyIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2]) # 必ずしも辞書に追加した順番には並んでいないことに注意してください。 # 同様に、values はすべての値を返します。 values(filled_dict) # => ValueIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2]) # 鍵と同様に、必ずしも辞書に追加した順番には並んでいないことに注意してください。 # in や haskey を使うことで、要素や鍵が辞書の中にあるかを調べられます。 in(("one", 1), filled_dict) # => true in(("two", 3), filled_dict) # => false haskey(filled_dict, "one") # => true haskey(filled_dict, 1) # => false # 存在しない鍵を問い合わせると、エラーが発生します。 try filled_dict["four"] # => ERROR: key not found: four in getindex at dict.jl:489 catch e println(e) end # get 関数を使い、鍵がなかった場合のデフォルト値を与えておくことで、 # このエラーを回避できます。 get(filled_dict,"one",4) # => 1 get(filled_dict,"four",4) # => 4 # 集合 (Set) は一意な値の、順序付けられていない集まりです。 empty_set = Set() # => Set{Any}() # 集合の初期化 filled_set = Set(1,2,2,3,4) # => Set{Int64}(1,2,3,4) # 集合への追加 push!(filled_set,5) # => Set{Int64}(5,4,2,3,1) # in で、値が既に存在するかを調べられます。 in(2, filled_set) # => true in(10, filled_set) # => false # 積集合や和集合、差集合を得る関数も用意されています。 other_set = Set(3, 4, 5, 6) # => Set{Int64}(6,4,5,3) intersect(filled_set, other_set) # => Set{Int64}(3,4,5) union(filled_set, other_set) # => Set{Int64}(1,2,3,4,5,6) setdiff(Set(1,2,3,4),Set(2,3,5)) # => Set{Int64}(1,4) #################################################### ## 3. 制御構文 #################################################### # まずは変数を作ります。 some_var = 5 # if 構文です。Julia ではインデントに意味はありません。 if some_var > 10 println("some_var is totally bigger than 10.") elseif some_var < 10 # elseif 節は省略可能です。 println("some_var is smaller than 10.") else # else 節も省略可能です。 println("some_var is indeed 10.") end # => "some var is smaller than 10" と出力されます。 # for ループによって、反復可能なオブジェクトを走査できます。 # 反復可能なオブジェクトの型として、 # Range, Array, Set, Dict, String などがあります。 for animal=["dog", "cat", "mouse"] println("$animal is a mammal") # $ を使うことで文字列に変数の値を埋め込めます。 # You can use $ to interpolate variables or expression into strings end # prints: # dog is a mammal # cat is a mammal # mouse is a mammal # for = の代わりに for in を使うこともできます for animal in ["dog", "cat", "mouse"] println("$animal is a mammal") end # prints: # dog is a mammal # cat is a mammal # mouse is a mammal # 辞書ではタプルが返ってきます。 for a in ["dog"=>"mammal","cat"=>"mammal","mouse"=>"mammal"] println("$(a[1]) is a $(a[2])") end # prints: # dog is a mammal # cat is a mammal # mouse is a mammal # タプルのアンパック代入もできます。 for (k,v) in ["dog"=>"mammal","cat"=>"mammal","mouse"=>"mammal"] println("$k is a $v") end # prints: # dog is a mammal # cat is a mammal # mouse is a mammal # while ループは、条件式がtrue となる限り実行され続けます。 x = 0 while x < 4 println(x) x += 1 # Shorthand for x = x + 1 end # prints: # 0 # 1 # 2 # 3 # 例外は try/catch で捕捉できます。 try error("help") catch e println("caught it $e") end # => caught it ErrorException("help") #################################################### ## 4. 関数 #################################################### # function キーワードを次のように使うことで、新しい関数を定義できます。 #function name(arglist) # body... #end function add(x, y) println("x is $x and y is $y") # 最後に評価された式の値が、関数全体の返り値となります。 x + y end add(5, 6) # => 11 after printing out "x is 5 and y is 6" # 可変長引数関数も定義できます。 function varargs(args...) return args # return キーワードを使うことで、好きな位置で関数から抜けられます。 end # => varargs (generic function with 1 method) varargs(1,2,3) # => (1,2,3) # ... はsplat と呼ばれます # (訳注:「ピシャッという音(名詞)」「衝撃で平らにする(動詞)」) # 今回は関数定義で使いましたが、関数呼び出しに使うこともできます。 # その場合、配列やタプルの要素を開いて、複数の引数へと割り当てることとなります。 Set([1,2,3]) # => Set{Array{Int64,1}}([1,2,3]) # 「整数の配列」の集合 Set([1,2,3]...) # => Set{Int64}(1,2,3) # 整数の集合 x = (1,2,3) # => (1,2,3) Set(x) # => Set{(Int64,Int64,Int64)}((1,2,3)) # タプルの集合 Set(x...) # => Set{Int64}(2,3,1) # 引数に初期値を与えることで、オプション引数をもった関数を定義できます。 function defaults(a,b,x=5,y=6) return "$a $b and $x $y" end defaults('h','g') # => "h g and 5 6" defaults('h','g','j') # => "h g and j 6" defaults('h','g','j','k') # => "h g and j k" try defaults('h') # => ERROR: no method defaults(Char,) defaults() # => ERROR: no methods defaults() catch e println(e) end # キーワード引数を持った関数も作れます。 function keyword_args(;k1=4,name2="hello") # ; が必要なことに注意 return ["k1"=>k1,"name2"=>name2] end keyword_args(name2="ness") # => ["name2"=>"ness","k1"=>4] keyword_args(k1="mine") # => ["k1"=>"mine","name2"=>"hello"] keyword_args() # => ["name2"=>"hello","k1"=>4] # もちろん、これらを組み合わせることもできます。 function all_the_args(normal_arg, optional_positional_arg=2; keyword_arg="foo") println("normal arg: $normal_arg") println("optional arg: $optional_positional_arg") println("keyword arg: $keyword_arg") end all_the_args(1, 3, keyword_arg=4) # prints: # normal arg: 1 # optional arg: 3 # keyword arg: 4 # Julia では関数は第一級関数として、値として扱われます。 function create_adder(x) adder = function (y) return x + y end return adder end # ラムダ式によって無名関数をつくれます。 (x -> x > 2)(3) # => true # 先ほどの create_adder と同じもの function create_adder(x) y -> x + y end # 中の関数に名前をつけても構いません。 function create_adder(x) function adder(y) x + y end adder end add_10 = create_adder(10) add_10(3) # => 13 # いくつかの高階関数が定義されています。 map(add_10, [1,2,3]) # => [11, 12, 13] filter(x -> x > 5, [3, 4, 5, 6, 7]) # => [6, 7] # map の代わりとしてリスト内包表記も使えます。 [add_10(i) for i=[1, 2, 3]] # => [11, 12, 13] [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] #################################################### ## 5. 型 #################################################### # Julia ではすべての値にひとつの型がついています。 # 変数に、ではなくて値に、です。 # typeof 関数を使うことで、値が持つ型を取得できます。 typeof(5) # => Int64 # 型自身もまた、第一級の値であり、型を持っています。 typeof(Int64) # => DataType typeof(DataType) # => DataType # DataType は型を表現する型であり、DataType 自身もDataType 型の値です。 # 型はドキュメント化や最適化、関数ディスパッチのために使われます。 # 静的な型チェックは行われません。 # 自分で新しい型を定義することもできます。 # 他の言語で言う、構造体やレコードに近いものになっています。 # 型定義には type キーワードを使います。 # type Name # field::OptionalType # ... # end type Tiger taillength::Float64 coatcolor # 型注釈を省略した場合、自動的に :: Any として扱われます。 end # 型を定義すると、その型のプロパティすべてを、定義した順番に # 引数として持つデフォルトコンストラクタが自動的に作られます。 tigger = Tiger(3.5,"orange") # => Tiger(3.5,"orange") # 型名がそのままコンストラクタ名(関数名)となります。 sherekhan = typeof(tigger)(5.6,"fire") # => Tiger(5.6,"fire") # このような、構造体スタイルの型は、具体型(concrete type)と呼ばれます。 # 具体型はインスタンス化可能ですが、派生型(subtype)を持つことができません。 # 具体型の他には抽象型(abstract type)があります。 # abstract Name abstract Cat # 型の階層図の途中の一点を指し示す名前となります。 # 抽象型はインスタンス化できませんが、派生型を持つことができます。 # 例えば、 Number は以下の派生型を持つ抽象型です。 subtypes(Number) # => 6-element Array{Any,1}: # Complex{Float16} # Complex{Float32} # Complex{Float64} # Complex{T<:Real} # ImaginaryUnit # Real subtypes(Cat) # => 0-element Array{Any,1} # すべての型は、直接的にはただひとつの基本型(supertype) を持ちます。 # super 関数でこれを取得可能です。 typeof(5) # => Int64 super(Int64) # => Signed super(Signed) # => Real super(Real) # => Number super(Number) # => Any super(super(Signed)) # => Number super(Any) # => Any # Int64 を除き、これらはすべて抽象型です。 # <: は派生形を表す演算子です。 # これを使うことで派生型を定義できます。 type Lion <: Cat # Lion は 抽象型 Cat の派生型 mane_color roar::String end # 型名と同じ名前の関数を定義し、既に存在するコンストラクタを呼び出して、 # 必要とする型の値を返すことによって、 # デフォルトコンストラクタ以外のコンストラクタを作ることができます。 Lion(roar::String) = Lion("green",roar) # 型定義の外側で定義されたコンストラクタなので、外部コンストラクタと呼ばれます。 type Panther <: Cat # Panther も Cat の派生型 eye_color Panther() = new("green") # Panther は内部コンストラクタとしてこれのみを持ち、 # デフォルトコンストラクタを持たない end # 内部コンストラクタを使うことで、どのような値が作られるのかをコントロールすることができます。 # 出来る限り、外部コンストラクタを使うべきです。 #################################################### ## 6. 多重ディスパッチ #################################################### # Julia では、すべての名前付きの関数は総称的関数(generic function) です。 # これは、関数はいくつかの細かいメソッドの集合である、という意味です。 # 例えば先の Lion 型のコンストラクタ Lion は、Lion という関数の1つのメソッドです。 # コンストラクタ以外の例をみるために、新たに meow 関数を作りましょう。 # Lion, Panther, Tiger 型それぞれに対する meow 関数のメソッド定義 function meow(animal::Lion) animal.roar # 型のプロパティには . でアクセスできます。 end function meow(animal::Panther) "grrr" end function meow(animal::Tiger) "rawwwr" end # meow 関数の実行 meow(tigger) # => "rawwr" meow(Lion("brown","ROAAR")) # => "ROAAR" meow(Panther()) # => "grrr" # 型の階層関係を見てみましょう issubtype(Tiger,Cat) # => false issubtype(Lion,Cat) # => true issubtype(Panther,Cat) # => true # 抽象型 Cat の派生型を引数にとる関数 function pet_cat(cat::Cat) println("The cat says $(meow(cat))") end pet_cat(Lion("42")) # => prints "The cat says 42" try pet_cat(tigger) # => ERROR: no method pet_cat(Tiger,) catch e println(e) end # オブジェクト指向言語では、一般的にシングルディスパッチが用いられます。 # つまり、関数に複数あるメソッドのうちにどれが呼ばれるかは、 # その第一引数(もしくは、 . や -> の前にある値の型)によってのみ決定されます。 # 一方でJulia では、すべての引数の型が、このメソッド決定に寄与します。 # 多変数関数を定義して、この辺りを見て行きましょう。 function fight(t::Tiger,c::Cat) println("The $(t.coatcolor) tiger wins!") end # => fight (generic function with 1 method) fight(tigger,Panther()) # => prints The orange tiger wins! fight(tigger,Lion("ROAR")) # => prints The orange tiger wins! # 第二引数の Cat が実際は Lion だった時に、挙動が変わるようにします。 fight(t::Tiger,l::Lion) = println("The $(l.mane_color)-maned lion wins!") # => fight (generic function with 2 methods) fight(tigger,Panther()) # => prints The orange tiger wins! fight(tigger,Lion("ROAR")) # => prints The green-maned lion wins! # 別に Tiger だけが戦う必要もないですね。 fight(l::Lion,c::Cat) = println("The victorious cat says $(meow(c))") # => fight (generic function with 3 methods) fight(Lion("balooga!"),Panther()) # => prints The victorious cat says grrr try fight(Panther(),Lion("RAWR")) # => ERROR: no method fight(Panther,Lion) catch end # 第一引数にも Cat を許しましょう。 fight(c::Cat,l::Lion) = println("The cat beats the Lion") # => Warning: New definition # fight(Cat,Lion) at none:1 # is ambiguous with # fight(Lion,Cat) at none:2. # Make sure # fight(Lion,Lion) # is defined first. #fight (generic function with 4 methods) # 警告が出ましたが、これは次の対戦で何が起きるのかが不明瞭だからです。 fight(Lion("RAR"),Lion("brown","rarrr")) # => prints The victorious cat says rarrr # Julia のバージョンによっては、結果が違うかもしれません。 fight(l::Lion,l2::Lion) = println("The lions come to a tie") fight(Lion("RAR"),Lion("brown","rarrr")) # => prints The lions come to a tie # Julia が生成する LLVM 内部表現や、アセンブリを調べることもできます。 square_area(l) = l * l # square_area (generic function with 1 method) square_area(5) #25 # square_area に整数を渡すと何が起きる? code_native(square_area, (Int32,)) # .section __TEXT,__text,regular,pure_instructions # Filename: none # Source line: 1 # Prologue # push RBP # mov RBP, RSP # Source line: 1 # movsxd RAX, EDI # l を取得 # imul RAX, RAX # l*l を計算して RAX に入れる # pop RBP # Base Pointer を元に戻す # ret # 終了。RAX の中身が結果 code_native(square_area, (Float32,)) # .section __TEXT,__text,regular,pure_instructions # Filename: none # Source line: 1 # push RBP # mov RBP, RSP # Source line: 1 # vmulss XMM0, XMM0, XMM0 # 単精度浮動小数点数演算 (AVX) # pop RBP # ret code_native(square_area, (Float64,)) # .section __TEXT,__text,regular,pure_instructions # Filename: none # Source line: 1 # push RBP # mov RBP, RSP # Source line: 1 # vmulsd XMM0, XMM0, XMM0 # 倍精度浮動小数点数演算 (AVX) # pop RBP # ret # # Julia では、浮動小数点数と整数との演算では # 自動的に浮動小数点数用の命令が生成されることに注意してください。 # 円の面積を計算してみましょう。 circle_area(r) = pi * r * r # circle_area (generic function with 1 method) circle_area(5) # 78.53981633974483 code_native(circle_area, (Int32,)) # .section __TEXT,__text,regular,pure_instructions # Filename: none # Source line: 1 # push RBP # mov RBP, RSP # Source line: 1 # vcvtsi2sd XMM0, XMM0, EDI # Load integer (r) from memory # movabs RAX, 4593140240 # Load pi # vmulsd XMM1, XMM0, QWORD PTR [RAX] # pi * r # vmulsd XMM0, XMM0, XMM1 # (pi * r) * r # pop RBP # ret # code_native(circle_area, (Float64,)) # .section __TEXT,__text,regular,pure_instructions # Filename: none # Source line: 1 # push RBP # mov RBP, RSP # movabs RAX, 4593140496 # Source line: 1 # vmulsd XMM1, XMM0, QWORD PTR [RAX] # vmulsd XMM0, XMM1, XMM0 # pop RBP # ret # ``` ## より勉強するために [公式ドキュメント](http://docs.julialang.org/en/latest/manual/) (英語)にはより詳細な解説が記されています。 Julia に関して助けが必要ならば、[メーリングリスト](https://groups.google.com/forum/#!forum/julia-users) が役に立ちます。 みんな非常に親密に教えてくれます。 ================================================ FILE: ja/markdown.md ================================================ --- contributors: - ["Dan Turkel", "http://danturkel.com/"] - ["Jacob Ward", "http://github.com/JacobCWard/"] - ["Tomáš Hartman", "https://github.com/tomas-hartman"] translators: - ["Kenryu Shibata", "https://github.com/kenryuS"] --- Markdownは2004年にジョン グラバー(John Gruber)によって作られました。 HTMLへの変換が容易な書きやすくかつ読みやすいマークアップ言語として開発されました。 今ではHTMLの他に様々なファイル形式へ変換できます。 Markdownは構文解析の実装によって様々な派生があるマークアップ言語として知られています。 このチュートリアルでは様々な実装での共通の構文であるか特定の実装でしか使えないものなのかを極力明記しています。 ## HTML要素 MarkdownはHTMLの上位互換言語として開発されたのでほとんどのHTMLはMarkdownでも使えます。 ```md ``` ## 見出し HTMLの`

`から`

`に相当する見出しが作れます。 ハッシュ(#)の数によって見出しのサイズを変えることができます。 ```md # これが

## これが

### これが

#### これが

##### これが

###### これが
``` h1とh2を表す別の記法もあります。 ```md これが h1 ======== これが h2 -------- ``` ## 文字の簡単なスタイリング Markdownを使えば簡単に太字にしたり、イタリック体にできます。 ```md *文字をイタリック体にする。* _これもイタリック体になる。_ **文字を太字にする。** __これも太字になる。__ ***文字を同時にイタリック体と太字にする。*** **_これも、_** *__これも同じ。__* ``` GitHub版Markdownでは取り消し線を引くことができます。 ```md ~~取り消し線と共にこれが表示されます。~~ ``` ## 段落 段落は1行以上の連続した行に記述された文章で、1行以上の改行で区切られます。 ```md これが段落です。これだけでもスゴくない? ここは第2段落です。 ここも第2段落だぜ! そしてここは第3段落だ! ``` 段落の途中で`
`タグを入れる時は2つ以上の半角スペースを段落末に入れることで 新たな段落を始めれます。 ```md これはスペース2つで終わっています。(ハイライトして見てください。)
が上にあります! ``` ブロッククォート(引用句)は文の前に ">" を書けば簡単にできます。 ```md > これが引用句です。手動 > で改行して `>` を各行に書くか、とてつもなく長い文を書いて、表示の際に自動で改行させることもできます。 > `>` で始めていれば、改行してもしなくても同じです。 > 更に、複数段のインデントが >> ブロッククォート内で使えます。 > よくできてるでしょう? ``` ## リスト 順序なしリストはアスタリスク、プラス記号、ハイフンで表します。 ```md * 項目 * 項目 * もう1つの項目 または、 + 項目 + 項目 + また1つの項目 または、 - 項目 - 項目 - 最後の項目 ``` 順序付きリストは数字とピリオドで表します。 ```md 1. 項目1 2. 項目2 3. 項目3 ``` 番号は1から順にしなくてもMarkdownは正しく番号振ってくれますが、 読みにくくなるので推奨しません。 ```md 1. 項目1 1. 項目2 1. 項目3 ``` (前の例と同じものが描画される。) サブリストを使用することができます。 ```md 1. 項目1 2. 項目2 3. 項目3 * サブ項目 * サブ項目 4. 項目4 ``` タスクリストも作成できます。これはHTMLのチェックボックスを生成します。 ```md 'x' がない物は未チェックのチェックボックスを生成します。 - [ ] 1つ目のタスク - [ ] 2つ目のタスク 以下はチェックが付いたHTMLチェックボックスを生成します。 - [x] This task has been completed ``` ## コード引用 HTMLの``を使用したコード引用は半角スペースで4つ空けるか、 タブを1文字を入れます。 ```md これはソースコード これもソースコード ``` タブをもう1つ(または半角スペースを追加で4つ)入れればコード引用内で インデントを出力できます。 ```md my_array.each do |item| puts item end ``` バックチック文字 `` ` `` を使用すれば文中でインラインコード引用を出力できます。 ```md 太郎は`go_to()`関数は何をするのか知らなかったのだ! ``` GitHub版Markdownでは特別な書き方があります。 ````md ```ruby def hogefuga puts "Hello world!" end ``` ```` 上記はインデントが必要無く、しかも最初の```の後に シンタックスハイライトで使用する言語を指定することが出来ます。 ## 横罫 横罫(`
`)は間のスペースの有無によらず、3つ以上のアスタリスクまたはハイフンを 挿入することで簡単に引くことができます。 ```md *** --- - - - **************** ``` ## リンク Markdownのよい特徴として、簡単にリンクを入れることができる点があります。 表示するテキストを角括弧 [] 内に記載し、URLを丸括弧 () 内に記載します。 ```md [ここをクリック!](http://test.com/) ``` 丸括弧内にクォーテーションにリンクタイトルを追加できます。 ```md [ここをクリック!](http://test.com/ "Test.com へのリンク。") ``` 相対パスもリンクできます。 ```md [musicへ](/music/) ``` Markdown は脚注スタイルのリンクを使えます。 ```md [このリンク][link1] から詳細を確認できます。 [更にこのリンク][hogefuga] も見てください! [link1]: http://test.com/ "Cool!" [hogefuga]: http://hogefuga.biz/ "Alright!" ``` タイトルはシングルクォートや括弧内に書いてもよいし、全く書かなくてもよい。 脚注はドキュメントのどこに書いてもよく、参照IDもユニークなものなら何でもよい。 リンクテキストをIDとして使用する暗黙命名が使えます。 ```md [これ][] はリンク. [これ]: http://thisisalink.com/ ``` が、これはあまり使用されていません。 ### 目次 いくつかのMarkdownの実装では、リストとリンクと見出しを使って目次を作ることができます。 この例では、英文字の見出しを小文字にしたものにハッシュ(`#`)を接頭し、これをリンクID として使っています。単語間にスペースがある場合はスペースの代わりにハイフン(`-`)を使います。 (この時、いくつかの特殊文字は無視されます。) ```md - [Heading](#heading) - [Another heading](#another-heading) - [Chapter](#chapter) - [Subchapter

](#subchapter-h3-) ``` それでも、この機能はすべてのMarkdown実装で同じ様に動作する保証がありません。 ## 画像 画像はリンクと似た構文を持ち、違いは先頭に感嘆符(`!`)があるところです。 ```md ![ここで画像のalt属性を指定できます。](http://imgur.com/myimage.jpg "任意でタイトルを追加できます。") ``` 脚注スタイルの書き方もリンクと同じ様に書けます。 ```md ![画像のalt属性][myimage] [myimage]: 画像/への/相対/パス.jpg "ここにタイトルを書きます。" ``` ## その他の機能 ### 自動リンク ```md は [http://testwebsite.com/](http://testwebsite.com/) と同じ。 ``` ### メールアドレスの自動リンク ```md ``` ### エスケープ文字 ```md 私は *この文節をアスタリスクで囲みたいが、* 斜字体にしたくない、なので こうします: \*この文節はアスタリスクで囲まれています。\* ``` ### キーボードのキー GitHub版Markdwonでは、`` タグを使用してキーボードのキーを表すことができます。 ```md パソコンがクラッシュした? Ctrl+Alt+Del を打ってごらん。 ``` ### 表 表はGitHub版Markdownでしか実装されておらず、少し使いずらいです。 ```md | 行1 | 行2 | 行3 | | :----- | :------: | -----: | | 左寄せ | 中央寄せ | 右寄せ | | ほげ | ふが | ほげ | ``` 下記も同じ様に表示されますが… ```md 行1 | 行2 | 行3 :-- | :-: | --: なんなんだ、この | ゴミコードは | 止めろ ``` ## Markdownlint Markdownでの執筆を簡略化したり、書式を統一するために`Markdownlint`が 作られました。スタンドアローンのツールは[このレポジトリ](https://github.com/markdownlint/markdownlint)で配布されていますし、幾つかのIDEのプラグインを 使用できます。これを用れば、Markdownの検証や可読性を確保できます。 --- ## 関連情報 より詳細な情報はJohn Gruberの公式ブログに書かれた[構文解説](http://daringfireball.net/projects/markdown/syntax)とAdam Pritchardの偉大なる[チートシート](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)を参照してください。 主要な実装については下記を参照してください: - [GitHub版Markdown](https://docs.github.com/en/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) - [GitLab版Markdown](https://docs.gitlab.com/ee/user/markdown.html) ================================================ FILE: ja/nim.md ================================================ --- contributors: - ["Jason J. Ayala P.", "http://JasonAyala.com"] - ["Dennis Felsing", "https://dennis.felsing.org"] translators: - ["Seiichi Ariga", "https://github.com/s-ariga"] --- Nim (元 Nimrod)は、静的型付けの命令型言語です。ランタイムの効率を損なうこと なく、プログラマーに恩恵を与えてくれます。 Nimは、効率的で、表現力があり、エレガントです。 ```nim # 単一行コメントは # で開始 #[ 複数行コメントです。 Nimでは、複数行コメントはネスト可能で、#[で始まり、 ... そして終了は ]# ]# discard """ これも複数行コメントとして機能します。 あるいは、解析不能のコードです。 """ var # 変数宣言 (そして割当て) letter: char = 'n' # 型注釈ありとなし lang = "N" & "im" nLength: int = len(lang) boat: float truth: bool = false let # letで変数を*1回(イミュータブル)*束縛します legs = 400 # legsはイミュータブル arms = 2_000 # _ は無視され、長い数値を読みやすくします aboutPi = 3.15 const # 定数はコンパイル時に評価されます。 debug = true # これにより実行速度を高めます。 compileBadCode = false when compileBadCode: # `when`はコンパイル時の`if`です。 legs = legs + 1 # この部分はコンパイルされません。ed. const input = readline(stdin) # 定数値はコンパイル時に決まっていなければ # なりません。 discard 1 > 2 # Note: コンパイラーはある式の結果が使われていないと警告を # 表示します。`discard`により、これを回避できます。 # # データ構造 # # タプル var child: tuple[name: string, age: int] # タプルにはフィールド名 today: tuple[sun: string, temp: float] # *そして*順序の*両方*があります child = (name: "Rudiger", age: 2) # ()リテラルで両方同時に割当て today.sun = "Overcast" # あるいは、個別のフィールドに割当て today.temp = 70.1 # シーケンス var drinks: seq[string] drinks = @["Water", "Juice", "Chocolate"] # シーケンスリテラルは@[V1,..,Vn] drinks.add("Milk") if "Milk" in drinks: echo "We have Milk and ", drinks.len - 1, " other drinks" let myDrink = drinks[2] # # 型の定義 # # あなた自身の型を定義することで、コンパイラーにより多くの仕事をさせられます。 # それにより静的型付けがパワフルで便利なものになります。 type Name = string # 型エイリアスは、既存の型と置き換え可能でありながら、 Age = int # より記述的な型を提供します。 Person = tuple[name: Name, age: Age] # データ構造も定義できます。 AnotherSyntax = tuple fieldOne: string secondField: int var john: Person = (name: "John B.", age: 17) newage: int = 18 # ここはint型よりもAge型を使ったほうが良いでしょう。 john.age = newage # intとAgeは同じ型なので、これで動作します。 type Cash = distinct int # `distinct`を使うと、新しい型と Desc = distinct string # 元の型の互換性がなくなります。 var money: Cash = 100.Cash # `.Cash`がint型をわれわれ独自の型に #変換しています。 description: Desc = "Interesting".Desc when compileBadCode: john.age = money # エラー! ageはint型でmoneyはCash型です。 john.name = description # コンパイル時のエラーになります。 # # さらに型とデータ構造 # # 列挙は型にいくつかの値の中から1つの値をとることを許します。 type Color = enum cRed, cBlue, cGreen Direction = enum # 別の書き方 dNorth dWest dEast dSouth var orient = dNorth # `orient`はDirection型で値は`dNorth` pixel = cGreen # `pixel`はColor型で値は`cGreen` discard dNorth > dEast # 列挙には通常、順序があります。 # サブレンジは有効な値の範囲を限定します。 type DieFaces = range[1..20] # 1から20のintだけが有効な値です。 var my_roll: DieFaces = 13 when compileBadCode: my_roll = 23 # エラー! # 配列 type RollCounter = array[DieFaces, int] # 配列の長さは固定で、順序のある型の DirNames = array[Direction, string] # どれかをインデックスとします。 Truths = array[42..44, bool] var counter: RollCounter directions: DirNames possible: Truths possible = [false, false, false] # [V1,..,Vn]で配列を作れます。 possible[42] = true directions[dNorth] = "Ahh. The Great White North!" directions[dWest] = "No, don't go there." my_roll = 13 counter[my_roll] += 1 counter[my_roll] += 1 var anotherArray = ["Default index", "starts at", "0"] # 他にも表、集合、リスト、キュー、Crit-bit treeなどのデータ構造があります。 # http://nim-lang.org/docs/lib.html#collections-and-algorithms # # IOと制御 # # `case`, `readLine()` echo "Read any good books lately?" case readLine(stdin) of "no", "No": echo "Go to your local library." of "yes", "Yes": echo "Carry on, then." else: echo "That's great; I assume." # `while`, `if`, `continue`, `break` import strutils as str # http://nim-lang.org/docs/strutils.html echo "I'm thinking of a number between 41 and 43. Guess which!" let number: int = 42 var raw_guess: string guess: int while guess != number: raw_guess = readLine(stdin) if raw_guess == "": continue # この繰り返しを飛ばす。 guess = str.parseInt(raw_guess) if guess == 1001: echo("AAAAAAGGG!") break elif guess > number: echo("Nope. Too high.") elif guess < number: echo(guess, " is too low") else: echo("Yeeeeeehaw!") # # 繰返し # for i, elem in ["Yes", "No", "Maybe so"]: # または単に`for elem in` echo(elem, " is at index: ", i) for k, v in items(@[(person: "You", power: 100), (person: "Me", power: 9000)]): echo v let myString = """ an `string` to play with """ # 複数行の生文字列 for line in splitLines(myString): echo(line) for i, c in myString: # インデックスと文字。 # あるいは`for j in`で文字だけ。 if i mod 2 == 0: continue # `if`構文の簡易版 elif c == 'X': break else: echo(c) # # プロシージャ # type Answer = enum aYes, aNo proc ask(question: string): Answer = echo(question, " (y/n)") while true: case readLine(stdin) of "y", "Y", "yes", "Yes": return Answer.aYes # 列挙に限定することができます。 of "n", "N", "no", "No": return Answer.aNo else: echo("Please be clear: yes or no") proc addSugar(amount: int = 2) = # amountのデフォルトは2、戻り値はなし assert(amount > 0 and amount < 9000, "Crazy Sugar") for a in 1..amount: echo(a, " sugar...") case ask("Would you like sugar in your tea?") of aYes: addSugar(3) of aNo: echo "Oh do take a little!" addSugar() # ここで可能な値は`yes`か`no`だけなので、`else`は必要ない # # FFI # # NimはCへとコンパイルされるので、容易にFFIができる: proc strcmp(a, b: cstring): cint {.importc: "strcmp", nodecl.} let cmp = strcmp("C?", "Easy!") ``` これらの他に、Nimはほかの言語と比較してメタプログラミング、 実行時パフォーマンス、コンパイル時の機能で特長があります。 ## 参考 * [Home Page](http://nim-lang.org) * [Download](http://nim-lang.org/download.html) * [Community](http://nim-lang.org/community.html) * [FAQ](http://nim-lang.org/question.html) * [Documentation](http://nim-lang.org/documentation.html) * [Manual](http://nim-lang.org/docs/manual.html) * [Standard Library](http://nim-lang.org/docs/lib.html) * [Rosetta Code](http://rosettacode.org/wiki/Category:Nim) ================================================ FILE: ja/php.md ================================================ --- contributors: - ["Malcolm Fell", "http://emarref.net/"] - ["Trismegiste", "https://github.com/Trismegiste"] translators: - ["Kazushige Tominaga", "https://github.com/kazu9su"] --- このドキュメントでは、 PHP 5+ について説明します。 ```php Hello World Again! 12 $int2 = -12; // => -12 $int3 = 012; // => 10 (先頭の0は8進法を示す) $int4 = 0x0F; // => 15 (先頭の0xは16進法を示す) // floats(浮動小数) (別名double) $float = 1.234; $float = 1.2e3; $float = 7E-10; // 変数の削除 unset($int1); // 計算式 $sum = 1 + 1; // 2 $difference = 2 - 1; // 1 $product = 2 * 2; // 4 $quotient = 2 / 1; // 2 // 式の省略 $number = 0; $number += 1; // $numberに1加算Increment $number by 1 echo $number++; // 1 がプリントされる(式の評価の後に加算される) echo ++$number; // 3 がプリントされる(式の評価の前に加算される) $number /= $float; // 割り算した結果の商を$numberに割り当てる // 文字列はシングルクォートで囲むのが望ましいです $sgl_quotes = '$String'; // => '$String' // 文字列中に、他の変数を埋め込みたい場合以外は、ダブルクォートを使用するのはやめましょう $dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.' // Special characters are only escaped in double quotes // 特殊文字はダブルクォートによってのみ、エスケープされます $escaped = "This contains a \t tab character."; $unescaped = 'This just contains a slash and a t: \t'; // 必要があれば、変数を波括弧で囲みます $money = "I have $${number} in the bank."; // PHP 5.3から、nowdocs形式が変数の挿入をしない複数行の文字列の定義に使用できます $nowdoc = <<<'END' Multi line string END; // ヒアドキュメント形式なら、文字列中に変数の挿入を行えます。 $heredoc = << 1, 'Two' => 2, 'Three' => 3); // PHP 5.4 から、新しいシンタックスが導入されました $associative = ['One' => 1, 'Two' => 2, 'Three' => 3]; echo $associative['One']; // 1とプリントされます // キーを指定しないシンプルな配列にも、自動的に数値キーが振られます $array = ['One', 'Two', 'Three']; echo $array[0]; // => "One" // 配列の最後に要素を追加する $array[] = 'Four'; // または、次のようにも書けます array_push($array, 'Five'); // 配列から要素を削除 unset($array[3]); /******************************** * 出力 */ echo('Hello World!'); // 標準出力にHello World! とプリントします // 標準出力はブラウザーで実行していればWebページに出力されます // Stdout is the web page if running in a browser. print('Hello World!'); // echoの結果と同じです // echo は言語自体の構成要素であり、括弧なしで呼び出せます // echo is actually a language construct, so you can drop the parentheses. echo 'Hello World!'; print 'Hello World!'; // printも同様です $paragraph = 'paragraph'; echo 100; // スカラー数値を直接出力します echo $paragraph; // 変数も使用できます // PHPタグの短縮型が設定されているか、使用しているPHPのバージョンが // 5.4.0 以上であれば、短縮echoシンタックスを使用できます ?>

2 echo $z; // => 2 $y = 0; echo $x; // => 2 echo $z; // => 0 // 変数の型と値を標準出力へダンプします var_dump($z); // int(0) と出力されます // 人間が読めるフォーマットで変数を標準出力にプリントします print_r($array); // prints: Array ( [0] => One [1] => Two [2] => Three ) /******************************** * ロジック */ $a = 0; $b = '0'; $c = '1'; $d = '1'; // assertは引数がfalseの場合、Exceptionを投げます //これらの比較は型が違ったとしても、常に真です。 assert($a == $b); // equality assert($c != $a); // inequality assert($c <> $a); // alternative inequality assert($a < $c); assert($c > $b); assert($a <= $b); assert($c >= $d); // 次の比較は値が等しく、かつ同じ型である場合のみ真です assert($c === $d); assert($a !== $d); assert(1 === '1'); assert(1 !== '1'); // spaceship演算子はPHP7から使用可能です $a = 100; $b = 1000; echo $a <=> $a; // 等しいので0になります echo $a <=> $b; // $a < $b なので -1 です echo $b <=> $a; // $b > $a なので 1 です // 変数は使用するコンテキストによって、変換されます $integer = 1; echo $integer + $integer; // => 2 $string = '1'; echo $string + $string; // => 2 (文字列は強制的に数値として処理されます) $string = 'one'; echo $string + $string; // => 0 // '+'演算子は文字列'one'を数値にキャストできないので、0と出力されます // 型のキャスティングによって、変数を指定したもう一つの型として扱うことができます // Type casting can be used to treat a variable as another type $boolean = (boolean) 1; // => true $zero = 0; $boolean = (boolean) $zero; // => false // 型をキャストするため専用の関数も存在します $integer = 5; $string = strval($integer); $var = null; // Null値 /******************************** * 制御構造 */ if (true) { print 'I get printed'; } if (false) { print 'I don\'t'; } else { print 'I get printed'; } if (false) { print 'Does not get printed'; } elseif(true) { print 'Does'; } // 三項演算子 print (false ? 'Does not get printed' : 'Does'); // PHP 5.3から、三項演算子の短縮形が使用できます // $x ? $x : 'Does'と同義です $x = false; print($x ?: 'Does'); // null合体演算子はPHP 7から使用できます $a = null; $b = 'Does print'; echo $a ?? 'a is not set'; // prints 'a is not set' echo $b ?? 'b is not set'; // prints 'Does print' $x = 0; if ($x === '0') { print 'Does not print'; } elseif($x == '1') { print 'Does not print'; } else { print 'Does print'; } // :を用いる別の構文はテンプレートで有用です ?> この部分はifが真のとき表示されます それ以外の場合は、この部分が表示されます 2, 'car' => 4]; //Foreachループによって、 配列を反復処理できます foreach ($wheels as $wheel_count) { echo $wheel_count; } // Prints "24" echo "\n"; // 値と同じ様に、keyも反復処理できます foreach ($wheels as $vehicle => $wheel_count) { echo "A $vehicle has $wheel_count wheels"; } echo "\n"; $i = 0; while ($i < 5) { if ($i === 3) { break; // Exit out of the while loop } echo $i++; } // Prints "012" for ($i = 0; $i < 5; $i++) { if ($i === 3) { continue; // Skip this iteration of the loop } echo $i; } // Prints "0124" /******************************** * 関数 */ // 関数を"function"で定義します function my_function () { return 'Hello'; } echo my_function(); // => "Hello" // 有効な関数名は、文字またはアンダースコアで始めます。それ以降は // どれだけ長い文字、数値、アンダースコアを続けても構いません function add ($x, $y = 1) { // $yはオプショナルな値であり、デフォルトで 1 です $result = $x + $y; return $result; } echo add(4); // => 5 echo add(4, 2); // => 6 // $result には、関数の外からアクセス出来ません // print $result; // エラーになります // PHP 5.3 から、無名関数が使えます $inc = function ($x) { return $x + 1; }; echo $inc(2); // => 3 function foo ($x, $y, $z) { echo "$x - $y - $z"; } // 関数は、関数を返すことができます function bar ($x, $y) { // 関数外の変数を利用したいときは、'use'を使います return function ($z) use ($x, $y) { foo($x, $y, $z); }; } $bar = bar('A', 'B'); $bar('C'); // Prints "A - B - C" // 文字列を使って、定義済みの関数を呼び出すことができます $function_name = 'add'; echo $function_name(1, 2); // => 3 // プログラミング中に、動的に動かす関数を決める場合に便利です。 // もしくは、call_user_func(callable $callback [, $parameter [, ... ]]) を使っても同じことができます // 特に指定しなくても、渡された引数を受け取ることもできます function parameters() { $numargs = func_num_args(); if ($numargs > 0) { echo func_get_arg(0) . ' | '; } $args_array = func_get_args(); foreach ($args_array as $key => $arg) { echo $key . ' - ' . $arg . ' | '; } } parameters('Hello', 'World'); // Hello | 0 - Hello | 1 - World | /******************************** * ファイルの読み込み */ instanceProp = $instanceProp; } // メソッドはクラス内で関数として定義されます public function myMethod() { print 'MyClass'; } // finalキーワードは関数の上書きを禁止します final function youCannotOverrideMe() { } /* * クラスプロパティまたはメソッドをstaticとして作成すれば、 * クラスをインスタンス化(newすること)しなくてもアクセスできます。 * プロパティをstaticとして定義すると、 * インスタンス化されたクラスオブジェクトを通してのアクセスはできなくなります。 */ public static function myStaticMethod() { print 'I am static'; } } // クラス定数は、いつでも静的にアクセスできます。 echo MyClass::MY_CONST; // Outputs 'value'; echo MyClass::$staticVar; // Outputs 'static'; MyClass::myStaticMethod(); // Outputs 'I am static'; // クラスをインスタンス化するには、newを使います。 $my_class = new MyClass('An instance property'); // 括弧はもし引数を渡す必要がなければ省略可能です。 // ->を使ってクラスのメンバにアクセスします。 echo $my_class->property; // => "public" echo $my_class->instanceProp; // => "An instance property" $my_class->myMethod(); // => "MyClass" // extendsを使用してクラスを継承します。 class MyOtherClass extends MyClass { function printProtectedProperty() { echo $this->prot; } // メソッドを上書きします。 function myMethod() { parent::myMethod(); print ' > MyOtherClass'; } } $my_other_class = new MyOtherClass('Instance prop'); $my_other_class->printProtectedProperty(); // => Prints "protected" $my_other_class->myMethod(); // Prints "MyClass > MyOtherClass" final class YouCannotExtendMe { } // 「マジックメソッド」を使ってゲッターとセッターを生成できます。 class MyMapClass { private $property; public function __get($key) { return $this->$key; } public function __set($key, $value) { $this->$key = $value; } } $x = new MyMapClass(); echo $x->property; // __get() メソッドを使用します $x->property = 'Something'; // __set() メソッドを使用します // クラスは抽象クラスにもできます(abstractキーワードを使用します)し、 // インターフェースを実装することもできます(implementsキーワードを使用します)。 // インターフェースはinterfaceキーワードで定義します。 interface InterfaceOne { public function doSomething(); } interface InterfaceTwo { public function doSomethingElse(); } // インターフェースは継承することができます interface InterfaceThree extends InterfaceTwo { public function doAnotherContract(); } abstract class MyAbstractClass implements InterfaceOne { public $x = 'doSomething'; } class MyConcreteClass extends MyAbstractClass implements InterfaceTwo { public function doSomething() { echo $x; } public function doSomethingElse() { echo 'doSomethingElse'; } } // クラスは1つ以上のインターフェースを実装できます。 class SomeOtherClass implements InterfaceOne, InterfaceTwo { public function doSomething() { echo 'doSomething'; } public function doSomethingElse() { echo 'doSomethingElse'; } } /******************************** * トレイト */ // トレイトはPHP 5.4.0 以上で使用可能で、traitキーワードで定義します。 trait MyTrait { public function myTraitMethod() { print 'I have MyTrait'; } } class MyTraitfulClass { use MyTrait; } $cls = new MyTraitfulClass(); $cls->myTraitMethod(); // Prints "I have MyTrait" /******************************** * 名前空間 */ // このセクションは名前空間の定義はファイルの先頭で宣言される必要があるため、 // 独立しています。 // そのケースには当てはまらないふりをして続けましょう。 3 # 四則演算はあなたの期待通りに動きます。 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 # 整数除算の結果は、正負に関わらず小数の切り捨てが行われます。 5 // 3 # => 1 -5 // 3 # => -2 5.0 // 3.0 # => 1.0 # 浮動小数点でも同様に動作します。 -5.0 // 3.0 # => -2.0 # 除算の結果は常に浮動小数点になります。 10.0 / 3 # => 3.3333333333333335 # 剰余の計算 7 % 3 # => 1 # 冪乗 (x**y, x の y 乗) 2**3 # => 8 # 括弧により、計算の順番を優先させられます。 (1 + 3) * 2 # => 8 # 真偽値はプリミティブ型です(大文字から始まっていることに注意!) True False # not で真偽を反転させられます。 not True # => False not False # => True # ブール演算 # 注意: "and" と "or" は小文字です。 True and False # => False False or True # => True # TrueとFalseは実際には1と0になるキーワードです。 True + True # => 2 True * 8 # => 8 False - 5 # => -5 # 比較演算子はTrueとFalseを数値として扱います。 0 == False # => True 1 == True # => True 2 == True # => False -5 != True # => True # bool論理演算子を整数に対して使うことで整数を真偽値に変換して評価できますが、キャストされていない値が # bool(int)とビット演算子(& や |)を混同しないようにうにしましょう。 bool(0) # => False bool(4) # => True bool(-6) # => True 0 and 2 # => 0 -5 or 0 # => -5 # 値が等しいか確認するには == 1 == 1 # => True 2 == 1 # => False # 値が等しくないか確認するには != 1 != 1 # => False 2 != 1 # => True # 他の比較方法 1 < 10 # => True 1 > 10 # => False 2 <= 2 # => True 2 >= 2 # => True # 値がある範囲の中にあるか調べる方法 1 < 2 and 2 < 3 # => True 2 < 3 and 3 < 2 # => False # 連結させるともっと見やすくなります。 1 < 2 < 3 # => True 2 < 3 < 2 # => False # (is vs. ==) # "is" は、2つの変数が同一のオブジェクトを参照しているか確認します。 # 一方 "==" は、それぞれが参照する2つのオブジェクトが同じ値を持つか確認します。 a = [1, 2, 3, 4] # a は新しいリストの [1, 2, 3, 4] を指します。 b = a # b は a が指すリストを指します。 b is a # => True, a と b は同一のオブジェクトを参照しています。 b == a # => True, a と b が参照するオブジェクトの値は等しいです。 b = [1, 2, 3, 4] # b は新しいリストの [1, 2, 3, 4] を指します。 b is a # => False, a と b は別々のオブジェクトを参照しています。 b == a # => True, a と b が参照するオブジェクトの値は等しいです。 # " または ' を使って文字列を作成します。 "This is a string." 'This is also a string.' # 文字列も加算をすることができます!でも、あまり行わないように。 "Hello " + "world!" # => "Hello world!" # '+' を使わなくても文字列リテラル(変数ではないもの)の連結ができます。 "Hello " "world!" # => "Hello world!" # 文字列は文字のリストであるかのように扱うことができます。 "This is a string"[0] # => 'T' # 文字列の長さを得るにはこのようにします。 len("This is a string") # => 16 # .format で文字列のフォーマットを行えます "{} can be {}".format("Strings", "interpolated") # => "Strings can be interpolated" # 入力を減らすために、フォーマットするときに引数を繰り返し使うことができます。 "{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick") # => "Jack be nimble, Jack be quick, Jack jump over the candle stick" # 引数の順番を数えるのがお嫌い?キーワード引数をどうぞ。 "{name} wants to eat {food}".format(name="Bob", food="lasagna") # => "Bob wants to eat lasagna" # もし Python 3 のコードを Python 2.5以下でも使う必要があるなら、 # 旧式のフォーマット方法を使うこともできます。 "%s can be %s the %s way" % ("Strings", "interpolated", "old") # => "Strings can be interpolated the old way" # Python3.6以上では、f-stringsやフォーマット文字列を使ってフォーマットすることもできます。 name = "Reiko" f"She said her name is {name}." # => "She said her name is Reiko" # 基本的に、任意のPythonの文を中括弧に書くことができ、それは文字列で出力されます。 f"{name} is {len(name)} characters long." # => "Reiko is 5 characters long." # None はオブジェクトです(大文字からです!) None # => None # オブジェクトがNoneであるか確認するのに "==" 演算子を使わないように。 # 代わりに "is" を使いましょう。オブジェクトの素性を確認できます。 "etc" is None # => False None is None # => True # None や 0 、空の 文字列/リスト/辞書/タプル は全て False として評価されます。 # 他の全ての値は True になります。 bool(0) # => False bool("") # => False bool([]) # => False bool({}) # => False bool(()) # => False #################################################### # 2. 変数と集合 #################################################### # Python にはprint関数があります。 print("I'm Python. Nice to meet you!") # => I'm Python. Nice to meet you! # 標準では、print関数は最後に改行を出力します。 # この動作を変更するためには、オプション引数を利用します。 print("Hello, World", end="!") # => Hello, World! # コンソールから入力を得るための簡単な例 input_string_var = input("Enter some data: ") # 入力を文字列として返します。 # Note: Python の初期のバージョンでは、 input() は raw_input() という名前で存在します。 # Pythonでは変数の宣言は存在せず、代入のみです。 # 慣例的に、小文字でアンダースコア区切り ( lower_case_with_underscores ) の変数が使われます。 some_var = 5 some_var # => 5 # 代入されていない変数へのアクセスは例外を引き起こします。 # 例外の取り扱いについては、3章の制御の流れをご確認ください。 some_unknown_var # NameError を送出します。 # ifは式として使用できます。 # C言語の「?:(三項演算子)」に対応する例: "yahoo!" if 3 > 2 else 2 # => "yahoo!" # リストは順序を保存します。 li = [] # 値の入っているリストも作成できます。 other_li = [4, 5, 6] # append により、リストの末尾にものを入れられます。 li.append(1) # li is now [1] li.append(2) # li is now [1, 2] li.append(4) # li is now [1, 2, 4] li.append(3) # li is now [1, 2, 4, 3] # pop でリストの末尾から取り除けます。 li.pop() # => 3 and li is now [1, 2, 4] # 元に戻しましょう! li.append(3) # li is now [1, 2, 4, 3] again. # 配列のように、リストにアクセスできます。 li[0] # => 1 # 最後の要素を参照できます。 li[-1] # => 3 # 範囲外の要素を参照すると IndexError になります。 li[4] # IndexError が発生します。 # スライス構文により範囲を参照できます。 # 開始部分のインデックスに対応する部分は含まれますが、終了部分のインデックスに対応する部分は含まれません。 li[1:3] # => [2, 4] # 先端を取り除いたリスト li[2:] # => [4, 3] # 末尾を取り除いたリスト li[:3] # => [1, 2, 4] # 1つ飛ばしで選択する li[::2] # => [1, 4] # 反転したリストを得る li[::-1] # => [3, 4, 2, 1] # これらの任意の組み合わせにより、より複雑なスライスを作ることができます。 # li[start:end:step] # スライスにより、深いコピーを1階層分行うことができます。 li2 = li[:] # => li2 = [1, 2, 4, 3] だが、 (li2 is li) は False になる。 # "del"によりリストから任意の要素を削除できます。 del li[2] # li は [1, 2, 3] になりました。 # "remove"で最初に出現する要素を削除できます。 li.remove(2) # li は [1, 3] になりました。 li.remove(2) # 2 はリストの中に存在しないので、 ValueError が発生します。 # 要素を好きなところに挿入できます。 li.insert(1, 2) # li は [1, 2, 3] に戻りました。 # "index"で引数の要素が最初に出現する場所のインデックスを得られます。 li.index(2) # => 1 li.index(4) # 4 はリストの中に存在しないので、 ValueError が発生します。 # リスト同士を足すこともできます。 # Note: li と other_li の値は変更されません。 li + other_li # => [1, 2, 3, 4, 5, 6] # "extend()"で他のリストを連結することができます。 li.extend(other_li) # li は [1, 2, 3, 4, 5, 6] になります。 # リストの中に値が存在するか、 "in" で確認できます。 1 in li # => True # 長さは "len()" で確認できます。 len(li) # => 6 # タプルはリストのようなものですが、不変であるという違いがあります。 tup = (1, 2, 3) tup[0] # => 1 tup[0] = 3 # 内容を変更しようとすると TypeError が発生します。 # 長さが1のタプルを作成するには、要素の後にカンマを付ける必要があります。 # しかし、それ以外の長さなら、例え長さが0でもそのようにする必要はありません。 type((1)) # => type((1,)) # => type(()) # => # 大抵のリスト操作はタプルでも行うことができます。 len(tup) # => 3 tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) tup[:2] # => (1, 2) 2 in tup # => True # タプルやリストから複数の変数に代入することができます。 a, b, c = (1, 2, 3) # a, b, c にはそれぞれ 1, 2, 3 が代入されました。 # 拡張記法もあります。 a, *b, c = (1, 2, 3, 4) # a は 1、 b は [2, 3]、c は 4 になります。 # 括弧を作成しなくてもデフォルトでタプルが作成されます。 d, e, f = 4, 5, 6 # 4、5、6がそれぞれd、 e、 fに代入されます。 # 2つの変数を交換するのがどれほど簡単か見てみましょう。 e, d = d, e # d は 5、 e は 4 になります。 # 辞書はマップ(キーと値の組み合わせ)を保存できます。 empty_dict = {} # 値が入っている辞書を直接作成することもできます。 filled_dict = {"one": 1, "two": 2, "three": 3} # キーは不変の型である必要があります。 # これは、高速化のため、キーを定数のハッシュ値に変換できるようにするためです。 # 不変の型の例として、int、float、string、tupleなどが上げられます。 invalid_dict = {[1, 2, 3]: "123"} # => list はハッシュ化できないので、 TypeError が発生します。 valid_dict = {(1, 2, 3): [1, 2, 3]} # 一方、キーに対応する値はどのような型でも利用できます。 # [] で 値を取り出せます。 filled_dict["one"] # => 1 # "keys()"により、全てのキーを反復可能な形式で取り出せます。 # これをリストにするために、"list()"で囲んでいます。これについては後程解説します。 # Note: Python3.7未満では、辞書のキーの順番は考慮されていません。実行した結果がこれと異なる場合があります。 # しかし、Python3.7以降ではキーの挿入順を保つようになりました。 list(filled_dict.keys()) # => ["three", "two", "one"] in Python <3.7 list(filled_dict.keys()) # => ["one", "two", "three"] in Python 3.7+ # "values()"により、全ての値を反復可能な形式で取り出せます。 # 前と同じように、これをリストにするために、"list()"で囲んでいます。 # Note: 辞書の値の順番は考慮されていません。実行した結果がこれと異なる場合があります。 list(filled_dict.values()) # => [3, 2, 1] in Python <3.7 list(filled_dict.values()) # => [1, 2, 3] in Python 3.7+ # "in" により、辞書のキーが存在するか確認できます。 "one" in filled_dict # => True 1 in filled_dict # => False # 存在しないキーで辞書を参照すると KeyError になります。 filled_dict["four"] # KeyError # "get()" メソッドを使うことで KeyError を回避できます。 filled_dict.get("one") # => 1 filled_dict.get("four") # => None # get ではキーが存在しなかったときのデフォルト値を指定できます。 filled_dict.get("one", 4) # => 1 filled_dict.get("four", 4) # => 4 # "setdefault()" で、キーが存在しなかった場合のみ、値を設定できます。 filled_dict.setdefault("five", 5) # filled_dict["five"] は 5 になりました。 filled_dict.setdefault("five", 6) # filled_dict["five"] は 5 のままです。 # 辞書にマップを追加する filled_dict.update({"four": 4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} filled_dict["four"] = 4 # 辞書に追加する別の方法 # del により辞書からキーを削除できます。 del filled_dict["one"] # "one" キーを辞書から削除します。 # Python 3.5 以降では、追加の値を取り出す方法があります。 {'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} {'a': 1, **{'a': 2}} # => {'a': 2} # set では集合を表現できます。 empty_set = set() # 集合を一連の値で初期化する例です。辞書に似ていますね?ごめんなさい。 some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} # 辞書のキーのように、集合の値は不変である必要があります。 invalid_set = {[1], 1} # => list はハッシュ化できないので、 TypeError が送出されます。 valid_set = {(1,), 1} # 集合に新しい要素を追加できます。 filled_set = some_set filled_set.add(5) # filled_set は {1, 2, 3, 4, 5} になりました。 # 集合は重複した要素を持ちません。 filled_set.add(5) # 以前の {1, 2, 3, 4, 5} のままです。 # & により、集合同士の共通部分が得られます。 other_set = {3, 4, 5, 6} filled_set & other_set # => {3, 4, 5} # | により、集合同士の合併が得られます。 filled_set | other_set # => {1, 2, 3, 4, 5, 6} # - により、集合同士の差集合が得られます。 {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} # ^ により、集合同士の対象差が得られます。 {1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} # 左の集合が右の集合の上位集合であるか確認。 {1, 2} >= {1, 2, 3} # => False # 左の集合が右の集合の部分集合であるか確認。 {1, 2} <= {1, 2, 3} # => True # in により値が集合の中に存在するか確認できます。 2 in filled_set # => True 10 in filled_set # => False #################################################### # 3. 制御の流れと反復可能オブジェクト #################################################### # まずは変数を作りましょう。 some_var = 5 # これはif文です。Pythonではインデントが特徴的ですね! # 規約ではタブではなく4つのスペースでインデントすることが推奨されています。 # 以下の例では"some_var is smaller than 10"と出力されます。 if some_var > 10: print("some_var is totally bigger than 10.") elif some_var < 10: # この elif 節はオプションです。 print("some_var is smaller than 10.") else: # この else 節もオプションです。 print("some_var is indeed 10.") """ for ループはリストの要素を反復することができます。 出力: dog is a mammal cat is a mammal mouse is a mammal """ for animal in ["dog", "cat", "mouse"]: # format() を使って文字列に変数を挿入して出力できます。 print("{} is a mammal".format(animal)) """ "range(数値)" は、ゼロから与えられた数値までのiterable(反復可能オブジェクト)を返します。 出力: 0 1 2 3 """ for i in range(4): print(i) """ "range(lower, upper)" は、 lower の数値から upper の数値までのiterableを返します。 upper の数値は含まれません。 出力: 4 5 6 7 """ for i in range(4, 8): print(i) """ "range(lower, upper, step)" は、lower の数値から upper の数値までが、 step 刻みで表現されるiterableを返します。 step が与えられない場合、デフォルトは1になります。 出力: 4 6 """ for i in range(4, 8, 2): print(i) """ while によるループは条件が成立しなくなるまで実行されます。 出力: 0 1 2 3 """ x = 0 while x < 4: print(x) x += 1 # x = x + 1 の省略記法 # try/except ブロックにより、例外を扱う try: # "raise" により例外を発生させます。 raise IndexError("This is an index error") except IndexError as e: pass # pass は、何もしないという命令(no-op)に相当します。普通、ここで例外に対処します。 except (TypeError, NameError): pass # もし必要なら、複数の種類の例外を一緒に処理できます。 else: # try/except ブロックへのオプションの節。他の全てのexceptブロックより後に置かなければなりません。 print("All good!") # tryで例外が発生しなかった場合のみ実行されます。 finally: # 例外が発生したか、しなかったか、どのような例外だったかに関らず実行されます。 print("We can clean up resources here") # try/finallyでリソースの始末をする代わりに、 with 文を使うこともできます。 with open("myfile.txt") as f: for line in f: print(line) # Pythonは、iterableと呼ばれる基本的な抽象化が提供しています。 # iterableは、シーケンスとして取り扱えるオブジェクトです。 # range関数で返されるオブジェクトもiterableの一種です。 filled_dict = {"one": 1, "two": 2, "three": 3} our_iterable = filled_dict.keys() print(our_iterable) # => dict_keys(['one', 'two', 'three']). これはiterableインタフェースを実装するオブジェクトです。 # iterableでループを行うことができます。 for i in our_iterable: print(i) # Prints one, two, three # しかし、インデックスで要素を参照することはできません。 our_iterable[1] # TypeError が発生します。 # iterableは、iteratorの作り方がわかるオブジェクトです。 our_iterator = iter(our_iterable) # iterator は、要素を取り出したときの状態を覚えるオブジェクトです。 # "next()"により次の要素を取り出せます。 next(our_iterator) # => "one" # 反復(iterate)する度に、状態を更新します。 next(our_iterator) # => "two" next(our_iterator) # => "three" # iteratorが自身の持つ全てのデータを返したあとは、 StopIteration 例外を発生させます。 next(our_iterator) # StopIteration が発生します。 # "list()"を呼ぶことにより、iteratorの全ての要素を得られます。 list(filled_dict.keys()) # => ["one", "two", "three"] #################################################### # 4. 関数 #################################################### # 新しい関数を作成するには "def" を使います。 def add(x, y): print("x is {} and y is {}".format(x, y)) return x + y # return 文で値を返します。 # 引数付きで関数を呼んでみましょう。 add(5, 6) # => "x is 5 and y is 6" と出力し、 11 を返します。 # キーワード引数で関数を呼ぶこともできます。 add(y=6, x=5) # キーワード引数を使うと任意の順番で引数を指定できます。 # 可変数の位置引数を持つ関数を定義できます。 def varargs(*args): return args varargs(1, 2, 3) # => (1, 2, 3) # 可変数のキーワード引数を持つ関数を定義できます。 def keyword_args(**kwargs): return kwargs # 何が起こるか、試してみましょう。 keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} # お望みなら、両方一気にやることもできます。 def all_the_args(*args, **kwargs): print(args) print(kwargs) """ all_the_args(1, 2, a=3, b=4) prints: (1, 2) {"a": 3, "b": 4} """ # 関数を呼ぶとき、 args/kwargs の逆のことをすることができます! # * を使ってタプルを展開したり、 ** を使って辞書を展開できます。 args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # all_the_args(1, 2, 3, 4) と等しいです。 all_the_args(**kwargs) # all_the_args(a=3, b=4) と等しいです。 all_the_args(*args, **kwargs) # all_the_args(1, 2, 3, 4, a=3, b=4) と等しいです。 # タプルで複数の値を返す def swap(x, y): # 括弧を使わずに、複数の値をタプルとして返すことができます。 return y, x # (Note: 括弧は使わなくてもいいですが、使うこともできます。) x = 1 y = 2 x, y = swap(x, y) # => x = 2, y = 1 # (x, y) = swap(x,y) # このように、括弧は使っても使わなくてもいいです。 # 関数のスコープ x = 5 def set_x(num): # ローカル変数の x はグローバル変数の x とは異なります。 x = num # => 43 print(x) # => 43 def set_global_x(num): global x print(x) # => 5 x = num # グローバル変数の x に 6 が代入されました。 print(x) # => 6 set_x(43) set_global_x(6) # Pythonは第一級関数をサポートします。 def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) # => 13 # 無名関数もサポートしています。 (lambda x: x > 2)(3) # => True (lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 # 高階関数も組込まれています。 list(map(add_10, [1, 2, 3])) # => [11, 12, 13] list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] # map や filter の代わりに、リスト内包表記を使うことができます。 # リスト内包表記は、出力を別のリスト内包表記にネストさせることができます。 [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] # 集合(set)や辞書も内包表記ができます。 {x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} {x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} #################################################### # 5. モジュール #################################################### # Pythonではモジュールをインポートできます。 import math print(math.sqrt(16)) # => 4.0 # モジュールの中から特定の関数をインポートすることもできます。 from math import ceil, floor print(ceil(3.7)) # => 4.0 print(floor(3.7)) # => 3.0 # 全部の関数をモジュールからインポートすることができます。 # 注意: この方法は推奨されません。 from math import * # 短い名前でモジュールをインポートすることができます。 import math as m math.sqrt(16) == m.sqrt(16) # => True # Pythonのモジュールは実際には単なるPythonのファイルです。 # 自分で書くことも、インポートすることもできます。 # ファイル名がそのままモジュール名になります。 # モジュールで定義されている関数と属性を調べることができます。 import math dir(math) # もし、現在書いているスクリプトと同じフォルダに「math.py」という # Pythonのスクリプトが存在する場合、そのmath.pyが # 組み込みのPythonモジュールの代わりに読み込まれるでしょう。 # これは、ローカルのフォルダはPythonの組み込みライブラリよりも # 優先度が高いため発生するのです。 #################################################### # 6. クラス #################################################### # クラスを作成するために、class文を使います。 class Human: # クラスの属性です。このクラスの全てのインスタンスで共有されます。 species = "H. sapiens" # 標準的なイニシャライザで、このクラスがインスタンスを作成するときは毎回呼ばれます。 # 2つのアンダースコアがオブジェクトや属性の前後についているとき、これらはPythonによって利用され、 # ユーザーの名前空間には存在しないということに注意してください。 # __init__ や __str__ 、 __repr__ のようなメソッド(やオブジェクト、属性)は、 # special methods (または dunder methods)と呼ばれます。 # 同じような名前を自分で発明しないほうがよいでしょう。 def __init__(self, name): # 引数をインスタンスのname属性に設定します。 self.name = name # プロパティの初期化 self._age = 0 # インスタンスメソッド。全てのメソッドは"self"を最初の引数に取ります。 def say(self, msg): print("{name}: {message}".format(name=self.name, message=msg)) # 別のインスタンスメソッドの例。 def sing(self): return 'yo... yo... microphone check... one two... one two...' # クラスメソッドは全てのインスタンスで共有されます。 # クラスメソッドではクラスを最初の引数として呼ばれます。 @classmethod def get_species(cls): return cls.species # スタティックメソッドはクラスやインスタンスを参照せずに呼ばれます。 @staticmethod def grunt(): return "*grunt*" # プロパティはgetterのようなものです。 # age() メソッドを同名の読取専用属性に変換します。 # Pythonではわざわざgetterやsetterを書く必要はありません。 @property def age(self): return self._age # プロパティを設定できるようにします。 @age.setter def age(self, age): self._age = age # プロパティを削除できるようにします。 @age.deleter def age(self): del self._age # Pythonインタプリタがソースファイルを読み込んだとき、全てのコードを実行します。 # この __name__ による確認により、このモジュールがメインのプログラムである場合にのみ、 # このコードブロックが実行されるようにします。 if __name__ == '__main__': # クラスのインスタンスを作成します。 i = Human(name="Ian") i.say("hi") # "Ian: hi" j = Human("Joel") j.say("hello") # "Joel: hello" # i と j はHumanのインスタンスです。別の言葉で言うなら、これらはHumanのオブジェクトです。 # クラスメソッドを呼んでみましょう。 i.say(i.get_species()) # "Ian: H. sapiens" # 共有属性を変更してみましょう。 Human.species = "H. neanderthalensis" i.say(i.get_species()) # => "Ian: H. neanderthalensis" j.say(j.get_species()) # => "Joel: H. neanderthalensis" # スタティックメソッドを呼んでみましょう。 print(Human.grunt()) # => "*grunt*" # スタティックメソッドはインスタンスから呼ぶことはできません。 # なぜならば、 i.grunt() は自動的に"self" ( i オブジェクト ) を引数として渡してしまうからです。 print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given # インスタンスのプロパティを更新してみましょう。 i.age = 42 # プロパティを取得してみましょう。 i.say(i.age) # => "Ian: 42" j.say(j.age) # => "Joel: 0" # プロパティを削除してみましょう。 del i.age # i.age # => AttributeError が発生します。 #################################################### # 6.1 継承 #################################################### # 継承を行うことで、親クラスからメソッドと変数を継承する新しい子クラスを定義できます。 # 上記で定義されたHumanクラスを親クラス(基底クラス)として使い、Superheroという子クラスを定義します。 # これは"species"、"name"や"age"といった変数や、"sing"や"grunt"のようなメソッドをHumanから継承しますが、 # Superhero独自のプロパティを持つこともできます。 # ファイルを分割してモジュール化の利点を活用するために、上記のHumanクラスを独自のファイル、ここでは human.py に記述ましょう。 # 別のファイルから関数をインポートするには次の形式を利用してください: # from "拡張子なしのファイル名" import "関数やクラス" from human import Human # 親クラスを子クラスのパラメータとして指定します。 class Superhero(Human): # もし子クラスが親クラスの全ての定義を変更なしで継承する場合、"pass"キーワードのみを書くだけで良いです。 # しかし、今回は親クラスとは異なる子クラスを作成するので、今回は以下の通りコメントアウトしています。 # pass # 子クラスは親クラスの属性を上書きできます。 species = 'Superhuman' # 子クラスは親クラスのコンストラクタを引数含めて自動的に継承しますが、 # 追加の引数や定義を行ってコンストラクタのようなメソッドを上書きすることもできます。 # このコンストラクタは"name"引数を"Human"クラスから継承し、"superpower"と"movie"という引数を追加します。 def __init__(self, name, movie=False, superpowers=["super strength", "bulletproofing"]): # 追加のクラス属性を作成する self.fictional = True self.movie = movie # デフォルト値は共有されるので、可変のデフォルト値には注意してください。 self.superpowers = superpowers # "super"関数を使うと子クラスに上書きされた親クラスのメソッド(今回は "__init__")にアクセスできます。 # これで、親クラスのコンストラクタを呼んでいます。 super().__init__(name) # singメソッドを上書きし、 def sing(self): return 'Dun, dun, DUN!' # 追加のインスタンスメソッドを作成します。 def boast(self): for power in self.superpowers: print("I wield the power of {pow}!".format(pow=power)) if __name__ == '__main__': sup = Superhero(name="Tick") # インスタンスの型を調べる if isinstance(sup, Human): print('I am human') if type(sup) is Superhero: print('I am a superhero') # getattr()とsuper()で使われるメソッドの解決順序を調べてみます。 # この属性は動的であり、変更可能です。 print(Superhero.__mro__) # => (, # => , ) # 親のメソッドを呼びだすものの、独自のクラス属性を参照します。 print(sup.get_species()) # => Superhuman # 上書きされたメソッドを呼ぶ print(sup.sing()) # => Dun, dun, DUN! # Humanのメソッドを呼ぶ sup.say('Spoon') # => Tick: Spoon # Superhero限定のメソッドを呼ぶ sup.boast() # => I wield the power of super strength! # => I wield the power of bulletproofing! # 継承されたクラス属性 sup.age = 31 print(sup.age) # => 31 # Superhero限定の属性 print('Am I Oscar eligible? ' + str(sup.movie)) #################################################### # 6.2 多重継承 #################################################### # 別のクラスを定義します。 # bat.py class Bat: species = 'Baty' def __init__(self, can_fly=True): self.fly = can_fly # このクラスも say メソッドを持ちます。 def say(self, msg): msg = '... ... ...' return msg # 同様に、独自のメソッドも与えましょう。 def sonar(self): return '))) ... (((' if __name__ == '__main__': b = Bat() print(b.say('hello')) print(b.fly) # superhero.py from superhero import Superhero from bat import Bat # BatmanをSuperheroとBatの両方を継承した子クラスとして定義します。 class Batman(Superhero, Bat): def __init__(self, *args, **kwargs): # 通常、属性を継承するにはsuper()を呼び出します。 # super(Batman, self).__init__(*args, **kwargs) # しかし、ここでは多重継承を行っているので、 super() はMRO(メソッド解決順序)の次の基本クラスにのみ動作します。 # なので、全ての祖先に対して明示的に __init__ を呼ぶことにします。 # *args と **kwargs を使うことで、それぞれの継承元が # たまねぎの皮を剥がすごとく、引数を用いることができます。 Superhero.__init__(self, 'anonymous', movie=True, superpowers=['Wealthy'], *args, **kwargs) Bat.__init__(self, *args, can_fly=False, **kwargs) # 名前の属性の値を上書きします。 self.name = 'Sad Affleck' def sing(self): return 'nan nan nan nan nan batman!' if __name__ == '__main__': sup = Batman() # getattr() や super() の両方で使われるMROを取得します。 # この属性は動的であり、更新が可能です。 print(Batman.__mro__) # => (, # => , # => , # => , ) # 親メソッドを呼び出しますが、独自のクラス属性を参照します。 print(sup.get_species()) # => Superhuman # 上書きされたメソッドを呼び出します。 print(sup.sing()) # => nan nan nan nan nan batman! # 継承順により、Humanから継承されたメソッドを呼び出します。 sup.say('I agree') # => Sad Affleck: I agree # 2番目の先祖にのみ存在するメソッドを呼び出してみます。 print(sup.sonar()) # => ))) ... ((( # 継承されたクラス属性 sup.age = 100 print(sup.age) # => 100 # デフォルト値が上書きされて、2番目の先祖から継承された属性 print('Can I fly? ' + str(sup.fly)) # => Can I fly? False #################################################### # 7. 発展的内容 #################################################### # ジェネレータは遅延をするコードの作成に役立ちます。 def double_numbers(iterable): for i in iterable: yield i + i # 次の値を処理するのに必要なデータしか読み込まないので、ジェネレータはメモリをあまり消費しません。 # この性質により、他の方法では非常に多くのメモリを消費するような操作が可能になります。 for i in double_numbers(range(1, 900000000)): # `range` もジェネレータの1つです。 print(i) if i >= 30: break # リスト内包表記のように、ジェネータ内包表記を作成することもできます。 values = (-x for x in [1, 2, 3, 4, 5]) for x in values: print(x) # prints -1 -2 -3 -4 -5 # ジェネレータ内包表記から直接リストを作成することもできます。 values = (-x for x in [1, 2, 3, 4, 5]) gen_to_list = list(values) print(gen_to_list) # => [-1, -2, -3, -4, -5] # デコレータ # この例では`beg` が `say` を `wraps`します。 # もし say_please が True なら、出力が変更されます。 from functools import wraps def beg(target_function): @wraps(target_function) def wrapper(*args, **kwargs): msg, say_please = target_function(*args, **kwargs) if say_please: return "{} {}".format(msg, "Please! I am poor :(") return msg return wrapper @beg def say(say_please=False): msg = "Can you buy me a beer?" return msg, say_please print(say()) # Can you buy me a beer? print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( ``` ## さらなる学習の準備ができましたか? ### 無料のオンラインコンテンツ * [Automate the Boring Stuff with Python](https://automatetheboringstuff.com) * [Ideas for Python Projects](http://pythonpracticeprojects.com) * [The Official Docs](http://docs.python.org/3/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/) * [Python Course](http://www.python-course.eu/index.php) * [First Steps With Python](https://realpython.com/learn/python-first-steps/) * [A curated list of awesome Python frameworks, libraries and software](https://github.com/vinta/awesome-python) * [Official Style Guide for Python](https://peps.python.org/pep-0008/) * [Python 3 Computer Science Circles](http://cscircles.cemc.uwaterloo.ca/) * [Dive Into Python 3](http://www.diveintopython3.net/index.html) ================================================ FILE: ja/r.md ================================================ --- contributors: - ["e99n09", "http://github.com/e99n09"] - ["isomorphismes", "http://twitter.com/isomorphisms"] translators: - ["akirahirose", "https://twitter.com/akirahirose"] --- R は統計計算用の言語です。 データの取得やクリーニング、統計処理やグラフ作成をするために便利な、たくさんのライブラリがあります。また、LaTeX文書からRコマンドを呼び出すこともできます ```r # コメント行は、#で開始します # 複数行をまとめてコメントにすることはできないので、 # コメントを複数の行に分けたい場合、このように、単に毎行をコメントにしてください # WindowsやMacでは、 COMMAND-ENTERで、コマンドを1行実行できます ############################################################################# # プログラミングがわからなくとも使えるコマンド類 ############################################################################# # この節では、プログラミングがわからなくとも使える便利なRコマンドを紹介します # 全てを理解できなくとも、まずはやってみましょう! data() # 既にロードされているデータを閲覧します data(rivers) # "北米にある大きな川の長さ"データを取得します ls() # "rivers" がワークスペースに表示されました head(rivers) # データの先頭部分です # 735 320 325 392 524 450 length(rivers) # 何本の川がデータにある? # 141 summary(rivers) # 統計的に要約するとどうなる? # Min. 1st Qu. Median Mean 3rd Qu. Max. # 135.0 310.0 425.0 591.2 680.0 3710.0 # 茎葉図(ヒストグラムに似た図)を描く stem(rivers) # The decimal point is 2 digit(s) to the right of the | # # 0 | 4 # 2 | 011223334555566667778888899900001111223333344455555666688888999 # 4 | 111222333445566779001233344567 # 6 | 000112233578012234468 # 8 | 045790018 # 10 | 04507 # 12 | 1471 # 14 | 56 # 16 | 7 # 18 | 9 # 20 | # 22 | 25 # 24 | 3 # 26 | # 28 | # 30 | # 32 | # 34 | # 36 | 1 stem(log(rivers)) # このデータは、正規分布でも対数正規分布でもないので、注意! # 特に正規分布原理主義のみなさん # The decimal point is 1 digit(s) to the left of the | # # 48 | 1 # 50 | # 52 | 15578 # 54 | 44571222466689 # 56 | 023334677000124455789 # 58 | 00122366666999933445777 # 60 | 122445567800133459 # 62 | 112666799035 # 64 | 00011334581257889 # 66 | 003683579 # 68 | 0019156 # 70 | 079357 # 72 | 89 # 74 | 84 # 76 | 56 # 78 | 4 # 80 | # 82 | 2 # ヒストグラム作成 hist(rivers, col="#333333", border="white", breaks=25) # これらのパラメータをつかいます hist(log(rivers), col="#333333", border="white", breaks=25) # いろいろな使い方ができます # 別のロード済データでやってみましょう。Rには、いろいろなデータがロードされています。 data(discoveries) plot(discoveries, col="#333333", lwd=3, xlab="Year", main="Number of important discoveries per year") plot(discoveries, col="#333333", lwd=3, type = "h", xlab="Year", main="Number of important discoveries per year") # 年次のソートだけではなく、 # 標準的な並べ替えもできます sort(discoveries) # [1] 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 # [26] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 # [51] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 # [76] 4 4 4 4 5 5 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 8 9 10 12 stem(discoveries, scale=2) # # The decimal point is at the | # # 0 | 000000000 # 1 | 000000000000 # 2 | 00000000000000000000000000 # 3 | 00000000000000000000 # 4 | 000000000000 # 5 | 0000000 # 6 | 000000 # 7 | 0000 # 8 | 0 # 9 | 0 # 10 | 0 # 11 | # 12 | 0 max(discoveries) # 12 summary(discoveries) # Min. 1st Qu. Median Mean 3rd Qu. Max. # 0.0 2.0 3.0 3.1 4.0 12.0 # サイコロを振ります round(runif(7, min=.5, max=6.5)) # 1 4 6 1 4 6 4 # 私と同じrandom.seed(31337)を使わない限りは、別の値になります # ガウス分布を9回生成します rnorm(9) # [1] 0.07528471 1.03499859 1.34809556 -0.82356087 0.61638975 -1.88757271 # [7] -0.59975593 0.57629164 1.08455362 ################################################## # データ型と基本計算 ################################################## # ここからは、プログラミングをつかうチュートリアルです # この節ではRで重要なデータ型(データクラス)の、整数型、数字型、文字型、論理型と因子(ファクター)型をつかいます # 他にもいろいろありますが、これらの必要最小限なものから始めましょう # 整数型 # 整数型はLで指定します 5L # 5 class(5L) # "integer" # (?class を実行すると、class()関数について、さらなる情報が得られます) # Rでは、この5Lのような1つの値は、長さ1のベクトルとして扱われます length(5L) # 1 # 整数型のベクトルはこのようにつくります c(4L, 5L, 8L, 3L) # 4 5 8 3 length(c(4L, 5L, 8L, 3L)) # 4 class(c(4L, 5L, 8L, 3L)) # "integer" # 数字型 # 倍精度浮動小数点数です 5 # 5 class(5) # "numeric" # しつこいですが、すべてはベクトルです # 1つ以上の要素がある数字のベクトルも、作ることができます c(3,3,3,2,2,1) # 3 3 3 2 2 1 # 指数表記もできます 5e4 # 50000 6.02e23 # アボガドロ数 1.6e-35 # プランク長 # 無限大、無限小もつかえます class(Inf) # "numeric" class(-Inf) # "numeric" # 例のように、"Inf"を使ってください。integrate( dnorm(x), 3, Inf); # Z-スコア表が必要なくなります # 基本的な計算 # 数を計算できます # 整数と整数以外の数字を両方使った計算をすると、結果は整数以外の数字になります 10L + 66L # 76 # 整数足す整数は整数 53.2 - 4 # 49.2 # 整数引く数字は数字 2.0 * 2L # 4 # 数字かける整数は数字 3L / 4 # 0.75 # 整数割る数字は数字 3 %% 2 # 1 # 二つの数字を割った余りは数字 # 不正な計算は "not-a-number"になります 0 / 0 # NaN class(NaN) # "numeric" # 長さが1より大きなベクター同士の計算もできます # どちらかが長い場合、短い方は何度も繰り返して使われます c(1,2,3) + c(1,2,3) # 2 4 6 # 文字 # Rでは、文字列と文字に区別がありません "Horatio" # "Horatio" class("Horatio") # "character" class('H') # "character" # 上記は両方とも、長さ1のベクターです # 以下は、より長い場合です c('alef', 'bet', 'gimmel', 'dalet', 'he') # => # "alef" "bet" "gimmel" "dalet" "he" length(c("Call","me","Ishmael")) # 3 # 正規表現処理を文字ベクターに適用できます substr("Fortuna multis dat nimis, nulli satis.", 9, 15) # "multis " gsub('u', 'ø', "Fortuna multis dat nimis, nulli satis.") # "Fortøna møltis dat nimis, nølli satis." # Rはいくつかの文字ベクターを組み込みで持っています letters # => # [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" # [20] "t" "u" "v" "w" "x" "y" "z" month.abb # "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec" # 論理 # Rでは、Booleanは論理(logical)型です class(TRUE) # "logical" class(FALSE) # "logical" # 以下は比較演算子の例です TRUE == TRUE # TRUE TRUE == FALSE # FALSE FALSE != FALSE # FALSE FALSE != TRUE # TRUE # 無いデータ (NA) も論理型です class(NA) # "logical" # 以下のようにすると、複数の要素を持つ、論理型ベクターが返ります c('Z', 'o', 'r', 'r', 'o') == "Zorro" # FALSE FALSE FALSE FALSE FALSE c('Z', 'o', 'r', 'r', 'o') == "Z" # TRUE FALSE FALSE FALSE FALSE # 因子(ファクター) # 因子型は、カテゴリカルデータ用の型です # 因子には、子供の学年のように順序がつけられるものか、性別のように順序がないものがあります factor(c("female", "female", "male", "NA", "female")) # female female male NA female # Levels: female male NA # "levels" は、カテゴリカルデータがとりうる値を返します levels(factor(c("male", "male", "female", "NA", "female"))) # "female" "male" "NA" # 因子ベクターの長さが1ならば、そのlevelも1です length(factor("male")) # 1 length(levels(factor("male"))) # 1 # 因子型は、この後で紹介するデータフレーム(というデータ型)内で、よくみられます data(infert) # "Infertility after Spontaneous and Induced Abortion" levels(infert$education) # "0-5yrs" "6-11yrs" "12+ yrs" # NULL # "NULL" は特殊な型なのですが、ベクターを空にするときに使います class(NULL) # NULL parakeet # => # [1] "beak" "feathers" "wings" "eyes" parakeet <- NULL parakeet # => # NULL # 型の強制 # 型の強制とは、ある値を、強制的に別の型として利用する事です as.character(c(6, 8)) # "6" "8" as.logical(c(1,0,1,1)) # TRUE FALSE TRUE TRUE # さまざまな要素が入っているベクターに対して型の強制を行うと、おかしなことになります c(TRUE, 4) # 1 4 c("dog", TRUE, 4) # "dog" "TRUE" "4" as.numeric("Bilbo") # => # [1] NA # Warning message: # NAs introduced by coercion # 追記: ここで紹介したのは、基本的な型だけです # 実際には、日付(dates)や時系列(time series)など、いろいろな型があります ################################################## # 変数、ループ、もし/ほかに(if/else) ################################################## # 変数は、ある値を後で使うために入れておく、箱のようなものです # 箱に入れることを、変数に値を代入する、といいます # 変数を使うと、ループや関数、if/else 分岐を利用できます # 変数 # 代入する方法はいろいろあります x = 5 # これはできます y <- "1" # これがおすすめです TRUE -> z # これも使えますが、ちょっとわかりにくいですね # ループ # forでループできます for (i in 1:4) { print(i) } # whileでループできます a <- 10 while (a > 4) { cat(a, "...", sep = "") a <- a - 1 } # Rでは、forやwhileは遅いことを覚えておいてください # ベクターを丸ごと処理する(つまり、行全体や、列全体を指定して処理する)か、 # 後述する、apply()系の関数を使うのが、速度的にはお勧めです # IF/ELSE # ごく普通のif文です if (4 > 3) { print("4 is greater than 3") } else { print("4 is not greater than 3") } # => # [1] "4 is greater than 3" # 関数 # 以下のように定義します jiggle <- function(x) { x = x + rnorm(1, sd=.1) #すこしだけ(制御された)ノイズを入れます return(x) } # 他の関数と同じように、呼びます jiggle(5) # 5±ε. set.seed(2716057)をすると、jiggle(5)==5.005043 ########################################################################### # データ構造: ベクター、行列、データフレーム、配列 ########################################################################### # 1次元 # まずは基本からです。ご存じベクターからです vec <- c(8, 9, 10, 11) vec # 8 9 10 11 # 特定の要素を、[角括弧]による指定で取り出せます # (Rでは、最初の要素は1番目と数えます) vec[1] # 8 letters[18] # "r" LETTERS[13] # "M" month.name[9] # "September" c(6, 8, 7, 5, 3, 0, 9)[3] # 7 # 特定のルールに当てはまる要素を見つけることもできます which(vec %% 2 == 0) # 1 3 # 最初か最後の数個を取り出すこともできます head(vec, 1) # 8 tail(vec, 2) # 10 11 # ある値がベクターにあるかどうかをみることができます any(vec == 10) # TRUE # ベクターの数より大きなインデックスを指定すると、NAが返ります vec[6] # NA # ベクターの長さは、length()で取得できます length(vec) # 4 # ベクター全体、または1部に対して、操作ができます vec * 4 # 16 20 24 28 vec[2:3] * 5 # 25 30 any(vec[2:3] == 8) # FALSE # R には、ベクターにある値を要約するための様々な関数があります mean(vec) # 9.5 var(vec) # 1.666667 sd(vec) # 1.290994 max(vec) # 11 min(vec) # 8 sum(vec) # 38 # 他にも、ベクター関連ではいろいろな関数があります。以下はベクターをつくるための方法です 5:15 # 5 6 7 8 9 10 11 12 13 14 15 seq(from=0, to=31337, by=1337) # => # [1] 0 1337 2674 4011 5348 6685 8022 9359 10696 12033 13370 14707 # [13] 16044 17381 18718 20055 21392 22729 24066 25403 26740 28077 29414 30751 # 2次元配列 (すべての値が同じ型の場合) # 同じ型の値が含まれる2次元配列は、このように作れます mat <- matrix(nrow = 3, ncol = 2, c(1,2,3,4,5,6)) mat # => # [,1] [,2] # [1,] 1 4 # [2,] 2 5 # [3,] 3 6 # ベクターとは違い、2次元配列の型名は"matrix"です。 class(mat) # => "matrix" # 最初の行 mat[1,] # 1 4 # 最初の列に対する操作 3 * mat[,1] # 3 6 9 # 特定のセルを取り出し mat[3,2] # 6 # 2次元配列全体を転置します t(mat) # => # [,1] [,2] [,3] # [1,] 1 2 3 # [2,] 4 5 6 # 2次元配列の積 mat %*% t(mat) # => # [,1] [,2] [,3] # [1,] 17 22 27 # [2,] 22 29 36 # [3,] 27 36 45 # cbind() は、複数のベクターを、別々の列に並べて2次元配列を作ります mat2 <- cbind(1:4, c("dog", "cat", "bird", "dog")) mat2 # => # [,1] [,2] # [1,] "1" "dog" # [2,] "2" "cat" # [3,] "3" "bird" # [4,] "4" "dog" class(mat2) # matrix # ここでいま1度、2次元配列内の型について注意してください! # 2次元配列にある値は、すべて同じ型にする必要があります。そのため、すべて文字型に変換されています c(class(mat2[,1]), class(mat2[,2])) # rbind() は、複数のベクターを、別々の行に並べて2次元配列を作ります mat3 <- rbind(c(1,2,4,5), c(6,7,0,4)) mat3 # => # [,1] [,2] [,3] [,4] # [1,] 1 2 4 5 # [2,] 6 7 0 4 # 全ての値は同じ型になります。上記例は幸い、強制変換がされないものでした # 2次元配列 (いろいろな型を含む場合) # 異なる型の値を含む配列をつくりたい場合、データフレームを使ってください # データフレームは、統計処理を行うプログラムをする際にとても便利です # Pythonでも、 "pandas"というパッケージにて、似たものが利用可能です students <- data.frame(c("Cedric","Fred","George","Cho","Draco","Ginny"), c(3,2,2,1,0,-1), c("H", "G", "G", "R", "S", "G")) names(students) <- c("name", "year", "house") #カラム名 class(students) # "data.frame" students # => # name year house # 1 Cedric 3 H # 2 Fred 2 G # 3 George 2 G # 4 Cho 1 R # 5 Draco 0 S # 6 Ginny -1 G class(students$year) # "numeric" class(students[,3]) # "factor" # 行と列の数をみます nrow(students) # 6 ncol(students) # 3 dim(students) # 6 3 # このdata.frame() 関数は、デフォルトでは文字列ベクターを因子ベクターに変換します # stringsAsFactors = FALSE に設定してからデータフレームを作成すると、変換されません ?data.frame # データフレームの1部を取り出すには、いろいろな(変な)、似たような方法があります students$year # 3 2 2 1 0 -1 students[,2] # 3 2 2 1 0 -1 students[,"year"] # 3 2 2 1 0 -1 # データフレームの拡張版が、データテーブルです。 # 大きなデータやパネルデータ、データセットの結合が必要な場合には、データテーブルを使うべきです。 # 以下に駆け足で説明します install.packages("data.table") # CRANからパッケージをダウンロードします require(data.table) # ロードします students <- as.data.table(students) students # 若干異なる出力がされることに注意 # => # name year house # 1: Cedric 3 H # 2: Fred 2 G # 3: George 2 G # 4: Cho 1 R # 5: Draco 0 S # 6: Ginny -1 G students[name=="Ginny"] # name == "Ginny"の行を取り出します # => # name year house # 1: Ginny -1 G students[year==2] # year == 2の行を取り出します # => # name year house # 1: Fred 2 G # 2: George 2 G # データテーブルは、二つのデータセットを結合するのにも便利です # 結合用に、生徒データが入った別のデータテーブルをつくります founders <- data.table(house=c("G","H","R","S"), founder=c("Godric","Helga","Rowena","Salazar")) founders # => # house founder # 1: G Godric # 2: H Helga # 3: R Rowena # 4: S Salazar setkey(students, house) setkey(founders, house) students <- founders[students] # 二つのデータテーブルを、"house"をキーとして結合します setnames(students, c("house","houseFounderName","studentName","year")) students[,order(c("name","year","house","houseFounderName")), with=F] # => # studentName year house houseFounderName # 1: Fred 2 G Godric # 2: George 2 G Godric # 3: Ginny -1 G Godric # 4: Cedric 3 H Helga # 5: Cho 1 R Rowena # 6: Draco 0 S Salazar # データテーブルは、要約を作るのも簡単です students[,sum(year),by=house] # => # house V1 # 1: G 3 # 2: H 3 # 3: R 1 # 4: S 0 # データフレームやデータテーブルから列を消したい場合は、NULL値を代入します students$houseFounderName <- NULL students # => # studentName year house # 1: Fred 2 G # 2: George 2 G # 3: Ginny -1 G # 4: Cedric 3 H # 5: Cho 1 R # 6: Draco 0 S # データテーブルから行を消す場合は、以下のように除く行を指定すればできます students[studentName != "Draco"] # => # house studentName year # 1: G Fred 2 # 2: G George 2 # 3: G Ginny -1 # 4: H Cedric 3 # 5: R Cho 1 # データフレームの場合も同様です students <- as.data.frame(students) students[students$house != "G",] # => # house houseFounderName studentName year # 4 H Helga Cedric 3 # 5 R Rowena Cho 1 # 6 S Salazar Draco 0 # 多次元 (すべての値が同じ型の場合) # 配列を並べて、N次元の表を作ります # 配列なので、すべての値は同じ型にする必要があります # ちなみに、以下のようにすれば2次元配列・2次元表も作成可能です array(c(c(1,2,4,5),c(8,9,3,6)), dim=c(2,4)) # => # [,1] [,2] [,3] [,4] # [1,] 1 4 8 3 # [2,] 2 5 9 6 # 2次元配列を並べて、3次元配列を作ることもできます array(c(c(c(2,300,4),c(8,9,0)),c(c(5,60,0),c(66,7,847))), dim=c(3,2,2)) # => # , , 1 # # [,1] [,2] # [1,] 2 8 # [2,] 300 9 # [3,] 4 0 # # , , 2 # # [,1] [,2] # [1,] 5 66 # [2,] 60 7 # [3,] 0 847 # リスト(多次元、不完全または複数の型が使われているもの) # ついにRのリストです list1 <- list(time = 1:40) list1$price = c(rnorm(40,.5*list1$time,4)) # random list1 # リストの要素は以下のようにして取得できます list1$time # ある方法 list1[["time"]] # 別の方法 list1[[1]] # また別の方法 # => # [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # [34] 34 35 36 37 38 39 40 # 他のベクターと同じく、1部を取り出すことができます list1$price[4] # リストは、Rで1番効率的なデータ型ではありません # 特別な理由がない限りは、リストの代わりにデータフレームを使うべきです # リストは、線形回帰関数の返値として、しばしば使われています ################################################## # apply() 系の関数 ################################################## # matは覚えていますよね? mat # => # [,1] [,2] # [1,] 1 4 # [2,] 2 5 # [3,] 3 6 # apply(X, MARGIN, FUN) は、行列Xの行(MARGIN=1で指定)または列(MARGIN=2で指定)に対して、関数FUNを実行します # Rで、このように指定してXの全行または全列に関数を実行するのは、forやwhileループを使うよりも、遥かに速いです apply(mat, MAR = 2, jiggle) # => # [,1] [,2] # [1,] 3 15 # [2,] 7 19 # [3,] 11 23 # 他にも便利な関数があります。?lapply, ?sapply で確認してみてください # apply()系関数の使い方は、ちょっとややこしいです(みんなそう思ってます)。なので、あまり怖がりすぎないでください # plyr パッケージは、*apply() 系の関数を置き換えて(さらに改善して)いこうとしています install.packages("plyr") require(plyr) ?plyr ######################### # データロード ######################### # "pets.csv"は、インターネット上に置いてあるファイルです # (しかし、自分のPCにあるのと同じぐらい簡単に扱う事ができます) pets <- read.csv("https://learnxinyminutes.com/pets.csv") pets head(pets, 2) # 最初の2行 tail(pets, 1) # 最後の行 # データフレームか行列をcsvファイルとして保存します write.csv(pets, "pets2.csv") # 新しくcsvファイルを作ります # ワーキングディレクトリを、setwd()で設定します。 ワーキングディレクトリは getwd()で確認可能です # ?read.csv や ?write.csv を入力すると、よりたくさんの情報を確認できます ######################### # プロット ######################### # Rに組込まれているプロット関数をつかいます # 散布図! plot(list1$time, list1$price, main = "fake data") # 回帰図! linearModel <- lm(price ~ time, data = list1) linearModel # outputs result of regression # 回帰直線を既存の図上に引きます abline(linearModel, col = "red") # いろいろな散布図をつくって、確認できます plot(linearModel) # ヒストグラム! hist(rpois(n = 10000, lambda = 5), col = "thistle") # 棒グラフ! barplot(c(1,4,5,1,2), names.arg = c("red","blue","purple","green","yellow")) # GGPLOT2 # 上記の組込み関数を使うよりも、もっときれいな図を描くこともできます # ggplot2 パッケージを使って、より多くのよい図を描いてみましょう install.packages("ggplot2") require(ggplot2) ?ggplot2 pp <- ggplot(students, aes(x=house)) pp + geom_histogram() ll <- as.data.table(list1) pp <- ggplot(ll, aes(x=time,price)) pp + geom_point() # ggplot2 には、素晴らしい関連ドキュメントがそろっています (http://docs.ggplot2.org/current/) ``` ## Rの入手方法 * RとR GUIはこちら [http://www.r-project.org/](http://www.r-project.org/) * [RStudio](http://www.rstudio.com/ide/) 別のGUI ================================================ FILE: ja/rust.md ================================================ --- contributors: - ["P1start", "http://p1start.github.io/"] translators: - ["Takashi Takeda", "https://github.com/Takashicc"] --- RustはMozilla Researchによって開発されたプログラミング言語です。 Rustは低レベルの性能制御と高レベルの利便性と、安全性の保証を兼ね備えています。 ガベージコレクションやランタイムを必要としないことから上記の目標が達成出来ます。 それによってRustライブラリをC言語の「完全互換品」として使用することが可能です。 Rustの最初のリリースである0.1は、2012年1月にリリースされ、 その後3年間の開発は非常に速く進み、最近までは安定板リリースの利用は推奨されていませんでした。 代わりにナイトリービルドを使用することが一般的なアドバイスでした。 2015年5月15日、後方互換性を完全に保障したRust 1.0がリリースされました。 コンパイル時間などの改善は、現在ナイトリービルドで提供されています。 Rustはトレインリリースモデルを採用しており、6週間ごとにリリースしています。 Rust 1.1 ベータ版は、Rust 1.0がリリースされたのと同時にリリースされました。 Rustは比較的低レベルの言語ですが、一般的に高水準言語に見られるようないくつかの概念を持っています。 これによりRustはただ速いだけではなく、コーディングが簡単で効率的に書くことが出来ます。 ```rust // これはコメントです。 行コメントはこのように書けます... // そしてこのように複数行に分けて書くこともできます。 /// ドキュメントコメントはこのように書けて、マークダウン記法をサポートしています。 /// # Examples /// /// ``` /// let five = 5 /// ``` //////////// // 1. 基本 // //////////// #[allow(dead_code)] // 関数 // `i32` は32ビットの符号付き整数の型です fn add2(x: i32, y: i32) -> i32 { // 暗黙の戻り値 (セミコロンなし) x + y } #[allow(unused_variables)] #[allow(unused_assignments)] #[allow(dead_code)] // Main関数 fn main() { // 数値 // // 不変な変数 let x: i32 = 1; // 整数/浮動小数点の型を数値の末尾に let y: i32 = 13i32; let f: f64 = 1.3f64; // 型推論 // ほとんどの場合、Rustコンパイラは変数の型を推測することができるため、 // 明示的に型アノテーションを書く必要はありません。 // このチュートリアルでは、多くの場所で明示的に型がアノテーションされていますが、 // あくまで説明目的です。型推論はほとんどの場合処理することができます。 let implicit_x = 1; let implicit_f = 1.3; // 算術 let sum = x + y + 13; // 可変な変数 let mut mutable = 1; mutable = 4; mutable += 2; // 文字列 // // 文字列リテラル let x: &str = "hello world!"; // プリント println!("{} {}", f, x); // 1.3 hello world // `String`はヒープに割り当てられた文字列です。 // `Vec`としてヒープに格納され、 // 常に有効なUTF-8シーケンス(ヌル文字で終了していない)を保持します。 let s: String = "hello world".to_string(); // 文字列スライスは不変なビューを別の文字列に変換します。 // これは基本的に文字列への不変のポインタのペアを保持しており、 // 文字そのものは保持していません。 // 文字列バッファの先頭と末尾へのポイントだけを保持しています。 // 静的割り当てられるか、別のオブジェクトに含まれます。(この場合は`s`) // 文字列スライスは`&[u8]`を`Vec`に変換するようなものです。 let s_slice: &str = &s; println!("{} {}", s, s_slice); // hello world hello world // ベクター/配列 // // 固定サイズの配列 let four_ints: [i32; 4] = [1, 2, 3, 4]; // 動的配列(ベクター) let mut vector: Vec = vec![1, 2, 3, 4]; vector.push(5); // スライスは不変なビューをベクターまたは配列に変換します。 // これは文字列スライスによく似ていますが、ベクターに対してのものです。 let slice: &[i32] = &vector; // デバッグ形式で何かを表示する際は、`{:?}`を使用できます。 println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] // タプル // // タプルは固定サイズの値の集合でできており、値それぞれが異なる型でもよい let x: (i32, &str, f64) = (1, "hello", 3.4); // `let`をデストラクト let (a, b, c) = x; println!("{} {} {}", a, b, c); // 1 hello 3.4 // インデックス println!("{}", x.1); // hello /////////// // 2. 型 // /////////// // 構造体 struct Point { x: i32, y: i32, } let origin: Point = Point { x: 0, y: 0 }; // 名前のないフィールドで構成された構造体は、タプル構造体と言われる。 struct Point2(i32, i32); let origin2 = Point2(0, 0); // C言語風列挙型 enum Direction { Left, Right, Up, Down, } let up = Direction::Up; // フィールドがある列挙型 enum OptionalI32 { AnI32(i32), Nothing, } let two: OptionalI32 = OptionalI32::AnI32(2); let nothing = OptionalI32::Nothing; // ジェネリクス // struct Foo { bar: T } // 以下は標準ライブラリで定義されている`Option`です。 enum Optional { SomeVal(T), NoVal, } // メソッド // impl Foo { // メソッドは明示的に`self`パラメータを受け取ります。 fn bar(&self) -> &T { // `self`は借用されています。 &self.bar } fn bar_mut(&mut self) -> &mut T { // `self`は可変に借用されています。 &mut self.bar } fn into_bar(self) -> T { // `self`は消費されています。 self.bar } } let a_foo = Foo { bar: 1 }; println!("{}", a_foo.bar()); // 1 // トレイト (他の言語ではインターフェースや型クラスとして知られています) // trait Frobnicate { fn frobnicate(self) -> Option; } impl Frobnicate for Foo { fn frobnicate(self) -> Option { Some(self.bar) } } let another_foo = Foo { bar: 1 }; println!("{:?}", another_foo.frobnicate()); // Some(1) // 関数ポインタの種類 // fn fibonacci(n: u32) -> u32 { match n { 0 => 1, 1 => 1, _ => fibonacci(n - 1) + fibonacci(n - 2), } } type FunctionPointer = fn(u32) -> u32; let fib : FunctionPointer = fibonacci; println!("Fib: {}", fib(4)); ///////////////////////// // 3. パターンマッチング // ///////////////////////// let foo = OptionalI32::AnI32(1); match foo { OptionalI32::AnI32(n) => println!("it’s an i32: {}", n), OptionalI32::Nothing => println!("it’s nothing!"), } // 応用的なパターンマッチング struct FooBar { x: i32, y: OptionalI32 } let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) }; match bar { FooBar { x: 0, y: OptionalI32::AnI32(0) } => println!("The numbers are zero!"), FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m => println!("The numbers are the same"), FooBar { x: n, y: OptionalI32::AnI32(m) } => println!("Different numbers: {} {}", n, m), FooBar { x: _, y: OptionalI32::Nothing } => println!("The second number is Nothing!"), } ////////////////// // 4. 制御フロー // ////////////////// // `for`ループ/イテレーション let array = [1, 2, 3]; for i in array { println!("{}", i); } // 範囲 for i in 0u32..10 { print!("{} ", i); } println!(""); // 右記にある文をプリントします `0 1 2 3 4 5 6 7 8 9 ` // `if` if 1 == 1 { println!("Maths is working!"); } else { println!("Oh no..."); } // 式として使う`if` let value = if true { "good" } else { "bad" }; // `while` loop while 1 == 1 { println!("The universe is operating normally."); // break文でwhileループから抜け出せます。 // 無駄な繰り返しを避けることができます。 break } // 無限ループ loop { println!("Hello!"); // break文でループから抜け出せます。 break } /////////////////////////// // 5. メモリ安全とポインタ // /////////////////////////// // 所有ポインタはポインタを「所有」できるのは、一度に1つだけです。 // つまり、`Box`がそのスコープから離れると、自動的に安全に解放されます。 let mut mine: Box = Box::new(3); *mine = 5; // デリファレンス // ここで`now_its_mine`が`mine`の所有権を取得します。言い換えると`mine`がムーブしました。 let mut now_its_mine = mine; *now_its_mine += 2; println!("{}", now_its_mine); // 7 // println!("{}", mine); // これは`now_its_mine`がポインタを所有しているため、コンパイルができません。 // 参照は他のデータを参照する不変なポインタです。 // 値を参照する場合、値を「借用」したと言います。 // 値が不変に借用されている間は、値を変更したり、ムーブすることはできない。 // 借用は借用されている変数が使用されている最後まで有効です。 let mut var = 4; var = 3; let ref_var: &i32 = &var; println!("{}", var); // `mine`と違って、`var`はまだ使用できます。 println!("{}", *ref_var); // var = 5; // `var`が借用されているため、コンパイルができません。 // *ref_var = 6; // `ref_var`が不変な参照であるため、コンパイルできません。 ref_var; // 操作は行っていませんが、使用されているとみなされ、借用が有効になります。 var = 2; // `ref_var`上記行以降使用されていないため、借用は終了しています。 // 可変な参照 // 値が可変な借用である間は、一切アクセスできません。 let mut var2 = 4; let ref_var2: &mut i32 = &mut var2; *ref_var2 += 2; // '*'は可変な参照をされた`var2`を指すために使用されます。 println!("{}", *ref_var2); // 6 , // `var2`はコンパイルされません。 // `ref_var2`は型が&mut i32であるため、i32への可変な参照が格納されています。値は入っていません。 // var2 = 2; // `var2`が借用されているため、コンパイルできません。 ref_var2; // 操作は行っていませんが、使用されているとみなされ、借用が有効になります。 } ``` ## 補足資料 Rustにはまだまだ多くの魅力がありますが、ここではRustの基本的な知識をお伝えします。 Rustについてもっと知りたい場合は、[The Rust Programming Language](http://doc.rust-lang.org/book/index.html) を読んで、[/r/rust](http://reddit.com/r/rust)をチェックしてみてください。 irc.mozilla.orgの#rustチャンネルにいる人たちも、新参者にも熱心に助けてくれます。 また、Rustの機能を公式のオンラインコンパイラで試すこともできます。 [Rust Playground](https://play.rust-lang.org) またはメインの [Rust website](http://rust-lang.org). ================================================ FILE: ja/vim.md ================================================ --- contributors: - ["RadhikaG", "https://github.com/RadhikaG"] translators: - ["Kota Kato", "https://github.com/kato-k"] --- [Vim](http://www.vim.org) (Vi IMproved) は、Unix用の人気なエディタである vi のクローンです。 これは、速度と生産性を高めることを目的に設計されたエディタであり、 ほとんどのUnix互換のシステムに組込まれています。 ファイル内の特定の位置に移動したり、素早く編集したりするための多数のキーバインドを持ちます。 `vimtutor`はあなたに`Vim`の使い方を教える素晴しいアプリケーションです。 Vimパッケージのインストール時に一緒に付属しますので、 コマンドラインで「vimtutor」を実行するだけで、このチュートリアルを開けるはずです。 これは、`vim`の全ての主要機能を説明します。 訳注) 日本語で`vimtutor`を利用するには、「vimtutor ja」を実行しなければならない場合があります。 ## 基本のVim操作 ``` vim # をVimで開く :help # についての組み込みドキュメントが存在する場合、 # それを開く :q # Vimを終了する :w # 編集中のファイルを保存する :wq # ファイルを保存して、Vimを終了する ZZ # ファイルを保存して、Vimを終了する。:xと同様 :q! # ファイルを保存せずにVimを終了する # :q を ! *強制的に* 実行するため保存せずにVimが終了します ZQ # ファイルを保存せずにVimを終了する :x # 変更点がある時、ファイルを保存してVimを終了する u # Undo CTRL+R # Redo h # 左に一文字移動 j # 一行下に移動 k # 一行上に移動 l # 右に一文字移動 Ctrl+B # ウィンドウを一画面上に移動 Ctrl+F # ウィンドウを一画面下に移動 Ctrl+D # ウィンドウを半画面上に移動 Ctrl+U # ウィンドウを半画面下に移動 # 行内を移動する 0 # 行頭に移動 $ # 行末に移動 ^ # 行の初めの非空白文字に移動 # テキストの検索 /word # カーソル以降に出現する全ての一致をハイライト ?word # カーソル以前に出現する全ての一致をハイライト n # カーソルを次の一致に移動 N # カーソルを前の一致に移動 :%s/foo/bar/g # 全ての行について「foo」を「bar」に置換 :s/foo/bar/g # 現在の行について「foo」を「bar」に置換 :%s/\n/\r/g # 改行文字の置換 # 文字への移動 f # 前方のに移動する t # 前方のの一文字前に移動する # 例 f< # 前方の < に移動 t< # 前方の < の一文字前に移動 # 単語ごとの移動 w # 一単語前に移動 b # 一単語後ろに移動 e # 現在の単語の後部に移動 # 移動のためのキーバインド gg # ファイルの先頭に移動 G # ファイルの最後に移動 :NUM # ファイルのNUM行に移動(NUMは任意の行数) H # カーソルをウィンドウ上部に移動 M # カーソルをウィンドウ中央に移動 L # カーソルをウィンドウ下部に移動 ``` ## ヘルプドキュメント Vimには`:help `でアクセスできるヘルプドキュメントが組込まれています。 例えば、`:help navigation`はカーソルを移動する方法についてのドキュメントを開きます。 `:help`はオプション無しでも利用できます。 これにより、Vimにより親しみやすくすることを目的としたデフォルトのヘルプダイアログが開かれます。 ## モード Vimは**モード**の概念に基づいています。 - Command Mode - Vimはこのモードで起動し、移動とコマンドの実行に使われます - Insert Mode - ファイルに変更を加えるのに使われます - Visual Mode - テキストをハイライトしてオペレータを適用するために使われます - Ex Mode - コマンドを入力するための「:」プロンプトで使われます ``` i # カーソル位置の前からInsert Modeに入る a # カーソル位置の後ろからInsert Modeに入る v # Visual Modeに入る : # Ex Modeに入る # 現在のモードからコマンドモードに「脱出」 # テキストのコピーと貼り付け y # 選択された対象をヤンクする yy # 現在の行をヤンクする d # 選択された対象を削除する dd # 現在の行を削除する p # ヤンクされたテキストをカーソルの後ろに貼り付ける P # ヤンクされたテキストをのカーソルの前に貼り付ける x # カーソル位置の文字を削除 ``` ## Vimの「文法」 Vimの操作は「動詞・修飾子・名詞」形式のコマンドとして考えることができます。 - 動詞 - 動作 - 修飾子 - 動作の実行方法 - 名詞 - 動作が作用するオブジェクト 「動詞・修飾子・名詞」関するいくつかの重要な例: ``` # '動詞' d # 削除 c # 変更 y # ヤンク (コピー) v # ビジュアル選択 # '修飾子' i # 内部 a # 周り NUM # 回数 (NUMは任意の番号) f # 任意の一文字まで t # 任意の一文字の手前まで / # カーソル以降の任意の文字列まで ? # カーソル以前の任意の文字列まで # '名詞' w # 単語 s # 文 p # 段落 b # ブロック # 「文」の例 d2w # 削除 2 単語 (2単語を削除) cis # 変更 内部 文 (文の内部を変更) yip # ヤンク 内部 段落 (段落の内部をヤンク) ct< # 変更 手前 < (<の手前まで変更) d$ # 削除 行末まで (行末まで削除) ``` ## いくつかのショートカットと小技 ``` > # 選択部を1ブロックインデント < # 選択部を1ブロックデインデント :earlier 15m # ファイルを15分前の状態に戻す :later 15m # 上記のコマンドの逆 ddp # 連続する行を入れ替え . # 前回の動作を繰り返す :w !sudo tee % # 編集中のファイルを管理者として保存 :set syntax=c # 「C言語」のシンタックスハイライトを利用する :sort # 全ての行をソートする :sort! # 全ての行を降順にソートする :sort u # 全ての行をソートして重複を削除する ~ # 選択部分の大文字小文字を入れ替える u # 選択部分を小文字にする U # 選択部分を大文字にする J # 現在の行と次の行を結合する # テキストの折り畳み zf # 選択したテキストを折り畳む zo # 折り畳みを開く zc # 折り畳みを閉じる zR # 全ての折り畳みを開く zM # 全ての折り畳みを閉じる ``` ## マクロ マクロは基本的に記録可能なアクションです。 マクロの記録を開始すると、記録を停止するまで**全て**の操作とコマンドが記録されます。 マクロを呼びだすと、まったく同じ一連の操作とコマンドが文書に再度適用されます。 ``` qa # 「a」という名前のマクロの記録を開始する q # 記録を停止する @a # 「a」マクロを再生する ``` ### ~/.vimrc の設定 ファイル.vimrcは起動時にVimの設定として利用されます 次は~/.vimrcファイルのサンプルです ```vim " Example ~/.vimrc " 2015.10 " Required for vim to be iMproved set nocompatible " 自動インデントなどを利用するために、ファイル名からファイルタイプを決定する filetype indent plugin on " シンタックスハイライトを利用する syntax on " より良いコマンドライン補完 set wildmenu " 大文字を利用しない場合、検索で大文字・小文字を区別しない set ignorecase set smartcase " ファイル固有のインデントが有効でない場合、現在行のインデントを継続する set autoindent " 行番号の表示 set number " インデントに関するオプション " TAB文字の幅 set tabstop=4 " 編集中TABキーを押した際の挙動 set softtabstop=4 " << >> を利用した再インデント時のスペースの数 set shiftwidth=4 " TABキーをスペースに変換する set expandtab " 賢いTAB機能を有効にする set smarttab ``` ### 参考文献 [Vim | Home](http://www.vim.org/index.php) `$ vimtutor` [A vim Tutorial and Primer](https://danielmiessler.com/study/vim/) [What are the dark corners of Vim your mom never told you about? (Stack Overflow thread)](http://stackoverflow.com/questions/726894/what-are-the-dark-corners-of-vim-your-mom-never-told-you-about) [Arch Linux Wiki](https://wiki.archlinux.org/index.php/Vim) ================================================ FILE: ja/yaml.md ================================================ --- contributors: - [Leigh Brenecki, 'https://leigh.net.au'] - [Suhas SG, 'https://github.com/jargnar'] translators: - [haru, 'https://haru52.com/'] --- YAMLはデータのシリアライズ用言語で、 人間が直接読み書きしやすいようにデザインされています。 YAMLはJSONの厳格なスーパーセットで、 改行とインデントが構文的に意味を持つというPythonに似た仕様を追加しています。 しかしPythonとは異なりYAMLではインデントにタブ文字を使うことはできません。 ```yaml --- # ドキュメント開始 # YAMLのコメントはこんな感じです。 ############## # スカラー型 # ############## # (ドキュメント全体を含む)ルートオブジェクトはマップになります。 # これは他言語における辞書型、ハッシュ、オブジェクトなどと等価です。 キー: 値 別のキー: 別の値。 数値: 100 指数表記: 1e+12 # 1 はbooleanでなく数値として解釈されます。 # もしbooleanとして解釈してほしい場合はtrueを使います boolean: true null値: null スペースを 含む キー: 値 # 文字列をクォートで囲う必要がないことに注意してください。 # しかし囲うこともできます。 しかし: 'クォートで囲まれた文字列。' 'キーもクォートで囲えます。': "keyの中で ':' を使いたいときに有用です。" シングルクォート: 'には ''1つの'' エスケープパターンがあります' ダブルクォート: "には多くのエスケープパターンがあります:\", \0, \t, \u263A, \x0d\x0a == \r\n, など、他にもあります。" # UTF-8/16/32文字はエンコードされている必要があります 上付き2: \u00B2 # 複数行の文字列は(| を使う)「リテラルブロック」、 # または、('>' を使う)「折り畳みブロック」として書くことができます リテラルブロック: | この文章のブロック全体が「リテラルブロック」キーの値になり、 改行は保持されます。 リテラルはインデントを解除するまで続き、先頭行のインデント文字数分を 各行のテキストの先頭から取り除きます。 「よりインデントの深い」行はその分のインデントを保持します - この2行はスペース4個分インデントされます。 折り畳みスタイル: > この文章のブロック全体が「折り畳みスタイル」の値になります。 しかしこちらの場合、全ての改行がスペース1個に置き換わります。 直前のような空行は改行文字に変換されます。 「よりインデントの深い」行も改行を保持します - このテキストは2行にわたって表示されます。 ################## # コレクション型 # ################## # 入れ子を表現するにはインデントを使います。 # スペース2個のインデントが好まれます(が必須ではありません)。 入れ子のマップ: キー: 値 別のキー: 別の値 別の入れ子のマップ: こんにちは: こんにちは # マップのキーは文字列である必要はありません。 0.25: 小数のキー # 複数行オブジェクトのような複雑なキーも使用可能です。 # ? の後にスペースを入れることで複雑なキーの開始を宣言できます。 ? | これはキーです 複数行あります : そしてこれがその値です # YAMLではシーケンスを複雑なキー構文で使うこともできます # しかし、言語パーサーによってはエラーになるかもしれません # 例 ? - マンチェスター・ユナイテッド - レアル・マドリード : [2001-01-01, 2002-02-02] # シーケンス(リストや配列と等価)はこんな感じです # ('-' はインデントとしてカウントしてください): シーケンス: - アイテム1 - アイテム2 - 0.5 # シーケンスには異なる型の値を混在させられます - アイテム4 - キー: 値 別のキー: 別の値 - - これはシーケンスです - 別のシーケンス内部 - - - 入れ子のシーケンス表記は - 折り畳めます # YAMLはJSONのスーパーセットなので、 # JSON形式のマップとシーケンスを書くこともできます: jsonマップ: {"キー": "値"} jsonシーケンス: [3, 2, 1, "発進"] クォートは任意: {キー: [3, 2, 1, 発進]} ###################### # その他のYAMLの機能 # ###################### # YAMLには「アンカー」と呼ばれる便利な機能もあります。これによりコンテンツを # ドキュメント内で簡単に複製できます。これらのキーはどちらも同じ値を持ちます: アンカーされたコンテンツ: &anchor_name この文字列は2つのキーの値になります。 他のアンカー: *anchor_name # アンカーは複製/継承プロパティとして使えます ベース: &base 名前: みんな同じ名前を持ちます # 記号 << はマージキー言語非依存型(Merge Key Language-Independent Type) # と呼ばれます。これは指定された1つ以上のマップの全てのキーを現在のマップに # 挿入することを示すために使われます。 foo: <<: *base 年齢: 10 bar: <<: *base 年齢: 20 # fooとbarも「名前: みんな同じ名前を持ちます」を持ちます # YAMLにはタグもあり、明示的に型を宣言できます。 明示的な文字列: !!str 0.5 # 言語特有のタグを実装したパーサーもあり、例えばPythonの複素数型が使えます。 pythonの複素数型: !!python/complex 1+2j # YAMLの複雑なキーでは言語特有のタグも使えます ? !!python/tuple [5, 7] : 五十七 # Python上で {(5, 7): '五十七'} として扱われます #################### # その他のYAMLの型 # #################### # 文字列と数値がYAMLの理解できる唯一のスカラーではありません。 # ISO形式の日付や日時リテラルもパースされます。 日時: 2001-12-15T02:59:43.1Z スペースを含む日時: 2001-12-14 21:59:43.10 -5 日付: 2002-12-14 # !!binaryタグは文字列の実体がバイナリblobのbase64エンコード表現であることを # 示します。 gifファイル: !!binary | R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= # YAMLにはセット型もあり、それはこんな感じです: セット: ? アイテム1 ? アイテム2 ? アイテム3 または: {アイテム1, アイテム2, アイテム3} # セットは値がnullのただのマップで、直前のセットは以下と等価です: セット2: アイテム1: null アイテム2: null アイテム3: null ... # ドキュメント終了 ``` ### 補足資料 + [YAML公式ウェブサイト](https://yaml.org/) + [オンラインYAMLバリデーター](http://www.yamllint.com/) ================================================ FILE: janet.md ================================================ --- name: Janet filename: learnJanet.janet contributors: - ["John Gabriele", "http://www.unexpected-vortices.com/"] --- [Janet](https://janet-lang.org/) is a Lisp-like (Clojure-like), lexically-scoped, dynamically-typed, garbage-collected, C-based, high-level language. The entire language (core library, interpreter, compiler, assembler, PEG) is about 300-500 kB and should run on many constrained systems. I encourage you to try out the code snippets below in the Janet repl (either by [installing Janet](https://janet-lang.org/docs/index.html), or else by using the repl embedded in the Janet homepage). As we only have a scant *y* minutes, we'll survey the basics here and leave the remaining details for the manual. So please, keep your arms and legs inside the vehicle at all times, and on with the scenic tour! ```clojure # A comment. # Some literal values. true false nil # Typical style for symbols (identifiers-for / names-of things). do-stuff pants-on-fire! foo->bar # Evidently for converting foos to bars. fully-charged? _ # Usually used as a dummy variable. # Keywords are like symbols that start with a colon, are treated like # constants, and are typically used as map keys or pieces of syntax in # macros. :a :some-val # Numbers ##################################################################### 5 1e3 # => 1000 1_000 # => 1000 2e-03 # => 0.002 0xff # => 255 # You can specify a radix (base) like so: 16rff # => 255 (same as 0xff) 2r1101 # => 13 # Some numbers in the math library: math/pi # => 3.14159 math/e # => 2.71828 # Strings ##################################################################### "hello" "hey\tthere" # contains a tab # For multi-line strings, use one or more backticks. Backslash-escapes not # recognized in these (bytes will be parsed literally). ``a long multi-line string`` # => "a long\nmulti-line\nstring" # Strings and data structures in Janet come in two varieties: mutable and # immutable. The literal for the mutable variety is written with a `@` in # front of it. # A mutable string (aka "buffer"). @"this" @`a multi-line one here` (string "con" "cat" "enate") # => "concatenate" # To get a substring: (string/slice "abcdefgh" 2 5) # => "cde" # To find a substring: (string/find "de" "abcdefgh") # => 3 # See the string library for more (splitting, replacement, etc.) # Data Structures ############################################################# # Arrays and Tuples # Arrays are mutable, tuples are immutable. # Arrays (mutable) @(4 5 6) @[4 5 6] # Tuples (immutable) # Note that an open paren usually indicates a function call, so if you want a # literal tuple with parens, you need to "quote" it (with a starting single # quote mark)... '(4 5 6) [4 5 6] # ... or just use square brackets. # Tables and Structs (associative data structures) @{:a 1 :b 2 :c 3} # table (mutable) {:a 1 :b 2 :c 3} # struct (immutable) # To "pretty-print" these out, use `pp` instead of `print`. # More about how to work with arrays/tuples and tables/structs below. # Bindings #################################################################### # Bind a value to a symbol. (def x 4.7) # Define a constant, `x`. x # => 4.7 (quote x) # => x (the symbol x) 'x # => x (the symbol x (shorthand)) (print x) # prints 4.7 # Since we used `def`, can't change to what `x` refers: (set x 5.6) # Error, `x` is a constant. (var y 10) (set y 12) # Works, since `y` was defined using `var`. # Note that bindings are local to the scope they're called in. `let` # creates a local scope and makes some bindings all in one shot: (let [a 2 b 3] (print "Hello from inside this local scope.") (* a b)) # => 6 # Destructuring is supported, both for arrays/tuples ... (def a ["foos" "bars" "moos"]) (let [[s1 _ s2] a] (print s1 s2)) # foosmoos # ... and for tables/structs. (def t {:a "ayy" :b "bee" :c "sea"}) (let [{:a a :b b} t] (print a b)) # ayybee # You can even destructure right in a `def`: (def [aa1 aa2] a) aa1 # => foos aa2 # => bars (def {:c body-of-water :b insect-friend} t) body-of-water # => sea insect-friend # => bee # Note that keywords evaluate to themselves, whereas symbols evaluate # to whatever value they're bound to (unless you quote them). # Operators ################################################################### # Janet supports the usual ensemble of operators. # +, -, *, /, and so on. Note: (/ 5 3) # => 1.66667 (% 5 3) # => 2 (remainder) (- 5) # => -5 (or you can just write `-5`) (++ i) # increments (modifies `i`) (-- i) # decrements (+= i 3) # add 3 to `i` (*= i 3) # triple `i` # ... and so on for the other operations on numbers. # If you don't want to mutate `i`, use `(inc i)` and `(dec i)`. # Comparison # = < > not= <= >= (< 2 7 12) # => true # Functions ################################################################### # Call them: (- 5 3) # => 2 (Operators and functions work the same way.) (math/sin (/ math/pi 2)) # => 1 (range 5) # => @[0 1 2 3 4] # Create them: (defn mult-by-2 ``First line of docstring. Some more of the docstring.`` [x] (print "Hi.") (print "Will compute using: " x) (* 2 x)) (print (mult-by-2 6)) # => 12 (after printing "Hi" and so forth) # If you have a function named "main" in your file, `janet` will automatically # call it for you when you run the file. # Interactively read a function's docs from within the repl: (doc mult-by-2) # Note, functions have to be defined before they can be used in a function, # so if you design top-down, you'll need to write your functions from the # bottom of the file up. # You can make anonymous functions as well: (fn [x] (+ x x)) (fn my-func [x] (+ x x)) # This one's less anonymous. # Use `do` to make some side-effecting calls and then evaluate to # the last form in the `do`: (def n (do (print "hi") (do-some-side-effecting 42) 3)) n # => 3 # You might say that function bodies provide an "implicit do". # Operations on data structures ############################################### # (Making all of these mutable so we can ... mutate them.) (def s @"Hello, World!") (def a @[:a :b :c :d :e]) (def t @{:a 1 :b 2}) (length s) # => 13 (length a) # => 5 (length t) # => 2 # Getting values: (s 7) # => 87 (which is the code point for "W") (a 1) # => :b (t :a) # => 1 (keys t) # => @[:a :b] (values t) # => @[1 2] # Changing values (for mutable data structures): (put s 2 87) # @"HeWlo, World!" (put a 2 :x) # @[:a :b :x :d :e] (put t :b 42) # @{:a 1 :b 42} # Adding and removing values (again, for mutable data structures): (buffer/push-string s "??") # @"HeWlo, World!??" (array/push a :f) # @[:a :b :x :d :e :f] (array/pop a) # => :f, and it's also removed from `a`. (put t :x 88) # @{:a 1 :b 42 :x 88} # See the manual for a wide variety of functions for working with # buffers/strings, arrays/tuples, and tables/structs. # Flow control ################################################################ (if some-condition 42 38) # Only `nil` and `false` are falsey. Everything else is truthy. (if got-it? 71) # No false-branch value. Returns `nil` if `got-it?` is falsey. (var i 10) (while (pos? i) (print "... " i) (-- i)) # Now `i` is 0. # `case` compares the dispatch value to each of the options. (var x 2) (case x 1 "won" 2 "too" 3 "tree" "unknown") # => "too" # `cond` evaluates conditions until it gets a `true`. (set x 8) (cond (= x 1) "won" (= x 2) "too" (< x 10) "tree" "oof!") # => "tree" (when (avoided-wipeout?) (do-side-effecty-thing 88) (smell-the-roses) (paint-fencepost-error)) # Pattern matching. # `match` is like a high-powered switch expression. If you switch on a data # structure, it can look inside to try and match on its contents. For example, # matching on a table or struct: (def t {:a 1 :b 2 :c 3}) (match t {:yar v} (print "matches key :yar! " v) {:moo v} (print "matches key :moo! " v) {:c v} (print "matches key :c! " v) _ (print "no match")) # => prints "matches key :c! 3" # Iterating ################################################################### # Iterate over an integer range: (for i 0 5 (print i)) # prints 0, 1, 2, 3, 4 # There's also the more general `loop`: (loop [i :range [0 10] :when (even? i)] (print i)) # Loop over an array/tuple: (def words ["foo" "bar" "baz"]) (each word words (print word)) # Loop over a table/struct: (def t {:a 1 :b 2}) (eachp [k v] t # Loop over each pair in `t`. (print k " --> " v)) # Can also use `eachk` to loop over keys in a table or struct. # Functional programming ###################################################### # You'll find many familiar old friends here. (filter even? (map (fn [x] (* x x)) (range 10))) # => @[0 4 16 36 64] (reduce + 0 (range 5)) # => 10 # ...and lots more (see the API docs). # Errata ###################################################################### (type a) # => the type of `a` (as a keyword) (describe a) # => a human-readable description of `a` (string/format "%j" a) # => Janet values, nicely-formatted ``` This tour didn't cover a number of other features such as modules, fibers, PEGs, macros, etc., but should give you a taste of what Janet is like. See the [Janet manual](https://janet-lang.org/docs/index.html) and the [Janet API docs](https://janet-lang.org/api/index.html) for more info. Also check out [Janet for Mortals](https://janet.guide/) for an in-depth ebook on Janet. ================================================ FILE: java.md ================================================ --- name: Java contributors: - ["Jake Prather", "https://github.com/JakeHP"] - ["Jakukyo Friel", "https://weakish.github.io"] - ["Madison Dickson", "https://github.com/mix3d"] - ["Simon Morgan", "https://sjm.io/"] - ["Zachary Ferguson", "https://github.com/zfergus2"] - ["Cameron Schermerhorn", "https://github.com/cschermerhorn"] - ["Rachel Stiyer", "https://github.com/rstiyer"] - ["Michael Dähnert", "https://github.com/JaXt0r"] - ["Rob Rose", "https://github.com/RobRoseKnows"] - ["Sean Nam", "https://github.com/seannam"] - ["Shawn M. Hanes", "https://github.com/smhanes15"] filename: LearnJava.java --- Java is a general-purpose, concurrent, class-based, object-oriented computer programming language. [Read more here.](https://docs.oracle.com/javase/tutorial/java/) ```java // Single-line comments start with // /* Multi-line comments look like this. */ /** * JavaDoc comments look like this. Used to describe the Class or various * attributes of a Class. * Main attributes: * * @author Name (and contact information such as email) of author(s). * @version Current version of the program. * @since When this part of the program was first added. * @param For describing the different parameters for a method. * @return For describing what the method returns. * @deprecated For showing the code is outdated or shouldn't be used. * @see Links to another part of documentation. */ // Import ArrayList class inside of the java.util package import java.util.ArrayList; // Import all classes inside of java.security package import java.security.*; // Java to illustrate calling of static members and methods without calling classname import static java.lang.Math.*; import static java.lang.System.*; public class LearnJava { // In order to run a java program, it must have a main method as an entry // point. public static void main(String[] args) { /////////////////////////////////////// // Input/Output /////////////////////////////////////// /* * Output */ // Use System.out.println() to print lines. System.out.println("Hello World!"); System.out.println( "Integer: " + 10 + " Double: " + 3.14 + " Boolean: " + true); // To print without a newline, use System.out.print(). System.out.print("Hello "); System.out.print("World"); // Use System.out.printf() for easy formatted printing. System.out.printf("pi = %.5f", Math.PI); // => pi = 3.14159 /* * Input */ // use Scanner to read input // must import java.util.Scanner; Scanner scanner = new Scanner(System.in); // read string input String name = scanner.next(); // read byte input byte numByte = scanner.nextByte(); // read int input int numInt = scanner.nextInt(); // read long input long numLong = scanner.nextLong(); // read float input float numFloat = scanner.nextFloat(); // read double input double numDouble = scanner.nextDouble(); // read boolean input boolean bool = scanner.nextBoolean(); /////////////////////////////////////// // Variables /////////////////////////////////////// /* * Variable Declaration */ // Declare a variable using int fooInt; // Declare multiple variables of the same // type , , int fooInt1, fooInt2, fooInt3; /* * Variable Initialization */ // Initialize a variable using = int barInt = 1; // Initialize multiple variables of same type with same // value , , // = = = int barInt1, barInt2, barInt3; barInt1 = barInt2 = barInt3 = 1; // Shorthand for multiple declarations int barInt4 = 1, barInt5 = 2; /* * Variable types */ // Byte - 8-bit signed two's complement integer // (-128 <= byte <= 127) byte fooByte = 100; // If you would like to interpret a byte as an unsigned integer // then this simple operation can help int unsignedIntLessThan256 = 0xff & fooByte; // this contrasts a cast which can be negative. int signedInt = (int) fooByte; // Short - 16-bit signed two's complement integer // (-32,768 <= short <= 32,767) short fooShort = 10000; // Integer - 32-bit signed two's complement integer // (-2,147,483,648 <= int <= 2,147,483,647) int bazInt = 1; // Long - 64-bit signed two's complement integer // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) long fooLong = 100000L; // L is used to denote that this variable value is of type Long; // anything without is treated as integer by default. // Note: byte, short, int and long are signed. They can have positive and negative values. // There are no unsigned variants. // char, however, is 16-bit unsigned. // Float - Single-precision 32-bit IEEE 754 Floating Point // 2^-149 <= float <= (2-2^-23) * 2^127 float fooFloat = 234.5f; // f or F is used to denote that this variable value is of type float; // otherwise it is treated as double. // Double - Double-precision 64-bit IEEE 754 Floating Point // 2^-1074 <= x <= (2-2^-52) * 2^1023 double fooDouble = 123.4; // Boolean - true & false boolean fooBoolean = true; boolean barBoolean = false; // Char - A single 16-bit Unicode character char fooChar = 'A'; // final variables can't be reassigned, final int HOURS_I_WORK_PER_WEEK = 9001; // but they can be initialized later. final double E; E = 2.71828; // BigInteger - Immutable arbitrary-precision integers // // BigInteger is a data type that allows programmers to manipulate // integers longer than 64-bits. Integers are stored as an array of // bytes and are manipulated using functions built into BigInteger // // BigInteger can be initialized using an array of bytes or a string. BigInteger fooBigInteger = new BigInteger(fooByteArray); // BigDecimal - Immutable, arbitrary-precision signed decimal number // // A BigDecimal takes two parts: an arbitrary precision integer // unscaled value and a 32-bit integer scale // // BigDecimal allows the programmer complete control over decimal // rounding. It is recommended to use BigDecimal with currency values // and where exact decimal precision is required. // // BigDecimal can be initialized with an int, long, double or String // or by initializing the unscaled value (BigInteger) and scale (int). BigDecimal fooBigDecimal = new BigDecimal(fooBigInteger, fooInt); // Be wary of the constructor that takes a float or double as // the inaccuracy of the float/double will be copied in BigDecimal. // Prefer the String constructor when you need an exact value. BigDecimal tenCents = new BigDecimal("0.1"); // Type inference with 'var' var x = 100; // int var y = 1.90; // double var z = 'a'; // char var p = "tanu"; // String var q = false; // boolean // Strings String fooString = "My String Is Here!"; // Text blocks var textBlock = """ This is a in Java """; // \n is an escaped character that starts a new line String barString = "Printing on a new line?\nNo Problem!"; // \t is an escaped character that adds a tab character String bazString = "Do you want to add a tab?\tNo Problem!"; System.out.println(fooString); System.out.println(barString); System.out.println(bazString); // String Building // #1 - with plus operator // That's the basic way to do it (optimized under the hood) String plusConcatenated = "Strings can " + "be concatenated " + "via + operator."; System.out.println(plusConcatenated); // Output: Strings can be concatenated via + operator. // #2 - with StringBuilder // This way doesn't create any intermediate strings. It just stores the string pieces, and ties them together // when toString() is called. // Hint: This class is not thread safe. A thread-safe alternative (with some impact on performance) is StringBuffer. StringBuilder builderConcatenated = new StringBuilder(); builderConcatenated.append("You "); builderConcatenated.append("can use "); builderConcatenated.append("the StringBuilder class."); System.out.println(builderConcatenated.toString()); // only now is the string built // Output: You can use the StringBuilder class. // StringBuilder is efficient when the fully constructed String is not required until the end of some processing. StringBuilder stringBuilder = new StringBuilder(); String inefficientString = ""; for (int i = 0 ; i < 10; i++) { stringBuilder.append(i).append(" "); inefficientString += i + " "; } System.out.println(inefficientString); System.out.println(stringBuilder.toString()); // inefficientString requires a lot more work to produce, as it generates a String on every loop iteration. // Simple concatenation with + is compiled to a StringBuilder and toString() // Avoid string concatenation in loops. // #3 - with String formatter // Another alternative way to create strings. Fast and readable. String.format("%s may prefer %s.", "Or you", "String.format()"); // Output: Or you may prefer String.format(). // Arrays // The array size must be decided upon instantiation // The following formats work for declaring an array // [] = new []; // [] = new []; int[] intArray = new int[10]; String[] stringArray = new String[1]; boolean boolArray[] = new boolean[100]; // Another way to declare & initialize an array int[] y = {9000, 1000, 1337}; String names[] = {"Bob", "John", "Fred", "Juan Pedro"}; boolean bools[] = {true, false, false}; // Indexing an array - Accessing an element System.out.println("intArray @ 0: " + intArray[0]); // Arrays are zero-indexed and mutable. intArray[1] = 1; System.out.println("intArray @ 1: " + intArray[1]); // => 1 // Other data types worth checking out // ArrayLists - Like arrays except more functionality is offered, and // the size is mutable. // LinkedLists - Implementation of doubly-linked list. All of the // operations perform as could be expected for a // doubly-linked list. // Maps - A mapping of key Objects to value Objects. Map is // an interface and therefore cannot be instantiated. // The type of keys and values contained in a Map must // be specified upon instantiation of the implementing // class. Each key may map to only one corresponding value, // and each key may appear only once (no duplicates). // HashMaps - This class uses a hashtable to implement the Map // interface. This allows the execution time of basic // operations, such as get and insert element, to remain // constant-amortized even for large sets. // TreeMap - A Map that is sorted by its keys. Each modification // maintains the sorting defined by either a Comparator // supplied at instantiation, or comparisons of each Object // if they implement the Comparable interface. // Failure of keys to implement Comparable combined with failure to // supply a Comparator will throw ClassCastExceptions. // Insertion and removal operations take O(log(n)) time // so avoid using this data structure unless you are taking // advantage of the sorting. /////////////////////////////////////// // Operators /////////////////////////////////////// System.out.println("\n->Operators"); int i1 = 1, i2 = 2; // Arithmetic is straightforward System.out.println("1+2 = " + (i1 + i2)); // => 3 System.out.println("2-1 = " + (i2 - i1)); // => 1 System.out.println("2*1 = " + (i2 * i1)); // => 2 System.out.println("1/2 = " + (i1 / i2)); // => 0 (int/int returns int) System.out.println("1/2.0 = " + (i1 / (double)i2)); // => 0.5 // Modulo System.out.println("11%3 = " + (11 % 3)); // => 2 // Comparison operators System.out.println("3 == 2? " + (3 == 2)); // => false System.out.println("3 != 2? " + (3 != 2)); // => true System.out.println("3 > 2? " + (3 > 2)); // => true System.out.println("3 < 2? " + (3 < 2)); // => false System.out.println("2 <= 2? " + (2 <= 2)); // => true System.out.println("2 >= 2? " + (2 >= 2)); // => true // Boolean operators System.out.println("3 > 2 && 2 > 3? " + ((3 > 2) && (2 > 3))); // => false System.out.println("3 > 2 || 2 > 3? " + ((3 > 2) || (2 > 3))); // => true System.out.println("!(3 == 2)? " + (!(3 == 2))); // => true // Bitwise operators! /* ~ Unary bitwise complement << Signed left shift >> Signed/Arithmetic right shift >>> Unsigned/Logical right shift & Bitwise AND ^ Bitwise exclusive OR | Bitwise inclusive OR */ // Increment operators int i = 0; System.out.println("\n->Inc/Dec-rementation"); // The ++ and -- operators increment and decrement by 1 respectively. // If they are placed before the variable, they increment then return; // after the variable they return then increment. System.out.println(i++); // i = 1, prints 0 (post-increment) System.out.println(++i); // i = 2, prints 2 (pre-increment) System.out.println(i--); // i = 1, prints 2 (post-decrement) System.out.println(--i); // i = 0, prints 0 (pre-decrement) /////////////////////////////////////// // Control Structures /////////////////////////////////////// System.out.println("\n->Control Structures"); // If statements are c-like int j = 10; if (j == 10) { System.out.println("I get printed"); } else if (j > 10) { System.out.println("I don't"); } else { System.out.println("I also don't"); } // While loop int fooWhile = 0; while (fooWhile < 100) { System.out.println(fooWhile); // Increment the counter // Iterated 100 times, fooWhile 0,1,2...99 fooWhile++; } System.out.println("fooWhile Value: " + fooWhile); // Do While Loop int fooDoWhile = 0; do { System.out.println(fooDoWhile); // Increment the counter // Iterated 100 times, fooDoWhile 0->99 fooDoWhile++; } while (fooDoWhile < 100); System.out.println("fooDoWhile Value: " + fooDoWhile); // For Loop // for loop structure => for(; ; ) for (int fooFor = 0; fooFor < 10; fooFor++) { System.out.println(fooFor); // Iterated 10 times, fooFor 0->9 } System.out.println("fooFor Value: " + fooFor); // Nested For Loop Exit with Label outer: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; // breaks out of outer loop instead of only the inner one } } } // For Each Loop // The for loop is also able to iterate over arrays as well as objects // that implement the Iterable interface. int[] fooList = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // for each loop structure => for ( : ) // reads as: for each element in the iterable // note: the object type must match the element type of the iterable. for (int bar : fooList) { System.out.println(bar); //Iterates 9 times and prints 1-9 on new lines } // Switch Case // A switch works with the byte, short, char, and int data types. // It also works with enumerated types (discussed in Enum Types), the // String class, and a few special classes that wrap primitive types: // Character, Byte, Short, and Integer. // Starting in Java 7 and above, we can also use the String type. // Note: Do remember that, not adding "break" at end any particular case ends up in // executing the very next case(given it satisfies the condition provided) as well. int month = 3; String monthString; switch (month) { case 1: monthString = "January"; break; case 2: monthString = "February"; break; case 3: monthString = "March"; break; default: monthString = "Some other month"; break; } System.out.println("Switch Case Result: " + monthString); // Try-with-resources (Java 7+) // Try-catch-finally statements work as expected in Java but in Java 7+ // the try-with-resources statement is also available. Try-with-resources // simplifies try-catch-finally statements by closing resources // automatically. // In order to use a try-with-resources, include an instance of a class // in the try statement. The class must implement java.lang.AutoCloseable. try (BufferedReader br = new BufferedReader(new FileReader("foo.txt"))) { // You can attempt to do something that could throw an exception. System.out.println(br.readLine()); // In Java 7, the resource will always be closed, even if it throws // an Exception. } catch (IOException | SQLException ex) { // Java 7+ Multi catch block handle both exceptions } catch (Exception ex) { //The resource will be closed before the catch statement executes. System.out.println("readLine() failed."); } // No need for a finally statement in this case, the BufferedReader is // already closed. This can be used to avoid certain edge cases where // a finally statement might not be called. // To learn more: // https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html // Conditional Shorthand // You can use the '?' operator for quick assignments or logic forks. // Reads as "If (statement) is true, use , otherwise, use // " int foo = 5; String bar = (foo < 10) ? "A" : "B"; System.out.println("bar : " + bar); // Prints "bar : A", because the // statement is true. // Or simply System.out.println("bar : " + (foo < 10 ? "A" : "B")); //////////////////////////////////////// // Converting Data Types //////////////////////////////////////// // Converting data // Convert String To Integer Integer.parseInt("123");//returns an integer version of "123" // Convert Integer To String Integer.toString(123);//returns a string version of 123 // For other conversions check out the following classes: // Double // Long // String /////////////////////////////////////// // Classes And Functions /////////////////////////////////////// System.out.println("\n->Classes & Functions"); // (definition of the Bicycle class follows) // Use new to instantiate a class Bicycle trek = new Bicycle(); // Call object methods trek.speedUp(3); // You should always use setter and getter methods trek.setCadence(100); // toString returns this Object's string representation. System.out.println("trek info: " + trek.toString()); } // End main method private static class TestInitialization { // Double Brace Initialization // Before Java 11, the Java Language had no syntax for how to create // static Collections in an easy way. Usually you end up like this: private static final Set COUNTRIES = new HashSet(); static { COUNTRIES.add("DENMARK"); COUNTRIES.add("SWEDEN"); COUNTRIES.add("FINLAND"); } // There's a nifty way to achieve the same thing, // by using something that is called Double Brace Initialization. private static final Set COUNTRIES_DOUBLE_BRACE = new HashSet() {{ add("DENMARK"); add("SWEDEN"); add("FINLAND"); }} // The first brace creates a new AnonymousInnerClass and the second // one declares an instance initializer block. This block is called // when the anonymous inner class is created. // However, this is considered an anti-pattern: it creates a new class // for every instance, increasing memory overhead (Metaspace) // and potentially causing memory leaks by holding an implicit // reference to the enclosing class. Use Set.of() in Java 9+. // Another option was to initialize the Collection from an array, // using Arrays.asList() method: private static final List COUNTRIES_AS_LIST = Arrays.asList("SWEDEN", "DENMARK", "NORWAY"); // This has one catch: the list we get is internally backed by the array, // and since arrays can't change their size, the list backed by the array // is not resizeable, which means we can't add new elements to it: public static void main(String[] args) { COUNTRIES.add("FINLAND"); // throws UnsupportedOperationException! // However, we can replace elements by index, just like in array: COUNTRIES.set(1, "FINLAND"); System.out.println(COUNTRIES); // prints [SWEDEN, FINLAND, NORWAY] } // The resizing problem can be circumvented // by creating another Collection from the List: private static final Set COUNTRIES_SET = new HashSet<>(Arrays.asList("SWEDEN", "DENMARK", "NORWAY")); // It's perfectly fine to add anything to the Set of COUNTRIES now. } // End TestInitialization class private static class TestJava11Initialization { // Since Java 11, there is a convenient option to initialize Collections: // Set.of() and List.of() methods. private static final Set COUNTRIES = Set.of("SWEDEN", "DENMARK", "NORWAY"); // There is a massive catch, though: Lists and Sets initialized like this // 1) are immutable // 2) can't contain null elements (even check for null elements fails)! public static void main(String[] args) { COUNTRIES.add("FINLAND"); // throws UnsupportedOperationException COUNTRIES.remove("NORWAY"); // throws UnsupportedOperationException COUNTRIES.contains(null); // throws NullPointerException } private static final Set COUNTRIES_WITH_NULL = Set.of("SWEDEN", null, "NORWAY"); // throws NullPointerException } // End TestJava11Initialization class } // End LearnJava class // You can include other, non-public outer-level classes in a .java file, // but it is not good practice. Instead split classes into separate files. // Class Declaration Syntax: // class { // // data fields, constructors, functions all inside. // // functions are called as methods in Java. // } class Bicycle { // Bicycle's Fields/Variables public int cadence; // Public: Can be accessed from anywhere private int speed; // Private: Only accessible from within the class protected int gear; // Protected: Accessible from the class and subclasses String name; // default: Only accessible from within this package static String className; // Static class variable // Static block // Java has no implementation of static constructors, but // has a static block that can be used to initialize class variables // (static variables). // This block will be called when the class is loaded. static { className = "Bicycle"; } // Constructors are a way of creating classes // This is a constructor public Bicycle() { // You can also call another constructor: // this(1, 50, 5, "Bontrager"); gear = 1; cadence = 50; speed = 5; name = "Bontrager"; } // This is a constructor that takes arguments public Bicycle(int startCadence, int startSpeed, int startGear, String name) { this.gear = startGear; this.cadence = startCadence; this.speed = startSpeed; this.name = name; } // Method Syntax: // () // Java classes often implement getters and setters for their fields // Method declaration syntax: // () public int getCadence() { return cadence; } // void methods require no return statement public void setCadence(int newValue) { cadence = newValue; } public void setGear(int newValue) { gear = newValue; } public void speedUp(int increment) { speed += increment; } public void slowDown(int decrement) { speed -= decrement; } public void setName(String newName) { name = newName; } public String getName() { return name; } //Method to display the attribute values of this Object. @Override // Inherited from the Object class. public String toString() { return "gear: " + gear + " cadence: " + cadence + " speed: " + speed + " name: " + name; } } // end class Bicycle // PennyFarthing is a subclass of Bicycle class PennyFarthing extends Bicycle { // (Penny Farthings are those bicycles with the big front wheel. // They have no gears.) public PennyFarthing(int startCadence, int startSpeed) { // Call the parent constructor with super super(startCadence, startSpeed, 0, "PennyFarthing"); } // You should mark a method you're overriding with an @annotation. // To learn more about what annotations are and their purpose check this // out: http://docs.oracle.com/javase/tutorial/java/annotations/ @Override public void setGear(int gear) { this.gear = 0; } } // Object casting // Since the PennyFarthing class is extending the Bicycle class, we can say // a PennyFarthing is a Bicycle and write : // Bicycle bicycle = new PennyFarthing(); // This is called object casting where an object is taken for another one. There // are lots of details and deals with some more intermediate concepts here: // https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html // Interfaces // Interface declaration syntax // interface extends { // // Constants // // Method declarations // } // Example - Food: public interface Edible { public void eat(); // Any class that implements this interface, must // implement this method. } public interface Digestible { public void digest(); // Since Java 8, interfaces can have default method. public default void defaultMethod() { System.out.println("Hi from default method ..."); } } // We can now create a class that implements both of these interfaces. public class Fruit implements Edible, Digestible { @Override public void eat() { // ... } @Override public void digest() { // ... } } // In Java, you can extend only one class, but you can implement many // interfaces. For example: public class ExampleClass extends ExampleClassParent implements InterfaceOne, InterfaceTwo { @Override public void InterfaceOneMethod() { } @Override public void InterfaceTwoMethod() { } } // Abstract Classes // Abstract Class declaration syntax // abstract class extends // { // // Constants and variables // // Method declarations // } // Abstract Classes cannot be instantiated. // Abstract classes may define abstract methods. // Abstract methods have no body and are marked abstract // Non-abstract child classes must @Override all abstract methods // from their super-classes. // Abstract classes can be useful when combining repetitive logic // with customised behavior, but as Abstract classes require // inheritance, they violate "Composition over inheritance" // so consider other approaches using composition. // https://en.wikipedia.org/wiki/Composition_over_inheritance public abstract class Animal { private int age; public abstract void makeSound(); // Method can have a body public void eat() { System.out.println("I am an animal and I am Eating."); // Note: We can access private variable here. age = 30; } public void printAge() { System.out.println(age); } // Abstract classes can have main method. public static void main(String[] args) { System.out.println("I am abstract"); } } class Dog extends Animal { // Note still have to override the abstract methods in the // abstract class. @Override public void makeSound() { System.out.println("Bark"); // age = 30; ==> ERROR! age is private to Animal } // NOTE: You will get an error if you used the // @Override annotation here, since java doesn't allow // overriding of static methods. // What is happening here is called METHOD HIDING. // Check out this SO post: http://stackoverflow.com/questions/16313649/ public static void main(String[] args) { Dog pluto = new Dog(); pluto.makeSound(); pluto.eat(); pluto.printAge(); } } // Final Classes // Final Class declaration syntax // final { // // Constants and variables // // Method declarations // } // Final classes are classes that cannot be inherited from and are therefore a // final child. In a way, final classes are the opposite of abstract classes // because abstract classes must be extended, but final classes cannot be // extended. public final class SaberToothedCat extends Animal { // Note still have to override the abstract methods in the // abstract class. @Override public void makeSound() { System.out.println("Roar"); } } // Final Methods public abstract class Mammal() { // Final Method Syntax: // final () // Final methods, like, final classes cannot be overridden by a child // class, and are therefore the final implementation of the method. public final boolean isWarmBlooded() { return true; } } // Java Records are a concise way to define immutable data carrier classes, automatically // generating boilerplate code like constructors, equals(), hashCode()and toString(). // This automatically creates an immutable class Person with fields name and age. public record Person(String name, int age) {} Person p = new Person("Alice", 30); // Enum Type // // An enum type is a special data type that enables for a variable to be a set // of predefined constants. The variable must be equal to one of the values // that have been predefined for it. Because they are constants, the names of // an enum type's fields are in uppercase letters. In the Java programming // language, you define an enum type by using the enum keyword. For example, // you would specify a days-of-the-week enum type as: public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } // We can use our enum Day like that: public class EnumTest { // Variable Enum Day day; public EnumTest(Day day) { this.day = day; } public void tellItLikeItIs() { switch (day) { case MONDAY: System.out.println("Mondays are bad."); break; case FRIDAY: System.out.println("Fridays are better."); break; case SATURDAY: case SUNDAY: System.out.println("Weekends are best."); break; default: System.out.println("Midweek days are so-so."); break; } } public static void main(String[] args) { EnumTest firstDay = new EnumTest(Day.MONDAY); firstDay.tellItLikeItIs(); // => Mondays are bad. EnumTest thirdDay = new EnumTest(Day.WEDNESDAY); thirdDay.tellItLikeItIs(); // => Midweek days are so-so. } } // Enum types are much more powerful than we show above. // The enum body can include methods and other fields. // You can see more at https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html // Getting Started with Lambda Expressions // // New to Java version 8 are lambda expressions. Lambdas are more commonly found // in functional programming languages, which means they are methods which can // be created without belonging to a class, passed around as if it were itself // an object, and executed on demand. // // Final note, lambdas must implement a functional interface. A functional // interface is one which has only a single abstract method declared. It can // have any number of default methods. Lambda expressions can be used as an // instance of that functional interface. Any interface meeting the requirements // is treated as a functional interface. You can read more about interfaces // above. // import java.util.Map; import java.util.HashMap; import java.util.function.*; import java.security.SecureRandom; public class Lambdas { public static void main(String[] args) { // Lambda declaration syntax: // -> // We will use this hashmap in our examples below. Map planets = new HashMap<>(); planets.put("Mercury", "87.969"); planets.put("Venus", "224.7"); planets.put("Earth", "365.2564"); planets.put("Mars", "687"); planets.put("Jupiter", "4,332.59"); planets.put("Saturn", "10,759"); planets.put("Uranus", "30,688.5"); planets.put("Neptune", "60,182"); // Lambda with zero parameters using the Supplier functional interface // from java.util.function.Supplier. The actual lambda expression is // what comes after numPlanets =. Supplier numPlanets = () -> Integer.toString(planets.size()); System.out.format("Number of Planets: %s\n\n", numPlanets.get()); // Lambda with one parameter and using the Consumer functional interface // from java.util.function.Consumer. This is because planets is a Map, // which implements both Collection and Iterable. The forEach used here, // found in Iterable, applies the lambda expression to each member of // the Collection. The default implementation of forEach behaves as if: /* for (T t : this) action.accept(t); */ // The actual lambda expression is the parameter passed to forEach. planets.keySet().forEach((p) -> System.out.format("%s\n", p)); // If you are only passing a single argument, then the above can also be // written as (note absent parentheses around p): planets.keySet().forEach(p -> System.out.format("%s\n", p)); // Tracing the above, we see that planets is a HashMap, keySet() returns // a Set of its keys, forEach applies each element as the lambda // expression of: (parameter p) -> System.out.format("%s\n", p). Each // time, the element is said to be "consumed" and the statement(s) // referred to in the lambda body is applied. Remember the lambda body // is what comes after the ->. // The above without use of lambdas would look more traditionally like: for (String planet : planets.keySet()) { System.out.format("%s\n", planet); } // This example differs from the above in that a different forEach // implementation is used: the forEach found in the HashMap class // implementing the Map interface. This forEach accepts a BiConsumer, // which generically speaking is a fancy way of saying it handles // the Set of each Key -> Value pairs. This default implementation // behaves as if: /* for (Map.Entry entry : map.entrySet()) action.accept(entry.getKey(), entry.getValue()); */ // The actual lambda expression is the parameter passed to forEach. String orbits = "%s orbits the Sun in %s Earth days.\n"; planets.forEach((K, V) -> System.out.format(orbits, K, V)); // The above without use of lambdas would look more traditionally like: for (String planet : planets.keySet()) { System.out.format(orbits, planet, planets.get(planet)); } // Or, if following more closely the specification provided by the // default implementation: for (Map.Entry planet : planets.entrySet()) { System.out.format(orbits, planet.getKey(), planet.getValue()); } // These examples cover only the very basic use of lambdas. It might not // seem like much or even very useful, but remember that a lambda can be // created as an object that can later be passed as parameters to other // methods. } } ``` ## Further Reading The links provided here below are just to get an understanding of the topic, feel free to Google and find specific examples. ### Official Oracle Guides * [Java Tutorial Trail from Sun / Oracle](https://docs.oracle.com/javase/tutorial/index.html) * [Java Access level modifiers](https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html) * [Object-Oriented Programming Concepts](https://docs.oracle.com/javase/tutorial/java/concepts/index.html): * [Inheritance](https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html) * [Polymorphism](https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html) * [Abstraction](https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html) * [Exceptions](https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) * [Interfaces](https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html) * [Generics](https://docs.oracle.com/javase/tutorial/java/generics/index.html) * [Java Code Conventions](https://www.oracle.com/technetwork/java/codeconvtoc-136057.html) * New features in Java 8: * [Lambda expressions (functional programming)](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html) * [Date and time API (java.time package)](http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html) ### Online Practice and Tutorials * [Codingbat.com](http://codingbat.com/java) * [Codewars - Java Katas](https://www.codewars.com/?language=java) * [University of Helsinki - Object-Oriented programming with Java](http://moocfi.github.io/courses/2013/programming-part-1/) ### Books * [Head First Java](http://www.headfirstlabs.com/books/hfjava/) * [Thinking in Java](https://www.amazon.com/Thinking-Java-4th-Bruce-Eckel/dp/0131872486/) * [Objects First with Java](https://www.amazon.com/Objects-First-Java-Practical-Introduction/dp/0132492660) * [Java The Complete Reference](https://www.amazon.com/gp/product/0071606300) ### Real-World Java Ecosystem & Projects To explore Java beyond language fundamentals, here are widely used real-world tools, frameworks, and open-source projects: * [Awesome Java](https://github.com/akullpp/awesome-java) * [Spring Boot Guides](https://spring.io/guides) * [Java Design Patterns](https://github.com/iluwatar/java-design-patterns) * [OpenJFX Official Documentation](https://openjfx.io/openjfx-docs/) ================================================ FILE: javascript.md ================================================ --- name: JavaScript contributors: - ["Leigh Brenecki", "https://leigh.net.au"] - ["Ariel Krakowski", "http://www.learneroo.com"] filename: javascript.js --- JavaScript was created by Netscape's Brendan Eich in 1995. It was originally intended as a simpler scripting language for websites, complementing the use of Java for more complex web applications, but its tight integration with Web pages and built-in support in browsers has caused it to become far more common than Java in web frontends. JavaScript isn't just limited to web browsers, though: Node.js, a project that provides a standalone runtime for Google Chrome's V8 JavaScript engine, is becoming more and more popular. JavaScript has a C-like syntax, so if you've used languages like C or Java, a lot of the basic syntax will already be familiar. Despite this, and despite the similarity in name, JavaScript's object model is significantly different to Java's. ```js // Single-line comments start with two slashes. /* Multiline comments start with slash-star, and end with star-slash */ // Statements can be terminated by ; doStuff(); // ... but they don't have to be, as semicolons are automatically inserted // wherever there's a newline, except in certain cases. doStuff() // Because those cases can cause unexpected results, we'll keep on using // semicolons in this guide. /////////////////////////////////// // 1. Numbers, Strings and Operators // JavaScript has one number type (which is a 64-bit IEEE 754 double). // Doubles have a 52-bit mantissa, which is enough to store integers // up to about 9✕10¹⁵ precisely. 3; // = 3 1.5; // = 1.5 // Some basic arithmetic works as you'd expect. 1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 // Including uneven division. 5 / 2; // = 2.5 // And modulo division. 10 % 2; // = 0 30 % 4; // = 2 18.5 % 7; // = 4.5 // Bitwise operations also work; when you perform a bitwise operation your float // is converted to a signed int *up to* 32 bits. 1 << 2; // = 4 // Precedence is enforced with parentheses. (1 + 3) * 2; // = 8 // There are three special not-a-real-number values: Infinity; // result of e.g. 1/0 -Infinity; // result of e.g. -1/0 NaN; // result of e.g. 0/0, stands for 'Not a Number' // There's also a boolean type. true; false; // Strings are created with ' or ". 'abc'; "Hello, world"; // Negation uses the ! symbol !true; // = false !false; // = true // Equality is === 1 === 1; // = true 2 === 1; // = false // Inequality is !== 1 !== 1; // = false 2 !== 1; // = true // More comparisons 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true // Strings are concatenated with + "Hello " + "world!"; // = "Hello world!" // ... which works with more than just strings "1, 2, " + 3; // = "1, 2, 3" "Hello " + ["world", "!"]; // = "Hello world,!" // ...which can result in some weird behaviour... 13 + !0; // 14 "13" + !0; // '13true' // and are compared with < and > "a" < "b"; // = true // Type coercion is performed for comparisons with double equals... "5" == 5; // = true null == undefined; // = true // ...unless you use === "5" === 5; // = false null === undefined; // = false // You can access characters in a string with `charAt` "This is a string".charAt(0); // = 'T' // ...or use `substring` to get larger pieces. "Hello world".substring(0, 5); // = "Hello" // `length` is a property, so don't use (). "Hello".length; // = 5 // There's also `null` and `undefined`. null; // used to indicate a deliberate non-value undefined; // used to indicate a value is not currently present (although // `undefined` is actually a value itself) // false, null, undefined, NaN, 0 and "" are falsy; everything else is truthy. // Note that 0 is falsy and "0" is truthy, even though 0 == "0". /////////////////////////////////// // 2. Variables, Arrays and Objects // Variables are declared with the `var` keyword. JavaScript is dynamically // typed, so you don't need to specify type. Assignment uses a single `=` // character. var someVar = 5; // If you leave the var keyword off, you won't get an error... someOtherVar = 10; // ...but your variable will be created in the global scope, not in the scope // you defined it in. // Variables declared without being assigned to are set to undefined. var someThirdVar; // = undefined // If you want to declare a couple of variables, then you could use a comma // separator var someFourthVar = 2, someFifthVar = 4; // There's shorthand for performing math operations on variables: someVar += 5; // equivalent to someVar = someVar + 5; someVar is 10 now someVar *= 10; // now someVar is 100 // and an even-shorter-hand for adding or subtracting 1 someVar++; // now someVar is 101 someVar--; // back to 100 // Arrays are ordered lists of values, of any type. var myArray = ["Hello", 45, true]; // Their members can be accessed using the square-brackets subscript syntax. // Array indices start at zero. myArray[1]; // = 45 // Arrays are mutable and of variable length. myArray.push("World"); myArray.length; // = 4 // Add/Modify at specific index myArray[3] = "Hello"; // Add and remove element from front or back end of an array myArray.unshift(3); // Add as the first element someVar = myArray.shift(); // Remove first element and return it myArray.push(3); // Add as the last element someVar = myArray.pop(); // Remove last element and return it // Join all elements of an array with semicolon var myArray0 = [32,false,"js",12,56,90]; myArray0.join(";"); // = "32;false;js;12;56;90" // Get subarray of elements from index 1 (include) to 4 (exclude) myArray0.slice(1,4); // = [false,"js",12] // Remove 4 elements starting from index 2, and insert there strings // "hi","wr" and "ld"; return removed subarray myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] // myArray0 === [32,false,"hi","wr","ld"] // JavaScript's objects are equivalent to "dictionaries" or "maps" in other // languages: an unordered collection of key-value pairs. var myObj = {key1: "Hello", key2: "World"}; // Keys are strings, but quotes aren't required if they're a valid // JavaScript identifier. Values can be any type. var myObj = {myKey: "myValue", "my other key": 4}; // Object attributes can also be accessed using the subscript syntax, myObj["my other key"]; // = 4 // ... or using the dot syntax, provided the key is a valid identifier. myObj.myKey; // = "myValue" // Objects are mutable; values can be changed and new keys added. myObj.myThirdKey = true; // If you try to access a value that's not yet set, you'll get undefined. myObj.myFourthKey; // = undefined /////////////////////////////////// // 3. Logic and Control Structures // The `if` structure works as you'd expect. var count = 1; if (count == 3){ // evaluated if count is 3 } else if (count == 4){ // evaluated if count is 4 } else { // evaluated if it's not either 3 or 4 } // As does `while`. while (true){ // An infinite loop! } // Do-while loops are like while loops, except they always run at least once. var input; do { input = getInput(); } while (!isValid(input)); // The `for` loop is the same as C and Java: // initialization; continue condition; iteration. for (var i = 0; i < 5; i++){ // will run 5 times } // Breaking out of labeled loops is similar to Java outer: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; // breaks out of outer loop instead of only the inner one } } } // The for/in statement allows iteration over properties of an object. var description = ""; var person = {fname:"Paul", lname:"Ken", age:18}; for (var x in person){ description += person[x] + " "; } // description = 'Paul Ken 18 ' // The for/of statement allows iteration over iterable objects (including the built-in String, // Array, e.g. the Array-like arguments or NodeList objects, TypedArray, Map and Set, // and user-defined iterables). var myPets = ""; var pets = ["cat", "dog", "hamster", "hedgehog"]; for (var pet of pets){ myPets += pet + " "; } // myPets = 'cat dog hamster hedgehog ' // && is logical and, || is logical or if (house.size == "big" && house.colour == "blue"){ house.contains = "bear"; } if (colour == "red" || colour == "blue"){ // colour is either red or blue } // && and || "short circuit", which is useful for setting default values. var name = otherName || "default"; // The `switch` statement checks for equality with `===`. // Use 'break' after each case // or the cases after the correct one will be executed too. grade = 'B'; switch (grade) { case 'A': console.log("Great job"); break; case 'B': console.log("OK job"); break; case 'C': console.log("You can do better"); break; default: console.log("Oy vey"); break; } /////////////////////////////////// // 4. Functions, Scope and Closures // JavaScript functions are declared with the `function` keyword. function myFunction(thing){ return thing.toUpperCase(); } myFunction("foo"); // = "FOO" // Note that the value to be returned must start on the same line as the // `return` keyword, otherwise you'll always return `undefined` due to // automatic semicolon insertion. Watch out for this when using Allman style. function myFunction(){ return // <- semicolon automatically inserted here {thisIsAn: 'object literal'}; } myFunction(); // = undefined // JavaScript functions are first class objects, so they can be reassigned to // different variable names and passed to other functions as arguments - for // example, when supplying an event handler: function myFunction(){ // this code will be called in 5 seconds' time } setTimeout(myFunction, 5000); // Note: setTimeout isn't part of the JS language, but is provided by browsers // and Node.js. // Another function provided by browsers is setInterval function myFunction(){ // this code will be called every 5 seconds } setInterval(myFunction, 5000); // Function objects don't even have to be declared with a name - you can write // an anonymous function definition directly into the arguments of another. setTimeout(function(){ // this code will be called in 5 seconds' time }, 5000); // JavaScript has function scope; functions get their own scope but other blocks // do not. if (true){ var i = 5; } i; // = 5 - not undefined as you'd expect in a block-scoped language // This has led to a common pattern of "immediately-executing anonymous // functions", which prevent temporary variables from leaking into the global // scope. (function(){ var temporary = 5; // We can access the global scope by assigning to the "global object", which // in a web browser is always `window`. The global object may have a // different name in non-browser environments such as Node.js. window.permanent = 10; })(); temporary; // raises ReferenceError permanent; // = 10 // One of JavaScript's most powerful features is closures. If a function is // defined inside another function, the inner function has access to all the // outer function's variables, even after the outer function exits. function sayHelloInFiveSeconds(name){ var prompt = "Hello, " + name + "!"; // Inner functions are put in the local scope by default, as if they were // declared with `var`. function inner(){ alert(prompt); } setTimeout(inner, 5000); // setTimeout is asynchronous, so the sayHelloInFiveSeconds function will // exit immediately, and setTimeout will call inner afterwards. However, // because inner is "closed over" sayHelloInFiveSeconds, inner still has // access to the `prompt` variable when it is finally called. } sayHelloInFiveSeconds("Adam"); // will open a popup with "Hello, Adam!" in 5s /////////////////////////////////// // 5. More about Objects; Constructors and Prototypes // Objects can contain functions. var myObj = { myFunc: function(){ return "Hello world!"; } }; myObj.myFunc(); // = "Hello world!" // When functions attached to an object are called, they can access the object // they're attached to using the `this` keyword. myObj = { myString: "Hello world!", myFunc: function(){ return this.myString; } }; myObj.myFunc(); // = "Hello world!" // What `this` is set to has to do with how the function is called, not where // it's defined. So, our function doesn't work if it isn't called in the // context of the object. var myFunc = myObj.myFunc; myFunc(); // = undefined // Inversely, a function can be assigned to the object and gain access to it // through `this`, even if it wasn't attached when it was defined. var myOtherFunc = function(){ return this.myString.toUpperCase(); }; myObj.myOtherFunc = myOtherFunc; myObj.myOtherFunc(); // = "HELLO WORLD!" // We can also specify a context for a function to execute in when we invoke it // using `call` or `apply`. var anotherFunc = function(s){ return this.myString + s; }; anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" // The `apply` function is nearly identical, but takes an array for an argument // list. anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" // This is useful when working with a function that accepts a sequence of // arguments and you want to pass an array. Math.min(42, 6, 27); // = 6 Math.min([42, 6, 27]); // = NaN (uh-oh!) Math.min.apply(Math, [42, 6, 27]); // = 6 // But, `call` and `apply` are only temporary. When we want it to stick, we can // use `bind`. var boundFunc = anotherFunc.bind(myObj); boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" // `bind` can also be used to partially apply (curry) a function. var product = function(a, b){ return a * b; }; var doubler = product.bind(this, 2); doubler(8); // = 16 // When you call a function with the `new` keyword, a new object is created, and // made available to the function via the `this` keyword. Functions designed to be // called like that are called constructors. var MyConstructor = function(){ this.myNumber = 5; }; myNewObj = new MyConstructor(); // = {myNumber: 5} myNewObj.myNumber; // = 5 // Unlike most other popular object-oriented languages, JavaScript has no // concept of 'instances' created from 'class' blueprints; instead, JavaScript // combines instantiation and inheritance into a single concept: a 'prototype'. // Every JavaScript object has a 'prototype'. When you go to access a property // on an object that doesn't exist on the actual object, the interpreter will // look at its prototype. // Some JS implementations let you access an object's prototype on the magic // property `__proto__`. While this is useful for explaining prototypes it's not // part of the standard; we'll get to standard ways of using prototypes later. var myObj = { myString: "Hello world!" }; var myPrototype = { meaningOfLife: 42, myFunc: function(){ return this.myString.toLowerCase(); } }; myObj.__proto__ = myPrototype; myObj.meaningOfLife; // = 42 // This works for functions, too. myObj.myFunc(); // = "hello world!" // Of course, if your property isn't on your prototype, the prototype's // prototype is searched, and so on. myPrototype.__proto__ = { myBoolean: true }; myObj.myBoolean; // = true // There's no copying involved here; each object stores a reference to its // prototype. This means we can alter the prototype and our changes will be // reflected everywhere. myPrototype.meaningOfLife = 43; myObj.meaningOfLife; // = 43 // The for/in statement allows iteration over properties of an object, // walking up the prototype chain until it sees a null prototype. for (var x in myObj){ console.log(myObj[x]); } ///prints: // Hello world! // 43 // [Function: myFunc] // true // To only consider properties attached to the object itself // and not its prototypes, use the `hasOwnProperty()` check. for (var x in myObj){ if (myObj.hasOwnProperty(x)){ console.log(myObj[x]); } } ///prints: // Hello world! // We mentioned that `__proto__` was non-standard, and there's no standard way to // change the prototype of an existing object. However, there are two ways to // create a new object with a given prototype. // The first is Object.create, which is a recent addition to JS, and therefore // not available in all implementations yet. var myObj = Object.create(myPrototype); myObj.meaningOfLife; // = 43 // The second way, which works anywhere, has to do with constructors. // Constructors have a property called prototype. This is *not* the prototype of // the constructor function itself; instead, it's the prototype that new objects // are given when they're created with that constructor and the new keyword. MyConstructor.prototype = { myNumber: 5, getMyNumber: function(){ return this.myNumber; } }; var myNewObj2 = new MyConstructor(); myNewObj2.getMyNumber(); // = 5 myNewObj2.myNumber = 6; myNewObj2.getMyNumber(); // = 6 // Built-in types like strings and numbers also have constructors that create // equivalent wrapper objects. var myNumber = 12; var myNumberObj = new Number(12); myNumber == myNumberObj; // = true // Except, they aren't exactly equivalent. typeof myNumber; // = 'number' typeof myNumberObj; // = 'object' myNumber === myNumberObj; // = false if (0){ // This code won't execute, because 0 is falsy. } if (new Number(0)){ // This code will execute, because wrapped numbers are objects, and objects // are always truthy. } // However, the wrapper objects and the regular builtins share a prototype, so // you can actually add functionality to a string, for instance. String.prototype.firstCharacter = function(){ return this.charAt(0); }; "abc".firstCharacter(); // = "a" // This fact is often used in "polyfilling", which is implementing newer // features of JavaScript in an older subset of JavaScript, so that they can be // used in older environments such as outdated browsers. // For instance, we mentioned that Object.create isn't yet available in all // implementations, but we can still use it with this polyfill: if (Object.create === undefined){ // don't overwrite it if it exists Object.create = function(proto){ // make a temporary constructor with the right prototype var Constructor = function(){}; Constructor.prototype = proto; // then use it to create a new, appropriately-prototyped object return new Constructor(); }; } // ES6 Additions // The "let" keyword allows you to define variables in a lexical scope, // as opposed to a function scope like the var keyword does. let name = "Billy"; // Variables defined with let can be reassigned new values. name = "William"; // The "const" keyword allows you to define a variable in a lexical scope // like with let, but you cannot reassign the value once one has been assigned. const pi = 3.14; pi = 4.13; // You cannot do this. // There is a new syntax for functions in ES6 known as "lambda syntax". // This allows functions to be defined in a lexical scope like with variables // defined by const and let. const isEven = (number) => { return number % 2 === 0; }; isEven(7); // false // The "equivalent" of this function in the traditional syntax would look like this: function isEven(number) { return number % 2 === 0; }; // I put the word "equivalent" in double quotes because a function defined // using the lambda syntax cannot be called before the definition. // The following is an example of invalid usage: add(1, 8); const add = (firstNumber, secondNumber) => { return firstNumber + secondNumber; }; ``` ## Further Reading The [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/JavaScript) (MDN) provides excellent documentation for JavaScript as it's used in browsers. MDN's [A re-introduction to JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) covers much of the concepts covered here in more detail. This guide has quite deliberately only covered the JavaScript language itself; if you want to learn more about how to use JavaScript in web pages, start by learning about the [Document Object Model](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core). [JavaScript Garden](https://shamansir.github.io/JavaScript-Garden/) is an in-depth guide of all the counter-intuitive parts of the language. [JavaScript: The Definitive Guide](https://www.amazon.com/gp/product/0596805527/) is a classic guide and reference book. [Eloquent JavaScript](https://eloquentjavascript.net/) by Marijn Haverbeke is an excellent JS book/ebook with attached terminal [javascript.info](https://javascript.info/) is a modern JavaScript tutorial covering the basics (core language and working with a browser) as well as advanced topics with concise explanations. ================================================ FILE: jinja.md ================================================ --- name: Jinja contributors: - ["Adaías Magdiel", "https://github.com/AdaiasMagdiel"] filename: learn-jinja.j2 --- ## Getting Started with Jinja Jinja is a fast, expressive, and extensible templating engine for Python applications. Jinja includes a lot of functionalities, such as: - Template inheritance and inclusion; - Defining and importing macros within templates; - Security mechanisms to prevent XSS attacks; - A sandboxed environment that can safely render untrusted templates; - Extensible filters, tests, functions, and even syntax. A Jinja template is simply a text file. Jinja doesn't require a specific extension, but it's common to use `.j2` or `.jinja` to make it easier for some IDEs. There are a few kinds of delimiters. The default Jinja delimiters are configured as follows: - `{% ... %}` for Statements - `{{ ... }}` for Expressions to print to the template output - `{# ... #}` for Comments not included in the template output ```jinja {# This is an example of a comment. #} {# You can use this syntax to write multiline comments as well. #} ``` ## VARIABLES ```jinja {# You have the option to access variables from the context passed to the template #} {{ foo }} {# Additionally, you can use a dot (.) to access attributes of a variable or use Python syntax, using [] #} {{ foo.bar }} {{ foo['bar'] }} {# Within the template, you can define variables as well #} {% set name = "Magdiel" %} {{ name }} ``` ## Loops ```html

Members

    {% for user in users %}
  • {{ user.username }}
  • {% endfor %}
{% for key, value in my_dict.items() %}

{{ key }}

-

{{ value }}

{% endfor %}
{% for idx, url in enumerate(urls) %} Go to url {{ idx + 1 }} {% endfor %}
``` ## Conditionals The if statement in Jinja is similar to the if statement in Python. It is commonly used to check if a variable is defined, not empty, and not false in its most basic form. ```html {% if users %}
    {% for user in users %}
  • {{ user.username }}
  • {% endfor %}
{% endif %} {# For multiple branches, elif and else can be used like in Python. #} {% if message.status == "error" %}

{{ message.content }}

{% elif message.status == "success" %}

{{ message.content }}

{% else %}

{{ message.content }}

{% endif %} ``` ## Template Inheritance One of the most powerful features of Jinja is template inheritance. You can create a base layout with predefined blocks that you can extend in another file and override with your own content. ```html {# file: base.html.j2 #} {% block head %} {% block title %}{% endblock title %} - Learning Jinja {% endblock head %}
{% block content %}{% endblock %} {# the endblock tag doesn't need the name of the block #}
{# file: child.html.j2 #} {% extends "base.html.j2" %} {% block head %} {{ super() }} {% endblock %} {% block title %}Home{% endblock %} {% block content %}

Index

Welcome to my home homepage.

{% endblock %} {# RESULT #} Home - Learning Jinja

Index

Welcome to my home homepage.

``` ### Including Content You can include content from another template on your current template using the `{% include "template/path" %}` tag. ```html {# file: footer.html.j2 #}

© 2024 - John Doe

{# file: index.html.j2 #} ...

Hi! I'm John Doe!

{% include "footer.html.j2" %} ... {# RESULT #} ...

Hi! I'm John Doe!

© 2024 - John Doe

... ``` Variables passed to the main template can also be used in the include, as the included template has access to the context of the main template. ```html {# file: greetings.html.j2 #}

I'm the {{ name }} and i like to {{ hobby }}.

{# file: index.html.j2 #} {% set name = "Captain Nemo" %} {% set hobby = "navigate through the depths of the ocean" %}
{% include "greetings.html.j2" %}
{# RESULT #}

I'm the Captain Nemo and i like to navigate through the depths of the ocean.

``` ## Macros Macros are basically like functions in another languages. You can define macros with or without arguments and reuse them in various parts of your template. ```html {% macro input(value="", type="text", placeholder="") -%} {%- endmacro %}

{{ input(placeholder="Your username") }}

{{ input(type="password") }}

``` ## Official Documentation To learn more, access the [official documentation](https://jinja.palletsprojects.com/en/). ================================================ FILE: jq.md ================================================ --- category: tool name: jq contributors: - ["Jack Kuan", "https://github.com/kjkuan"] - ["Azeem Sajid", "https://github.com/iamazeem"] filename: learnjq.sh --- `jq` is a tool for transforming JSON inputs and generating JSON outputs. As a programming language, jq supports boolean and arithmetic expressions, object and array indexing; it has conditionals, functions, and even exception handling... etc. Knowing jq enables you to easily write small programs that can perform complex queries on JSON documents to find answers, make reports, or to produce another JSON document for further processing by other programs. > **NOTE**: This guide demonstrates the use of jq from the command line, > specifically, under an environment running the Bash shell. ```bash # When running jq from the command line, jq program code can be specified as the # first argument after any options to `jq`. We often quote such jq program with # single quotes (`'`) to prevent any special interpretation from the command line # shell. # jq -n '# Comments start with # until the end of line. # The -n option sets the input to the value, `null`, and prevents `jq` # from reading inputs from external sources. ' # Output: # null # By default jq reads from *STDIN* a stream of JSON inputs (values). It # processes each input with the jq program (filters) specified at the command # line, and prints the outputs of processing each input with the program to # *STDOUT*. # echo ' "hello" 123 [ "one", "two", "three" ] { "name": "jq" } ' | jq '. # <-- the jq program here is the single dot (.), called the identity # operator, which stands for the current input. ' # Output: # "hello" # 123 # [ # "one", # "two", # "three" # ] # { # "name": "jq" # } # Notice that jq pretty-prints the outputs by default, therefore, piping # to `jq` is a simple way to format a response from some REST API endpoint # that returns JSON. E.g., `curl -s https://freegeoip.app/json/ | jq` # Instead of processing each JSON input with a jq program, you can also # ask jq to slurp them up as an array. # echo '1 "two" 3' | jq -s . # Output: # [ # 1, # "two", # 3 # ] # Or, treat each line as a string. # (echo line 1; echo line 2) | jq -R . # Output: # "line 1" # "line 2" # Or, combine -s and -R to slurp the input lines into a single string. # (echo line 1; echo line 2) | jq -sR . # Output: # "line 1\nline2\n" # Inputs can also come from a JSON file specified at the command line: # echo '"hello"' > hello.json jq . hello.json # Output: # "hello" # Passing a value into a jq program can be done with the `--arg` option. # Below, `val` is the variable name to bind the value, `123`, to. # The variable is then referenced as `$val`. # jq -n --arg val 123 '$val' # $val is the string "123" here # Output: # "123" # If you need to pass a JSON value, use `--argjson` # jq -n --argjson val 123 '$val' # $val is a number # Output: # 123 # Using `--arg` or `--argjson` is an useful way of building JSON output from # existing input. # jq --arg text "$(date; echo "Have a nice day!")" -n '{ "today": $text }' # Output: # { # "today": "Sun Apr 10 09:53:07 PM EDT 2022\nHave a nice day!" # } # Instead of outputting values as JSON, you can use the `-r` option to print # string values unquoted / unescaped. Non-string values are still printed as # JSON. # echo '"hello" 2 [1, "two", null] {}' | jq -r . # Output: # hello # 2 # [ # 1, # "two", # null # ] # {} # Inside a string in jq, `\(expr)` can be used to substitute the output of # `expr` into the surrounding string context. # jq -rn '"1 + 2 = \(1+2)"' # Output: # 1 + 2 = 3 # The `-r` option is most useful for generating text outputs to be processed # down in a shell pipeline, especially when combined with an interpolated # string that is prefixed the `@sh` prefix operator. # # The `@sh` operator escapes the outputs of `\(...)` inside a string with # single quotes so that each resulting string of `\(...)` can be evaluated # by the shell as a single word / token / argument without special # interpretations. # env_vars=$( echo '{"var1": "value one", "var2": "value\ntwo"}' \ | jq -r ' "export " + @sh "var1=\(.var1) var2=\(.var2)" # ^^^^^^^^ ^^^^^^^^ # "'value one'" "'value\ntwo'" # # NOTE: The + (plus) operator here concatenates strings. ' ) echo "$env_vars" eval "$env_vars" declare -p var1 var2 # Output: # export var1='value one' var2='value # two' # declare -- var1="value one" # declare -- var2="value # two" # There are other string `@prefix` operators (e.g., @base64, @uri, @csv, ...) # that might be useful to you. See `man jq` for details. # The comma (`,`) operator in jq evaluates each operand and generates multiple # outputs: # jq -n '"one", 2, ["three"], {"four": 4}' # Output: # "one" # 2 # [ # "three" # ] # { # "four": 4 # } # Any JSON value is a valid jq expression that evaluates to the JSON value # itself. # jq -n '1, "one", [1, 2], {"one": 1}, null, true, false' # Output: # 1 # "one" # [ # 1, # 2 # ] # { # "one": 1 # } # null # true # false # Any jq expression can be used where a JSON value is expected, even as object # keys. (though parenthesis might be required for object keys or values) # jq -n '[2*3, 8-1, 16/2], {("tw" + "o"): (1 + 1)}' # Output: # [ # 6, # 7, # 8 # ] # { # "two": 2 # } # As a shortcut, if a JSON object key looks like a valid identifier (matching # the regex `^[a-zA-Z_][a-zA-Z_0-9]*$`), quotes can be omitted. # jq -n '{ key_1: "value1" }' # If a JSON object's key's value is omitted, it is looked up in the current # input using the key: (see next example for the meaning of `... | ...`) # jq -n '{c: 3} | {a: 1, "b", c}' # Output: # { # "a": 1, # "b": null, # "c": 3 # } # jq programs are more commonly written as a series of expressions (filters) # connected by the pipe (`|`) operator, which makes the output of its left # filter the input to its right filter. # jq -n '1 | . + 2 | . + 3' # first dot is 1; second dot is 3 # Output: # 6 # If an expression evaluates to multiple outputs, then jq will iterate through # them and propagate each output down the pipeline, and generate multiple # outputs in the end. # jq -n '1, 2, 3 | ., 4 | .' # Output: # 1 # 4 # 2 # 4 # 3 # 4 # The flows of the data in the last example can be visualized like this: # (number prefixed with `*` indicates the current output) # # *1, 2, 3 | *1, 4 | *1 # 1, 2, 3 | 1, *4 | *4 # 1, *2, 3 | *2, 4 | *2 # 1, 2, 3 | 2, *4 | *4 # 1, 2, *3 | *3, 4 | *3 # 1, 2, 3 | 3, *4 | *4 # # # To put it another way, the evaluation of the above example is very similar # to the following pieces of code in other programming languages: # # In Python: # # for first_dot in 1, 2, 3: # for second_dot in first_dot, 4: # print(second_dot) # # In Ruby: # # [1, 2, 3].each do |dot| # [dot, 4].each { |dot| puts dot } # end # # In JavaScript: # # [1, 2, 3].forEach(dot => { # [dot, 4].forEach(dot => console.log(dot)) # }) # # Below are some examples of array index and object attribute lookups using # the `[expr]` operator after an expression. If `expr` is a number then it's # an array index lookup; otherwise, it should be a string, in which case it's # an object attribute lookup: # Array index lookup # jq -n '[2, {"four": 4}, 6][1 - 1]' # => 2 jq -n '[2, {"four": 4}, 6][0]' # => 2 jq -n '[2, {"four": 4}, 6] | .[0]' # => 2 # You can chain the lookups since they are just expressions. # jq -n '[2, {"four": 4}, 6][1]["fo" + "ur"]' # => 4 # For object attributes, you can also use the `.key` shortcut. # jq -n '[2, {"four": 4}, 6][1].four' # => 4 # Use `."key"` if the key is not a valid identifier. # jq -n '[2, {"f o u r": 4}, 6][1]."f o u r"' # => 4 # Array index lookup returns null if the index is not found. # jq -n '[2, {"four": 4}, 6][99]' # => null # Object attribute lookup returns null if the key is not found. # jq -n '[2, {"four": 4}, 6][1].whatever' # => null # The alternative operator `//` can be used to provide a default # value when the result of the left operand is either `null` or `false`. # jq -n '.unknown_key // 7' # => 7 # If the thing before the lookup operator (`[expr]`) is neither an array # or an object, then you will get an error: # jq -n '123 | .[0]' # => jq: error (at ): Cannot index number with number jq -n '"abc" | .name' # => jq: error (at ): Cannot index string with string "name" jq -n '{"a": 97} | .[0]' # => jq: error (at ): Cannot index object with number jq -n '[89, 64] | .["key"]' # => jq: error (at ): Cannot index array with string "key" # You can, however, append a `?` to a lookup to make jq return `empty` # instead when such error happens. # jq -n '123 | .[0]?' # no output since it's empty. jq -n '"abc" | .name?' # no output since it's empty. # The alternative operator (`//`) also works with `empty`: # jq -n '123 | .[0]? // 99' # => 99 jq -n '"abc" | .name? // "unknown"' # => "unknown" # NOTE: `empty` is actually a built-in function in jq. # With the nested loop explanation we illustrated earlier before, # `empty` is like the `continue` or the `next` keyword that skips # the current iteration of the loop in some programming languages. # Strings and arrays can be sliced with the same syntax (`[i:j]`, but no # stepping) and semantic as found in the Python programming language: # # 0 1 2 3 4 5 ... infinite # array = ["a", "b", "c", "d"] # -infinite ... -4 -3 -2 -1 # jq -n '["Peter", "Jerry"][1]' # => "Jerry" jq -n '["Peter", "Jerry"][-1]' # => "Jerry" jq -n '["Peter", "Jerry", "Tom"][1:]' # => ["Jerry", "Tom"] jq -n '["Peter", "Jerry", "Tom"][:1+1]' # => ["Peter", "Jerry"] jq -n '["Peter", "Jerry", "Tom"][1:99]' # => ["Jerry", "Tom"] # If the lookup index or key is omitted then jq iterates through # the collection, generating one output value from each iteration. # # These examples produce the same outputs. # echo 1 2 3 | jq . jq -n '1, 2, 3' jq -n '[1, 2, 3][]' jq -n '{a: 1, b: 2, c: 3}[]' # Output: # 1 # 2 # 3 # You can build an array out of multiple outputs. # jq -n '{values: [{a: 1, b: 2, c: 3}[] | . * 2]}' # Output: # { # "values": [ # 2, # 4, # 6 # ] # } # If multiple outputs are not contained, then we'd get multiple outputs # in the end. # jq -n '{values: ({a: 1, b: 2, c: 3}[] | . * 2)}' # Output: # { # "values": 2 # } # { # "values": 4 # } # { # "values": 6 # } # Conditional `if ... then ... else ... end` in jq is an expression, so # both the `then` part and the `else` part are required. In jq, only # two values, `null` and `false`, are false; all other values are true. # jq -n 'if 1 > 2 | not and 1 <= 2 then "Makes sense" else "WAT?!" end' # Output # "Makes sense" # Notice that `not` is a built-in function that takes zero arguments, # that's why it's used as a filter to negate its input value. # We'll talk about functions soon. # Another example using a conditional: # jq -n '1, 2, 3, 4, 5 | if . % 2 != 0 then . else empty end' # Output # 1 # 3 # 5 # The `empty` above is a built-in function that takes 0 arguments and # generates no outputs. Let's see more examples of built-in functions. # The above conditional example can be written using the `select/1` built-in # function (`/1` indicates the number of arguments expected by the function). # jq -n '1, 2, 3, 4, 5 | select(. % 2 != 0)' # NOTE: % gives the remainder. # Output # 1 # 3 # 5 # Function arguments in jq are passed with call-by-name semantic, which # means, an argument is not evaluated at call site, but instead, is # treated as a lambda expression with the calling context of the call # site as its scope for variable and function references used in the # expression. # # In the above example, the expression `. % 2 != 0` is what's passed to # `select/1` as the argument, not `true` or `false`, which is what would # have been the case had the (boolean) expression was evaluated before it's # passed to the function. # The `range/1`, `range/2`, and `range/3` built-in functions generate # integers within a given range. # jq -n '[range(3)]' # => [0, 1, 2] jq -n '[range(0; 4)]' # => [0, 1, 2, 3] jq -n '[range(2; 10; 2)]' # => [2, 4, 6, 8] # Notice that `;` (semicolon) is used to separate function arguments. # The `map/1` function applies a given expression to each element of # the current input (array) and outputs a new array. # jq -n '[range(1; 6) | select(. % 2 != 0)] | map(. * 2)' # Output: # [ # 2, # 6, # 10 # ] # Without using `select/1` and `map/1`, we could have also written the # above example like this: # jq -n '[range(1; 6) | if . % 2 != 0 then . else empty end | . * 2]' # `keys/0` returns an array of keys of the current input. For an object, # these are the object's attribute names; for an array, these are the # array indices. # jq -n '[range(2; 10; 2)] | keys' # => [0, 1, 2, 3] jq -n '{a: 1, b: 2, c: 3} | keys' # => ["a", "b", "c"] # `values/0` returns an array of values of the current input. For an object, # these are the object's attribute values; for an array, these are the # elements of the array. # jq -n '[range(2; 10; 2)] | values' # => [2, 4, 6, 8] jq -n '{a: 1, b: 2, c: 3} | values' # => [1, 2, 3] # `to_entries/0` returns an array of key-value objects of the current input # object. # jq -n '{a: 1, b: 2, c: 3} | to_entries' # Output: # [ # { # "key": "a", # "value": 1 # }, # { # "key": "b", # "value": 2 # }, # { # "key": "c", # "value": 3 # } # ] # Here's how you can turn an object's attribute into environment variables # using what we have learned so far. # env_vars=$( jq -rn '{var1: "1 2 3 4", var2: "line1\nline2\n"} | to_entries[] | "export " + @sh "\(.key)=\(.value)" ' ) eval "$env_vars" declare -p var1 var2 # Output: # declare -x var1="1 2 3 4" # declare -x var2="line1 # line2 # " # `from_entries/0` is the opposite of `to_entries/0` in that it takes an # an array of key-value objects and turn that into an object with keys # and values from the `key` and `value` attributes of the objects. # # It's useful together with `to_entries/0` when you need to iterate and # do something to each attribute of an object. # jq -n '{a: 1, b: 2, c: 3} | to_entries | map(.value *= 2) | from_entries' # Output: # { # "a": 2, # "b": 4, # "c": 6 # } # The example above can be further shortened with the `with_entries/1` built-in: # jq -n '{a: 1, b: 2, c: 3} | with_entries(.value *= 2)' # The `group_by/1` generates an array of groups (arrays) from the current # input (array). The classification is done by applying the expression argument # to each member of the input array. # # Let's look at a contrived example (Note that `tostring`, `tonumber`, # `length` and `max` are all built-in jq functions. Feel free to look # them up in the jq manual): # # Generate some random numbers. numbers=$(echo $RANDOM{,,,,,,,,,,,,,,,,,,,,}) # # Feed the numbers to jq, classifying them into groups and calculating their # averages, and finally generate a report. # echo $numbers | jq -rs ' # Slurp the numbers into an array. [ [ map(tostring) # Turn it into an array of strings. | group_by(.[0:1]) # Group the numbers by their first digits. | .[] # Iterate through the array of arrays (groups). | map(tonumber) # Turn each group back to an array of numbers. ] # Finally, contain all groups in an array. | sort_by([length, max]) # Sort the groups by their sizes. # If two groups have the same size then the one with the largest # number wins (is bigger). | to_entries[] # Enumerate the array, generating key-value objects. | # For each object, generate two lines: "Group \(.key): \(.value | sort | join(" "))" + "\n" + "Average: \( .value | (add / length) )" ] # Contain the group+average lines in an array. # Join the array elements by separator lines (dashes) to produce the report. | join("\n" + "-"*78 + "\n") ' # Output: # # Group 0: 3267 # Average: 3267 # ------------------------------------------------------------------------------ # Group 1: 7854 # Average: 7854 # ------------------------------------------------------------------------------ # Group 2: 4415 4447 # Average: 4431 # ------------------------------------------------------------------------------ # Group 3: 681 6426 # Average: 3553.5 # ------------------------------------------------------------------------------ # Group 4: 21263 21361 21801 21832 22947 23523 29174 # Average: 23128.714285714286 # ------------------------------------------------------------------------------ # Group 5: 10373 12698 13132 13924 17444 17963 18934 18979 # Average: 15430.875 # The `add/1` built-in "reduces" an array of values to a single value. # You can think of it as sticking the `+` operator in between each value of # the collection. Here are some examples: # jq -n '[1, 2, 3, 4, 5] | add' # => 15 jq -n '["a", "b", "c"] | add' # => "abc" # `+` concatenates arrays jq -n '[["a"], ["b"], ["c"]] | add' # Output: # [ # "a", # "b", # "c" # ] # `+` merges objects non-recursively. jq -n '[{a: 1, b: {c: 3}}, {b: 2, c: 4}] | add' # Output: # { # "a": 1, # "b": 2, # "c": 4 # } # jq provides a special syntax for writing an expression that reduces # the outputs generated by a given expression to a single value. # It has this form: # # reduce outputs_expr as $var (initial_value; reduction_expr) # # Examples: # jq -n 'reduce range(1; 6) as $i (0; . + $i)' # => 15 jq -n 'reduce (1, 2, 3, 4, 5) as $i (0; . + $i)' # => 15 jq -n '[1, 2, 3, 4, 5] | reduce .[] as $i (0; . + $i)' # => 15 jq -n '["a", "b", "c"] | reduce .[] as $i (""; . + $i)' # => "abc" # Notice the `.` in the `reduction_expr` is the `initial_value` at first, # and then it becomes the result of applying the `reduction_expr` as # we iterate through the values of `outputs_expr`. The expression: # # reduce (1, 2, 3, 4, 5) as $i (0; . + $i) # # can be thought of as doing: # # 0 + 1 | . + 2 | . + 3 | . + 4 | . + 5 # # The `*` operator when used on two objects, merges both recursively. # Therefore, to merge JSON objects recursively, you can use `reduce` # with the `*` operator. For example: # echo ' {"a": 1, "b": {"c": 3}} { "b": {"d": 4}} {"a": 99, "e": 5 } ' | jq -s 'reduce .[] as $m ({}; . * $m)' # Output: # { # "a": 99, # "b": { # "c": 3, # "d": 4 # }, # "e": 5 # } # jq has variable assignment in the form of `expr as $var`, which binds # the value of `expr` to `$var`, and `$var` is immutable. Further more, # `... as ...` doesn't change the input of the next filter; its introduction # in a filter pipeline is only for establishing the binding of a value to a # variable, and its scope extends to the filters following its definition. # (i.e., to look up a variable's definition, scan to the left of the filter # chain from the expression using it until you find the definition) # jq -rn '[1, 2, 3, 4, 5] | (.[0] + .[-1]) as $sum # Always put ( ) around the binding `expr` to avoid surprises. | ($sum * length / 2) as $result # The current input at this step is still the initial array. | "The result is: \($result)" # Same. ' # Output: # The result is: 15 # With the `expr as $var` form, if multiple values are generated by `expr` # then jq will iterate through them and bind each value to `$var` in turn # for the rest of the pipeline. # jq -rn 'range(2; 4) as $i | range(1; 6) as $j | "\($i) * \($j) = \($i * $j)" ' # Output: # 2 * 1 = 2 # 2 * 2 = 4 # 2 * 3 = 6 # 2 * 4 = 8 # 2 * 5 = 10 # 3 * 1 = 3 # 3 * 2 = 6 # 3 * 3 = 9 # 3 * 4 = 12 # 3 * 5 = 15 # It's sometimes useful to bind the initial input to a variable at the # start of a program, so that you can refer to it later down the pipeline. # jq -rn "$(cat <<'EOF' {lookup: {a: 1, b: 2, c: 3}, bonuses: {a: 5, b: 2, c: 9} } | . as $doc | .bonuses | to_entries[] | "\(.key)'s total is \($doc.lookup[.key] + .value)" EOF )" # Output: # a's total is 6 # b's total is 4 # c's total is 12 # jq supports destructing during variable binding. This lets you extract values # from an array or an object and bind them to variables. # jq -n '[range(5)] | . as [$first, $second] | $second' # Output: # 1 jq -n '{ name: "Tom", numbers: [1, 2, 3], age: 32} | . as { name: $who, # bind .name to $who $name, # shorthand for `name: $name` numbers: [$first, $second], } | $name, $second, $first, $who ' # Output: # "Tom" # 2 # 1 # "Tom" # In jq, values can be assigned to an array index or object key via the # assignment operator, `=`. The same current input is given to both sides # of the assignment operator, and the assignment itself evaluates to the # current input. In other words, the assignment expression is evaluated # for its side effect, and doesn't generate a new output. # jq -n '.a = 1 | .b = .a + 1' # => {"a": 1, "b": 2} # Note that input is `null` due to `jq -n`, so `.` is `null` in the first # filter, and assigning to a key under `null` turns it into an object with # the key. The same input (now an object) then gets piped to the next filter, # which then sets the `b` key to the value of the `a` key plus `1`, which is `2`. # # Another example: # jq -n '.a=1, .a.b=2' # => {"a": 1} {"a": {"b": 2}} # In the above example, two objects are generated because both assignments # received `null` as their inputs, and each operand of the comma operator # is evaluated independently. Notice also how you can easily generate # nested objects. # In addition to the assignment operator, jq also has operators like: # `+=`, `-=`, `*=`, and '/=', ... etc. Basically, `a op= b` is a shorthand # for `a = a op b`, and they are handy for updating an object attribute or # an item in an array based on its current value. Examples: # jq -n '.a.b.c = 3 | .a.b.c = .a.b.c + 1' # => {"a": {"b": {"c": 4}}} jq -n '.a.b.c = 3 | .a.b.c += 1' # => {"a": {"b": {"c": 4}}} # To delete a value, use `del/1`, which takes a path expression that specifies # the locations of the things to be deleted. Example: # jq -n '{a: 1, b: {c: 2}, d: [3, 4, 5]} | del(.b.c, .d[1]) | .b.x = 6' # Output: # { # "a": 1, # "b": { # "x": 6 # }, # "d": [ # 3, # 5 # ] # } # Other than using jq's built-in functions, you can define your own. # In fact, many built-in functions are defined using jq (see the link # to jq's built-in functions at the end of the doc). # jq -n ' def my_select(expr): if expr then . else empty end; def my_map(expr): [.[] | expr]; def sum: reduce .[] as $x (0; . + $x); def my_range($from; $to): if $from >= $to then empty else $from, my_range($from + 1; $to) end ; [my_range(1; 6)] | my_map(my_select(. % 2 != 0)) | sum ' # Output: # 9 # Some notes about function definitions: # # - Functions are usually defined at the beginning, so that they are available # to the rest of the jq program. # # - Each function definition should end with a `;` (semicolon). # # - It's also possible to define a function within another, though it's not shown here. # # - Function parameters are separated by `;` (semicolon). This is consistent with # passing multiple arguments when calling a function. # # - A function can call itself; in fact, jq has TCO (Tail Call Optimization). # # - `def f($a; $b): ...;` is a shorthand for: `def f(a; b): a as $a | b as $b | ...` ``` ## Further Reading - [jq Manual](https://jqlang.github.io/jq/manual/) - [Language Description](https://github.com/jqlang/jq/wiki/jq-Language-Description) - [Cookbook](https://github.com/jqlang/jq/wiki/Cookbook) - [builtin.jq](https://github.com/jqlang/jq/blob/master/src/builtin.jq) ================================================ FILE: jquery.md ================================================ --- category: framework name: jQuery contributors: - ["Sawyer Charles", "https://github.com/xssc"] - ["Devansh Patil", "https://github.com/subtra3t"] filename: jquery.js --- jQuery is a JavaScript library that helps you "do more, write less". It makes many common JavaScript tasks and makes them easier to write. jQuery is used by many big companies and developers everywhere. It makes AJAX, event handling, document manipulation, and much more, easier and faster. Because jQuery is a JavaScript library you should [learn JavaScript first](../javascript/) **NOTE**: jQuery has fallen out of the limelight in recent years, since you can achieve the same thing with the vanilla DOM (Document Object Model) API. So the only thing it is used for is a couple of handy features, such as the [jQuery date picker](https://api.jqueryui.com/datepicker) (which actually has a standard, unlike the `` HTML element), and the obvious decrease in the code length. ```js /////////////////////////////////// // 1. Selectors // Selectors in jQuery are used to select an element var page = $(window); // Selects the whole viewport // Selectors can also be CSS selector var paragraph = $('p'); // Selects all paragraph elements var table1 = $('#table1'); // Selects element with id 'table1' var squares = $('.square'); // Selects all elements with the class 'square' var square_p = $('p.square') // Selects paragraphs with the 'square' class /////////////////////////////////// // 2. Events and Effects // jQuery is very good at handling what happens when an event is triggered // A very common event used is the ready event on the document // You can use the 'ready' method to wait until the element has finished loading $(document).ready(function(){ // Code won't execute until the document is loaded }); // You can also use defined functions function onAction() { // This is executed when the event is triggered } $('#btn').click(onAction); // Invokes onAction on click // Some other common events are: $('#btn').dblclick(onAction); // Double click $('#btn').hover(onAction); // Hovering over $('#btn').focus(onAction); // On focus $('#btn').blur(onAction); // Losses focus $('#btn').submit(onAction); // On submit $('#btn').select(onAction); // When an element is selected $('#btn').keydown(onAction); // When a key is pushed down $('#btn').keyup(onAction); // When a key is released $('#btn').keypress(onAction); // When a key is pressed $('#btn').mousemove(onAction); // When the mouse is moved $('#btn').mouseenter(onAction); // Mouse enters the element $('#btn').mouseleave(onAction); // Mouse leaves the element // These can all also trigger the event instead of handling it // by simply not giving any parameters $('#btn').dblclick(); // Fires double click on the element // You can handle multiple events while only using the selector once $('#btn').on( {dblclick: myFunction1} // Triggered on double click {blur: myFunction1} // Triggered on blur ); // You can move and hide elements with some effect methods $('.table').hide(); // Hides the element(s) // Note: calling a function in these methods will still hide the element $('.table').hide(function(){ // Element hidden then function executed }); // You can store selectors in variables var tables = $('.table'); // Some basic document manipulation methods are: tables.hide(); // Hides element(s) tables.show(); // Shows (un-hides) element(s) tables.toggle(); // Changes the hide/show state tables.fadeOut(); // Fades out tables.fadeIn(); // Fades in tables.fadeToggle(); // Fades in or out tables.fadeTo(0.5); // Fades to an opacity (between 0 and 1) tables.slideUp(); // Slides up tables.slideDown(); // Slides down tables.slideToggle(); // Slides up or down // All of the above take a speed (milliseconds) and callback function tables.hide(1000, myFunction); // 1 second hide animation then function // fadeTo has a required opacity as its second parameter tables.fadeTo(2000, 0.1, myFunction); // 2 sec. fade to 0.1 opacity then function // You can get slightly more advanced with the animate method tables.animate({margin-top:"+=50", height: "100px"}, 500, myFunction); // The animate method takes an object of css and values to end with, // optional options parameter to tune the animation, // and of course the callback function /////////////////////////////////// // 3. Manipulation // These are similar to effects but can do more $('div').addClass('taming-slim-20'); // Adds class taming-slim-20 to all div // Common manipulation methods $('p').append('Hello world'); // Adds to end of element $('p').attr('class'); // Gets attribute $('p').attr('class', 'content'); // Sets attribute $('p').hasClass('taming-slim-20'); // Returns true if it has the class $('p').height(); // Gets height of element or sets height // For many manipulation methods, getting info on an element // will ONLY get the first matching element $('p').height(); // Gets only the first 'p' tag's height // You can use each to loop through all the elements var heights = []; $('p').each(function() { heights.push($(this).height()); // Adds all 'p' tag heights to array }); ``` ## Further Reading * [Codecademy - jQuery](https://www.codecademy.com/learn/learn-jquery) A good introduction to jQuery in a "learn by doing it" format. ================================================ FILE: json.md ================================================ --- name: JSON filename: learnjson.json contributors: - ["Anna Harren", "https://github.com/iirelu"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["himanshu", "https://github.com/himanshu81494"] - ["Michael Neth", "https://github.com/infernocloud"] - ["Athanasios Emmanouilidis", "https://github.com/athanasiosem"] --- JSON is an extremely simple data-interchange format. As [json.org](https://json.org) says, it is easy for humans to read and write and for machines to parse and generate. A piece of JSON can be any value of the types listed later, but in practice almost always represents either: * A collection of name/value pairs (`{ }`). In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array. * An ordered list of values (`[ ]`). In various languages, this is realized as an array, vector, list, or sequence. JSON in its purest form has no actual comments, but most parsers will accept C-style (`//`, `/* */`) comments. Some parsers also tolerate a trailing comma (i.e. a comma after the last element of an array or the after the last property of an object), but they should be avoided for better compatibility. For the purposes of this tutorial, everything is going to be 100% valid JSON. Luckily, it kind of speaks for itself. Supported data types: * Strings: `"hello"`, `"\"A quote.\""`, `"\u0abe"`, `"Newline.\n"` * Numbers: `23`, `0.11`, `12e10`, `3.141e-10`, `1.23e+4` * Objects: `{ "key": "value" }` * Arrays: `["Values"]` * Miscellaneous: `true`, `false`, `null` ```json { "key": "value", "keys": "must always be enclosed in double quotes", "numbers": 0, "strings": "Hellø, wørld. All unicode is allowed, along with \"escaping\".", "has bools?": true, "nothingness": null, "big number": 1.2e+100, "objects": { "comment": "Most of your structure will come from objects.", "array": [0, 1, 2, 3, "Arrays can have anything in them.", 5], "another object": { "comment": "These things can be nested, very useful." } }, "silliness": [ { "sources of potassium": ["bananas"] }, [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, "neo"], [0, 0, 0, 1] ] ], "alternative style": { "comment": "check this out!" , "comma position": "doesn't matter, if it's before the next key, it's valid" , "another comment": "how nice" }, "whitespace": "Does not matter.", "that was short": "And done. You now know everything JSON has to offer." } ``` ## Further Reading * [JSON.org](https://json.org) All of JSON beautifully explained using flowchart-like graphics. * [JSON Tutorial](https://www.youtube.com/watch?v=wI1CWzNtE-M) A concise introduction to JSON. ================================================ FILE: jsonnet.md ================================================ --- name: Jsonnet filename: learnjsonnet.jsonnet contributors: - ["Huan Wang", "https://github.com/fredwangwang"] --- Jsonnet is a powerful templating language for JSON. Any valid JSON document is a valid Jsonnet object. For an interactive demo/tutorial, click [here](https://jsonnet.org/learning/tutorial.html) ```jsonnet // single line comment /* multiline comment */ # as well as python style comment # define a variable. # Variables have no effect in the generated JSON without being used. local num1 = 1; local num2 = 1 + 1; local num3 = 5 - 2; local num4 = 9 % 5; local num5 = 10 / 2.0; # jsonnet is a lazy language, if a variable is not used, it is not evaluated. local num_runtime_error = 1 / 0; # fields are valid identifiers without quotes local obj1 = { a: 'letter a', B: 'letter B' }; local arr1 = ['a', 'b', 'c']; # string literals use " or '. local str1 = 'a' + 'B'; # multiline text literal in between ||| # Each line must start with a white space. local str_multiline = ||| this is a multiline string |||; # Python-compatible string formatting is available via % # When combined with ||| this can be used for templating text files. local str_templating = ||| %(f1)0.3f ||| % { f1: 1.2345678 }; assert str_templating == '1.235\n'; # if b then e else e. The else branch is optional and defaults to null local var1 = if 3 < 2 then "YES"; assert var1 == null; local obj2 = { # variable defined inside the object ends with ',' local var_in_obj = 0, local vowels = ['a', 'e', 'i', 'o', 'u'], local numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], # [num] to look up an array element first_vowel: vowels[0], # can also slice the array like in Python even_numbers: numbers[1::2], # python-style list and object comprehensions are also supported double_numbers: [x * 2 for x in numbers], even_numbers_map: { # [ ] syntax in field name is to compute the field name dynamically [x + '_is_even']: true for x in numbers if x % 2 == 0 }, nested: { nested_field1: 'some-value', # self refers to the current object # ["field-name"] or .field-name can be used to look up a field nested_field2: self.nested_field1, nested_field3: self.nested_field1, # $ refers to outer-most object nested_field4: $.first_vowel, assert self.nested_field1 == self.nested_field2, assert self.nested_field1 == self.nested_field3, }, special_field: 'EVERYTHING FEELS BAD', }; local obj3 = { local var_in_obj = 1.234, local var_in_obj2 = { a: { b: 'c' } }, concat_array: [1, 2, 3] + [4], # strings can be concat with +, # which implicitly converts one operand to string if needed. concat_string: '123' + 4, # == tests deep equality equals: { a: { b: 'c', d: {} } } == var_in_obj2, special_field: 'this feels good', }; # objects can be merged with + where the right-hand side wins field conflicts local obj4 = obj2 + obj3; assert obj4.special_field == 'this feels good'; # define a function # functions have positional parameters, named parameters, and default arguments local my_function(x, y, z=1) = x + y - z; local num6 = my_function(7, 8, 9); local num7 = my_function(8, z=10, y=9); local num8 = my_function(4, 5); # inline anonymous function local num9 = (function(x) x * x)(3); local obj5 = { # define a method # fields defined with :: are hidden, which does not apper in generated JSON # function cannot be serialized so need to be hidden # if the object is used in the generated JSON. is_odd(x):: x % 2 == 1, }; assert obj5 == {}; # a jsonnet document has to evaluate to something # be it an object, list, number or just string literal "FIN" ``` ## Further Reading There are a few but important concepts that are not touched in this example, including: - Passing variables from command line: [Parameterize Entire Config](https://jsonnet.org/learning/tutorial.html#parameterize-entire-config) - Import other jsonnet libraries/files: [Imports](https://jsonnet.org/learning/tutorial.html#imports) - In depth example of OOP aspect of Jsonnet: [Object-Orientation](https://jsonnet.org/learning/tutorial.html#Object-Orientation) - Useful standard library: [Stdlib](https://jsonnet.org/ref/stdlib.html) ================================================ FILE: julia.md ================================================ --- name: Julia contributors: - ["Leah Hanson", "http://leahhanson.us"] - ["Pranit Bauva", "https://github.com/pranitbauva1997"] - ["Daniel YC Lin", "https://github.com/dlintw"] filename: learnjulia.jl --- Julia is a new homoiconic functional language focused on technical computing. While having the full power of homoiconic macros, first-class functions, and low-level control, Julia is as easy to learn and use as Python. This is based on Julia version 1.0.0. ```julia # Single line comments start with a hash (pound) symbol. #= Multiline comments can be written by putting '#=' before the text and '=#' after the text. They can also be nested. =# #################################################### ## 1. Primitive Datatypes and Operators #################################################### # Everything in Julia is an expression. # There are several basic types of numbers. typeof(3) # => Int64 typeof(3.2) # => Float64 typeof(2 + 1im) # => Complex{Int64} typeof(2 // 3) # => Rational{Int64} # All of the normal infix operators are available. 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 35 / 5 # => 7.0 10 / 2 # => 5.0 # dividing integers always results in a Float64 div(5, 2) # => 2 # for a truncated result, use div 5 \ 35 # => 7.0 2^2 # => 4 # power, not bitwise xor 12 % 10 # => 2 # Enforce precedence with parentheses (1 + 3) * 2 # => 8 # Julia (unlike Python for instance) has integer under/overflow 10^19 # => -8446744073709551616 # use bigint or floating point to avoid this big(10)^19 # => 10000000000000000000 1e19 # => 1.0e19 10.0^19 # => 1.0e19 # Bitwise Operators ~2 # => -3 # bitwise not 3 & 5 # => 1 # bitwise and 2 | 4 # => 6 # bitwise or xor(2, 4) # => 6 # bitwise xor 2 >>> 1 # => 1 # logical shift right 2 >> 1 # => 1 # arithmetic shift right 2 << 1 # => 4 # logical/arithmetic shift left # Use the bitstring function to see the binary representation of a number. bitstring(12345) # => "0000000000000000000000000000000000000000000000000011000000111001" bitstring(12345.0) # => "0100000011001000000111001000000000000000000000000000000000000000" # Boolean values are primitives true false # Boolean operators !true # => false !false # => true 1 == 1 # => true 2 == 1 # => false 1 != 1 # => false 2 != 1 # => true 1 < 10 # => true 1 > 10 # => false 2 <= 2 # => true 2 >= 2 # => true # Comparisons can be chained, like in Python but unlike many other languages 1 < 2 < 3 # => true 2 < 3 < 2 # => false # Strings are created with " "This is a string." # Character literals are written with ' 'a' # Strings are UTF8 encoded, so strings like "π" or "☃" are not directly equivalent # to an array of single characters. # Only if they contain only ASCII characters can they be safely indexed. ascii("This is a string")[1] # => 'T' # => 'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase) # Beware, Julia indexes everything from 1 (like MATLAB), not 0 (like most languages). # Otherwise, iterating over strings is recommended (map, for loops, etc). # String can be compared lexicographically, in dictionary order: "good" > "bye" # => true "good" == "good" # => true "1 + 2 = 3" == "1 + 2 = $(1 + 2)" # => true # $(..) can be used for string interpolation: "2 + 2 = $(2 + 2)" # => "2 + 2 = 4" # You can put any Julia expression inside the parentheses. # Printing is easy println("I'm Julia. Nice to meet you!") # => I'm Julia. Nice to meet you! # Another way to format strings is the printf macro from the stdlib Printf. using Printf # this is how you load (or import) a module @printf "%d is less than %f\n" 4.5 5.3 # => 4 is less than 5.300000 #################################################### ## 2. Variables and Collections #################################################### # You don't declare variables before assigning to them. someVar = 5 # => 5 someVar # => 5 # Accessing a previously unassigned variable is an error try someOtherVar # => ERROR: UndefVarError: someOtherVar not defined catch e println(e) end # Variable names start with a letter or underscore. # After that, you can use letters, digits, underscores, and exclamation points. SomeOtherVar123! = 6 # => 6 # You can also use certain unicode characters # here ☃ is a Unicode 'snowman' characters, see http://emojipedia.org/%E2%98%83%EF%B8%8F if it displays wrongly here ☃ = 8 # => 8 # These are especially handy for mathematical notation, like the constant π 2 * π # => 6.283185307179586 # A note on naming conventions in Julia: # # * Word separation can be indicated by underscores ('_'), but use of # underscores is discouraged unless the name would be hard to read # otherwise. # # * Names of Types begin with a capital letter and word separation is shown # with CamelCase instead of underscores. # # * Names of functions and macros are in lower case, without underscores. # # * Functions that modify their inputs have names that end in !. These # functions are sometimes called mutating functions or in-place functions. # Arrays store a sequence of values indexed by integers 1 through n: a = Int64[] # => 0-element Array{Int64,1} # 1-dimensional array literals can be written with comma-separated values. b = [4, 5, 6] # => 3-element Array{Int64,1}: [4, 5, 6] b = [4; 5; 6] # => 3-element Array{Int64,1}: [4, 5, 6] b[1] # => 4 b[end] # => 6 # 2-dimensional arrays use space-separated values and semicolon-separated rows. matrix = [1 2; 3 4] # => 2×2 Array{Int64,2}: [1 2; 3 4] # Arrays of a particular type b = Int8[4, 5, 6] # => 3-element Array{Int8,1}: [4, 5, 6] # Add stuff to the end of a list with push! and append! # By convention, the exclamation mark '!' is appended to names of functions # that modify their arguments push!(a, 1) # => [1] push!(a, 2) # => [1,2] push!(a, 4) # => [1,2,4] push!(a, 3) # => [1,2,4,3] append!(a, b) # => [1,2,4,3,4,5,6] # Remove from the end with pop pop!(b) # => 6 b # => [4,5] # Let's put it back push!(b, 6) # => [4,5,6] b # => [4,5,6] a[1] # => 1 # remember that Julia indexes from 1, not 0! # end is a shorthand for the last index. It can be used in any # indexing expression a[end] # => 6 # we also have popfirst! and pushfirst! popfirst!(a) # => 1 a # => [2,4,3,4,5,6] pushfirst!(a, 7) # => [7,2,4,3,4,5,6] a # => [7,2,4,3,4,5,6] # Function names that end in exclamations points indicate that they modify # their argument. arr = [5,4,6] # => 3-element Array{Int64,1}: [5,4,6] sort(arr) # => [4,5,6] arr # => [5,4,6] sort!(arr) # => [4,5,6] arr # => [4,5,6] # Looking out of bounds is a BoundsError try a[0] # => ERROR: BoundsError: attempt to access 7-element Array{Int64,1} at # index [0] # => Stacktrace: # => [1] getindex(::Array{Int64,1}, ::Int64) at .\array.jl:731 # => [2] top-level scope at none:0 # => [3] ... # => in expression starting at ...\LearnJulia.jl:180 a[end + 1] # => ERROR: BoundsError: attempt to access 7-element Array{Int64,1} at # index [8] # => Stacktrace: # => [1] getindex(::Array{Int64,1}, ::Int64) at .\array.jl:731 # => [2] top-level scope at none:0 # => [3] ... # => in expression starting at ...\LearnJulia.jl:188 catch e println(e) end # Errors list the line and file they came from, even if it's in the standard # library. You can look in the folder share/julia inside the julia folder to # find these files. # You can initialize arrays from ranges a = [1:5;] # => 5-element Array{Int64,1}: [1,2,3,4,5] a2 = [1:5] # => 1-element Array{UnitRange{Int64},1}: [1:5] # You can look at ranges with slice syntax. a[1:3] # => [1, 2, 3] a[2:end] # => [2, 3, 4, 5] # Remove elements from an array by index with splice! arr = [3,4,5] splice!(arr, 2) # => 4 arr # => [3,5] # Concatenate lists with append! b = [1,2,3] append!(a, b) # => [1, 2, 3, 4, 5, 1, 2, 3] a # => [1, 2, 3, 4, 5, 1, 2, 3] # Check for existence in a list with in in(1, a) # => true # Examine the length with length length(a) # => 8 # Tuples are immutable. tup = (1, 2, 3) # => (1,2,3) typeof(tup) # => Tuple{Int64,Int64,Int64} tup[1] # => 1 try tup[1] = 3 # => ERROR: MethodError: no method matching # setindex!(::Tuple{Int64,Int64,Int64}, ::Int64, ::Int64) catch e println(e) end # Many array functions also work on tuples length(tup) # => 3 tup[1:2] # => (1,2) in(2, tup) # => true # You can unpack tuples into variables a, b, c = (1, 2, 3) # => (1,2,3) a # => 1 b # => 2 c # => 3 # Tuples are created even if you leave out the parentheses d, e, f = 4, 5, 6 # => (4,5,6) d # => 4 e # => 5 f # => 6 # A 1-element tuple is distinct from the value it contains (1,) == 1 # => false (1) == 1 # => true # Look how easy it is to swap two values e, d = d, e # => (5,4) d # => 5 e # => 4 # Dictionaries store mappings emptyDict = Dict() # => Dict{Any,Any} with 0 entries # You can create a dictionary using a literal filledDict = Dict("one" => 1, "two" => 2, "three" => 3) # => Dict{String,Int64} with 3 entries: # => "two" => 2, "one" => 1, "three" => 3 # Look up values with [] filledDict["one"] # => 1 # Get all keys keys(filledDict) # => Base.KeySet for a Dict{String,Int64} with 3 entries. Keys: # => "two", "one", "three" # Note - dictionary keys are not sorted or in the order you inserted them. # Get all values values(filledDict) # => Base.ValueIterator for a Dict{String,Int64} with 3 entries. Values: # => 2, 1, 3 # Note - Same as above regarding key ordering. # Check for existence of keys in a dictionary with in, haskey in(("one" => 1), filledDict) # => true in(("two" => 3), filledDict) # => false haskey(filledDict, "one") # => true haskey(filledDict, 1) # => false # Trying to look up a non-existent key will raise an error try filledDict["four"] # => ERROR: KeyError: key "four" not found catch e println(e) end # Use the get method to avoid that error by providing a default value # get(dictionary, key, defaultValue) get(filledDict, "one", 4) # => 1 get(filledDict, "four", 4) # => 4 # Use Sets to represent collections of unordered, unique values emptySet = Set() # => Set(Any[]) # Initialize a set with values filledSet = Set([1, 2, 2, 3, 4]) # => Set([4, 2, 3, 1]) # Add more values to a set push!(filledSet, 5) # => Set([4, 2, 3, 5, 1]) # Check if the values are in the set in(2, filledSet) # => true in(10, filledSet) # => false # There are functions for set intersection, union, and difference. otherSet = Set([3, 4, 5, 6]) # => Set([4, 3, 5, 6]) intersect(filledSet, otherSet) # => Set([4, 3, 5]) union(filledSet, otherSet) # => Set([4, 2, 3, 5, 6, 1]) setdiff(Set([1,2,3,4]), Set([2,3,5])) # => Set([4, 1]) # Assignment with `=` attaches a new label to the same value without copying a = [1, 2, 3] b = a # Now `b` and `a` point to the same value, so changing one affects the other: a[3] = 5 b[3] # => 5 # The `copy()` function can create a shallow copy of an array, dictionary, # or other container a = [1, 2, 3] c = copy(a) a[3] = 5 c[3] # => 3 #################################################### ## 3. Control Flow #################################################### # Let's make a variable someVar = 5 # Here is an if statement. Indentation is not meaningful in Julia. if someVar > 10 println("someVar is totally bigger than 10.") elseif someVar < 10 # This elseif clause is optional. println("someVar is smaller than 10.") else # The else clause is optional too. println("someVar is indeed 10.") end # => prints "some var is smaller than 10" # For loops iterate over iterables. # Iterable types include Range, Array, Set, Dict, and AbstractString. for animal = ["dog", "cat", "mouse"] println("$animal is a mammal") # You can use $ to interpolate variables or expression into strings. # In this special case, no need for parenthesis: $animal and $(animal) give the same end # => dog is a mammal # => cat is a mammal # => mouse is a mammal # You can use 'in' instead of '='. for animal in ["dog", "cat", "mouse"] println("$animal is a mammal") end # => dog is a mammal # => cat is a mammal # => mouse is a mammal for pair in Dict("dog" => "mammal", "cat" => "mammal", "mouse" => "mammal") from, to = pair println("$from is a $to") end # => mouse is a mammal # => cat is a mammal # => dog is a mammal for (k, v) in Dict("dog" => "mammal", "cat" => "mammal", "mouse" => "mammal") println("$k is a $v") end # => mouse is a mammal # => cat is a mammal # => dog is a mammal # While loops loop while a condition is true let x = 0 while x < 4 println(x) x += 1 # Shorthand for in place increment: x = x + 1 end end # => 0 # => 1 # => 2 # => 3 # Handle exceptions with a try/catch block try error("help") catch e println("caught it $e") end # => caught it ErrorException("help") #################################################### ## 4. Functions #################################################### # The keyword 'function' creates new functions # function name(arglist) # body... # end function add(x, y) println("x is $x and y is $y") # Functions return the value of their last statement x + y end add(5, 6) # => x is 5 and y is 6 # => 11 # Compact assignment of functions f_add(x, y) = x + y # => f_add (generic function with 1 method) f_add(3, 4) # => 7 # Function can also return multiple values as tuple fn(x, y) = x + y, x - y # => fn (generic function with 1 method) fn(3, 4) # => (7, -1) # You can define functions that take a variable number of # positional arguments function varargs(args...) return args # use the keyword return to return anywhere in the function end # => varargs (generic function with 1 method) varargs(1, 2, 3) # => (1,2,3) # The ... is called a splat. # We just used it in a function definition. # It can also be used in a function call, # where it will splat an Array or Tuple's contents into the argument list. add([5,6]...) # this is equivalent to add(5,6) x = (5, 6) # => (5,6) add(x...) # this is equivalent to add(5,6) # You can define functions with optional positional arguments function defaults(a, b, x=5, y=6) return "$a $b and $x $y" end # => defaults (generic function with 3 methods) defaults('h', 'g') # => "h g and 5 6" defaults('h', 'g', 'j') # => "h g and j 6" defaults('h', 'g', 'j', 'k') # => "h g and j k" try defaults('h') # => ERROR: MethodError: no method matching defaults(::Char) defaults() # => ERROR: MethodError: no method matching defaults() catch e println(e) end # You can define functions that take keyword arguments function keyword_args(;k1=4, name2="hello") # note the ; return Dict("k1" => k1, "name2" => name2) end # => keyword_args (generic function with 1 method) keyword_args(name2="ness") # => ["name2"=>"ness", "k1"=>4] keyword_args(k1="mine") # => ["name2"=>"hello", "k1"=>"mine"] keyword_args() # => ["name2"=>"hello", "k1"=>4] # You can combine all kinds of arguments in the same function function all_the_args(normalArg, optionalPositionalArg=2; keywordArg="foo") println("normal arg: $normalArg") println("optional arg: $optionalPositionalArg") println("keyword arg: $keywordArg") end # => all_the_args (generic function with 2 methods) all_the_args(1, 3, keywordArg=4) # => normal arg: 1 # => optional arg: 3 # => keyword arg: 4 # Julia has first class functions function create_adder(x) adder = function (y) return x + y end return adder end # => create_adder (generic function with 1 method) # This is "stabby lambda syntax" for creating anonymous functions (x -> x > 2)(3) # => true # This function is identical to create_adder implementation above. function create_adder(x) y -> x + y end # => create_adder (generic function with 1 method) # You can also name the internal function, if you want function create_adder(x) function adder(y) x + y end adder end # => create_adder (generic function with 1 method) add_10 = create_adder(10) # => (::getfield(Main, Symbol("#adder#11")){Int64}) # (generic function with 1 method) add_10(3) # => 13 # There are built-in higher order functions map(add_10, [1,2,3]) # => [11, 12, 13] filter(x -> x > 5, [3, 4, 5, 6, 7]) # => [6, 7] # We can use list comprehensions [add_10(i) for i = [1, 2, 3]] # => [11, 12, 13] [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] #################################################### ## 5. Types #################################################### # Julia has a type system. # Every value has a type; variables do not have types themselves. # You can use the `typeof` function to get the type of a value. typeof(5) # => Int64 # Types are first-class values typeof(Int64) # => DataType typeof(DataType) # => DataType # DataType is the type that represents types, including itself. # Types are used for documentation, optimizations, and dispatch. # They are not statically checked. # Users can define types # They are like records or structs in other languages. # New types are defined using the `struct` keyword. # struct Name # field::OptionalType # ... # end struct Tiger taillength::Float64 coatcolor # not including a type annotation is the same as `::Any` end # The default constructor's arguments are the properties # of the type, in the order they are listed in the definition tigger = Tiger(3.5, "orange") # => Tiger(3.5,"orange") # The type doubles as the constructor function for values of that type sherekhan = typeof(tigger)(5.6, "fire") # => Tiger(5.6,"fire") # These struct-style types are called concrete types # They can be instantiated, but cannot have subtypes. # The other kind of types is abstract types. # abstract Name abstract type Cat end # just a name and point in the type hierarchy # Abstract types cannot be instantiated, but can have subtypes. # For example, Number is an abstract type subtypes(Number) # => 2-element Array{Any,1}: # => Complex # => Real subtypes(Cat) # => 0-element Array{Any,1} # AbstractString, as the name implies, is also an abstract type subtypes(AbstractString) # => 4-element Array{Any,1}: # => String # => SubString # => SubstitutionString # => Test.GenericString # Every type has a super type; use the `supertype` function to get it. typeof(5) # => Int64 supertype(Int64) # => Signed supertype(Signed) # => Integer supertype(Integer) # => Real supertype(Real) # => Number supertype(Number) # => Any supertype(supertype(Signed)) # => Real supertype(Any) # => Any # All of these type, except for Int64, are abstract. typeof("fire") # => String supertype(String) # => AbstractString # Likewise here with String supertype(SubString) # => AbstractString # <: is the subtyping operator struct Lion <: Cat # Lion is a subtype of Cat maneColor roar::AbstractString end # You can define more constructors for your type # Just define a function of the same name as the type # and call an existing constructor to get a value of the correct type Lion(roar::AbstractString) = Lion("green", roar) # This is an outer constructor because it's outside the type definition struct Panther <: Cat # Panther is also a subtype of Cat eyeColor Panther() = new("green") # Panthers will only have this constructor, and no default constructor. end # Using inner constructors, like Panther does, gives you control # over how values of the type can be created. # When possible, you should use outer constructors rather than inner ones. #################################################### ## 6. Multiple-Dispatch #################################################### # In Julia, all named functions are generic functions # This means that they are built up from many small methods # Each constructor for Lion is a method of the generic function Lion. # For a non-constructor example, let's make a function meow: # Definitions for Lion, Panther, Tiger function meow(animal::Lion) animal.roar # access type properties using dot notation end function meow(animal::Panther) "grrr" end function meow(animal::Tiger) "rawwwr" end # Testing the meow function meow(tigger) # => "rawwwr" meow(Lion("brown", "ROAAR")) # => "ROAAR" meow(Panther()) # => "grrr" # Review the local type hierarchy Tiger <: Cat # => false Lion <: Cat # => true Panther <: Cat # => true # Defining a function that takes Cats function pet_cat(cat::Cat) println("The cat says $(meow(cat))") end # => pet_cat (generic function with 1 method) pet_cat(Lion("42")) # => The cat says 42 try pet_cat(tigger) # => ERROR: MethodError: no method matching pet_cat(::Tiger) catch e println(e) end # In OO languages, single dispatch is common; # this means that the method is picked based on the type of the first argument. # In Julia, all of the argument types contribute to selecting the best method. # Let's define a function with more arguments, so we can see the difference function fight(t::Tiger, c::Cat) println("The $(t.coatcolor) tiger wins!") end # => fight (generic function with 1 method) fight(tigger, Panther()) # => The orange tiger wins! fight(tigger, Lion("ROAR")) # => The orange tiger wins! # Let's change the behavior when the Cat is specifically a Lion fight(t::Tiger, l::Lion) = println("The $(l.maneColor)-maned lion wins!") # => fight (generic function with 2 methods) fight(tigger, Panther()) # => The orange tiger wins! fight(tigger, Lion("ROAR")) # => The green-maned lion wins! # We don't need a Tiger in order to fight fight(l::Lion, c::Cat) = println("The victorious cat says $(meow(c))") # => fight (generic function with 3 methods) fight(Lion("balooga!"), Panther()) # => The victorious cat says grrr try fight(Panther(), Lion("RAWR")) # => ERROR: MethodError: no method matching fight(::Panther, ::Lion) # => Closest candidates are: # => fight(::Tiger, ::Lion) at ... # => fight(::Tiger, ::Cat) at ... # => fight(::Lion, ::Cat) at ... # => ... catch e println(e) end # Also let the cat go first fight(c::Cat, l::Lion) = println("The cat beats the Lion") # => fight (generic function with 4 methods) # This warning is because it's unclear which fight will be called in: try fight(Lion("RAR"), Lion("brown", "rarrr")) # => ERROR: MethodError: fight(::Lion, ::Lion) is ambiguous. Candidates: # => fight(c::Cat, l::Lion) in Main at ... # => fight(l::Lion, c::Cat) in Main at ... # => Possible fix, define # => fight(::Lion, ::Lion) # => ... catch e println(e) end # The result may be different in other versions of Julia fight(l::Lion, l2::Lion) = println("The lions come to a tie") # => fight (generic function with 5 methods) fight(Lion("RAR"), Lion("brown", "rarrr")) # => The lions come to a tie # Under the hood # You can take a look at the llvm and the assembly code generated. square_area(l) = l * l # square_area (generic function with 1 method) square_area(5) # => 25 # What happens when we feed square_area an integer? code_native(square_area, (Int32,), syntax = :intel) # .text # ; Function square_area { # ; Location: REPL[116]:1 # Prologue # push rbp # mov rbp, rsp # ; Function *; { # ; Location: int.jl:54 # imul ecx, ecx # Square l and store the result in ECX # ;} # mov eax, ecx # pop rbp # Restore old base pointer # ret # Result will still be in EAX # nop dword ptr [rax + rax] # ;} code_native(square_area, (Float32,), syntax = :intel) # .text # ; Function square_area { # ; Location: REPL[116]:1 # push rbp # mov rbp, rsp # ; Function *; { # ; Location: float.jl:398 # vmulss xmm0, xmm0, xmm0 # Scalar single precision multiply (AVX) # ;} # pop rbp # ret # nop word ptr [rax + rax] # ;} code_native(square_area, (Float64,), syntax = :intel) # .text # ; Function square_area { # ; Location: REPL[116]:1 # push rbp # mov rbp, rsp # ; Function *; { # ; Location: float.jl:399 # vmulsd xmm0, xmm0, xmm0 # Scalar double precision multiply (AVX) # ;} # pop rbp # ret # nop word ptr [rax + rax] # ;} # Note that julia will use floating point instructions if any of the # arguments are floats. # Let's calculate the area of a circle circle_area(r) = pi * r * r # circle_area (generic function with 1 method) circle_area(5) # 78.53981633974483 code_native(circle_area, (Int32,), syntax = :intel) # .text # ; Function circle_area { # ; Location: REPL[121]:1 # push rbp # mov rbp, rsp # ; Function *; { # ; Location: operators.jl:502 # ; Function *; { # ; Location: promotion.jl:314 # ; Function promote; { # ; Location: promotion.jl:284 # ; Function _promote; { # ; Location: promotion.jl:261 # ; Function convert; { # ; Location: number.jl:7 # ; Function Type; { # ; Location: float.jl:60 # vcvtsi2sd xmm0, xmm0, ecx # Load integer (r) from memory # movabs rax, 497710928 # Load pi # ;}}}}} # ; Function *; { # ; Location: float.jl:399 # vmulsd xmm1, xmm0, qword ptr [rax] # pi * r # vmulsd xmm0, xmm1, xmm0 # (pi * r) * r # ;}} # pop rbp # ret # nop dword ptr [rax] # ;} code_native(circle_area, (Float64,), syntax = :intel) # .text # ; Function circle_area { # ; Location: REPL[121]:1 # push rbp # mov rbp, rsp # movabs rax, 497711048 # ; Function *; { # ; Location: operators.jl:502 # ; Function *; { # ; Location: promotion.jl:314 # ; Function *; { # ; Location: float.jl:399 # vmulsd xmm1, xmm0, qword ptr [rax] # ;}}} # ; Function *; { # ; Location: float.jl:399 # vmulsd xmm0, xmm1, xmm0 # ;} # pop rbp # ret # nop dword ptr [rax + rax] # ;} ``` ## Further Reading You can get a lot more detail from the [Julia Documentation](https://docs.julialang.org/) The best place to get help with Julia is the (very friendly) [Discourse forum](https://discourse.julialang.org/). ================================================ FILE: kdb+.md ================================================ --- name: kdb+ contributors: - ["Matt Doherty", "https://github.com/picodoc"] - ["Jonny Press", "https://github.com/jonnypress"] filename: learnkdb.q --- The q language and its database component kdb+ were developed by Arthur Whitney and released by Kx systems in 2003. q is a descendant of APL and as such is very terse and a little strange looking for anyone from a "C heritage" language background. Its expressiveness and vector oriented nature make it well suited to performing complex calculations on large amounts of data (while also encouraging some amount of [code golf](https://en.wikipedia.org/wiki/Code_golf)). The fundamental structure in the language is not the object but instead the list, and tables are built as collections of lists. This means - unlike most traditional RDBMS systems - tables are column oriented. The language has both an in-memory and on-disk database built in, giving a large amount of flexibility. kdb+ is most widely used in the world of finance to store, analyze, process and retrieve large time-series data sets. The terms *q* and *kdb+* are usually used interchangeably, as the two are not separable so this distinction is not really useful. To learn more about kdb+ you can join the [KX Community forums](https://learninghub.kx.com/forums/) or the [TorQ kdb+](https://groups.google.com/forum/#!forum/kdbtorq) group. ```q / Single line comments start with a forward-slash / These can also be used in-line, so long as at least one whitespace character / separates it from text to the left / A forward-slash on a line by itself starts a multiline comment and a backward-slash on a line by itself terminates it \ / Run this file in an empty directory //////////////////////////////////// // Basic Operators and Datatypes // //////////////////////////////////// / We have integers, which are 8 byte by default 3 / => 3 / And floats, also 8 byte as standard. Trailing f distinguishes from int 3.0 / => 3f / 4 byte numerical types can also be specified with trailing chars 3i / => 3i 3.0e / => 3e / Math is mostly what you would expect 1+1 / => 2 8-1 / => 7 10*2 / => 20 / Except division, which uses percent (%) instead of forward-slash (/) 35%5 / => 7f (the result of division is always a float) / For integer division we have the keyword div 4 div 3 / => 1 / Modulo also uses a keyword, since percent (%) is taken 4 mod 3 / => 1 / And exponentiation... 2 xexp 4 / => 16 / ...and truncating... floor 3.14159 / => 3 / ...getting the absolute value... abs -3.14159 / => 3.14159 / ...and many other things / see http://code.kx.com/q/ref/ for more / q has no operator precedence, everything is evaluated right to left / so results like this might take some getting used to 2*1+1 / => 4 / (no operator precedence tables to remember!) / Precedence can be modified with parentheses (restoring the 'normal' result) (2*1)+1 / => 3 / Assignment uses colon (:) instead of equals (=) / No need to declare variables before assignment a:3 a / => 3 / Variables can also be assigned in-line / this does not affect the value passed on c:3+b:2+a:1 / (data "flows" from right to left) a / => 1 b / => 3 c / => 6 / In-place operations are also as you might expect a+:2 a / => 3 / There are no "true" or "false" keywords in q / boolean values are indicated by the bit value followed by b 1b / => true value 0b / => false value / Equality comparisons use equals (=) (since we don't need it for assignment) 1=1 / => 1b 2=1 / => 0b / Inequality uses <> 1<>1 / => 0b 2<>1 / => 1b / The other comparisons are as you might expect 1<2 / => 1b 1>2 / => 0b 2<=2 / => 1b 2>=2 / => 1b / Comparison is not strict with regard to types... 42=42.0 / => 1b / ...unless we use the match operator (~) / which only returns true if entities are identical 42~42.0 / => 0b / The not operator returns true if the underlying value is zero not 0b / => 1b not 1b / => 0b not 42 / => 0b not 0.0 / => 1b / The max operator (|) reduces to logical "or" for bools 42|2.0 / => 42f 1b|0b / => 1b / The min operator (&) reduces to logical "and" for bools 42&2.0 / => 2f 1b&0b / => 0b / q provides two ways to store character data / Chars in q are stored in a single byte and use double-quotes (") ch:"a" / Strings are simply lists of char (more on lists later) str:"This is a string" / Escape characters work as normal str:"This is a string with \"quotes\"" / Char data can also be stored as symbols using backtick (`) symbol:`sym / Symbols are NOT LISTS, they are an enumeration / the q process stores internally a vector of strings / symbols are enumerated against this vector / this can be more space and speed efficient as these are constant width / The string function converts to strings string `symbol / => "symbol" string 1.2345 / => "1.2345" / q has a time type... t:01:00:00.000 / date type... d:2015.12.25 / and a datetime type (among other time types) dt:2015.12.25D12:00:00.000000000 / These support some arithmetic for easy manipulation dt + t / => 2015.12.25D13:00:00.000000000 t - 00:10:00.000 / => 00:50:00.000 / and can be decomposed using dot notation d.year / => 2015i d.mm / => 12i d.dd / => 25i / see http://code.kx.com/q4m3/2_Basic_Data_Types_Atoms/#25-temporal-data for more / q also has an infinity value so div by zero will not throw an error 1%0 / => 0w -1%0 / => -0w / And null types for representing missing values 0N / => null int 0n / => null float / see http://code.kx.com/q4m3/2_Basic_Data_Types_Atoms/#27-nulls for more / q has standard control structures / if is as you might expect (; separates the condition and instructions) if[1=1;a:"hi"] a / => "hi" / if-else uses $ (and unlike if, returns a value) $[1=0;a:"hi";a:"bye"] / => "bye" a / => "bye" / if-else can be extended to multiple clauses by adding args separated by ; $[1=0;a:"hi";0=1;a:"bye";a:"hello again"] a / => "hello again" //////////////////////////////////// //// Data Structures //// //////////////////////////////////// / q is not an object oriented language / instead complexity is built through ordered lists / and mapping them into higher order structures: dictionaries and tables / Lists (or arrays if you prefer) are simple ordered collections / they are defined using parentheses () and semi-colons (;) (1;2;3) / => 1 2 3 (-10.0;3.14159e;1b;`abc;"c") / => -10f / => 3.14159e / => 1b / => `abc / => "c" (mixed type lists are displayed on multiple lines) ((1;2;3);(4;5;6);(7;8;9)) / => 1 2 3 / => 4 5 6 / => 7 8 9 / Lists of uniform type can also be defined more concisely 1 2 3 / => 1 2 3 `list`of`syms / => `list`of`syms `list`of`syms ~ (`list;`of;`syms) / => 1b / List length count (1;2;3) / => 3 count "I am a string" / => 13 (string are lists of char) / Empty lists are defined with parentheses l:() count l / => 0 / Simple variables and single item lists are not equivalent / parentheses syntax cannot create a single item list (they indicate precedence) (1)~1 / => 1b / single item lists can be created using enlist singleton:enlist 1 / or appending to an empty list singleton:(),1 1~(),1 / => 0b / Speaking of appending, comma (,) is used for this, not plus (+) 1 2 3,4 5 6 / => 1 2 3 4 5 6 "hello ","there" / => "hello there" / Indexing uses square brackets [] l:1 2 3 4 l[0] / => 1 l[1] / => 2 / indexing out of bounds returns a null value rather than an error l[5] / => 0N / and indexed assignment l[0]:5 l / => 5 2 3 4 / Lists can also be used for indexing and indexed assignment l[1 3] / => 2 4 l[1 3]: 1 3 l / => 5 1 3 3 / Lists can be untyped/mixed type l:(1;2;`hi) / but once they are uniformly typed, q will enforce this l[2]:3 l / => 1 2 3 l[2]:`hi / throws a type error / this makes sense in the context of lists as table columns (more later) / For a nested list we can index at depth l:((1;2;3);(4;5;6);(7;8;9)) l[1;1] / => 5 / We can elide the indexes to return entire rows or columns l[;1] / => 2 5 8 l[1;] / => 4 5 6 / All the functions mentioned in the previous section work on lists natively 1+(1;2;3) / => 2 3 4 (single variable and list) (1;2;3) - (3;2;1) / => -2 0 2 (list and list) / And there are many more that are designed specifically for lists avg 1 2 3 / => 2f sum 1 2 3 / => 6 sums 1 2 3 / => 1 3 6 (running sum) last 1 2 3 / => 3 1 rotate 1 2 3 / => 2 3 1 / etc. / Using and combining these functions to manipulate lists is where much of the / power and expressiveness of the language comes from / Take (#), drop (_) and find (?) are also useful working with lists l:1 2 3 4 5 6 7 8 9 l:1+til 9 / til is a useful shortcut for generating ranges / take the first 5 elements 5#l / => 1 2 3 4 5 / drop the first 5 5_l / => 6 7 8 9 / take the last 5 -5#l / => 5 6 7 8 9 / drop the last 5 -5_l / => 1 2 3 4 / find the first occurrence of 4 l?4 / => 3 l[3] / => 4 / Dictionaries in q are a generalization of lists / they map a list to another list (of equal length) / the bang (!) symbol is used for defining a dictionary d:(`a;`b;`c)!(1;2;3) / or more simply with concise list syntax d:`a`b`c!1 2 3 / the keyword key returns the first list key d / => `a`b`c / and value the second value d / => 1 2 3 / Indexing is identical to lists / with the first list as a key instead of the position d[`a] / => 1 d[`b] / => 2 / As is assignment d[`c]:4 d / => a| 1 / => b| 2 / => c| 4 / Arithmetic and comparison work natively, just like lists e:(`a;`b;`c)!(2;3;4) d+e / => a| 3 / => b| 5 / => c| 8 d-2 / => a| -1 / => b| 0 / => c| 2 d > (1;1;1) / => a| 0 / => b| 1 / => c| 1 / And the take, drop and find operators are remarkably similar too `a`b#d / => a| 1 / => b| 2 `a`b _ d / => c| 4 d?2 / => `b / Tables in q are basically a subset of dictionaries / a table is a dictionary where all values must be lists of the same length / as such tables in q are column oriented (unlike most RDBMS) / the flip keyword is used to convert a dictionary to a table / i.e. flip the indices flip `c1`c2`c3!(1 2 3;4 5 6;7 8 9) / => c1 c2 c3 / => -------- / => 1 4 7 / => 2 5 8 / => 3 6 9 / we can also define tables using this syntax t:([]c1:1 2 3;c2:4 5 6;c3:7 8 9) t / => c1 c2 c3 / => -------- / => 1 4 7 / => 2 5 8 / => 3 6 9 / Tables can be indexed and manipulated in a similar way to dicts and lists t[`c1] / => 1 2 3 / table rows are returned as dictionaries t[1] / => c1| 2 / => c2| 5 / => c3| 8 / meta returns table type information meta t / => c | t f a / => --| ----- / => c1| j / => c2| j / => c3| j / now we see why type is enforced in lists (to protect column types) t[1;`c1]:3 t[1;`c1]:3.0 / throws a type error / Most traditional databases have primary key columns / in q we have keyed tables, where one table containing key columns / is mapped to another table using bang (!) k:([]id:1 2 3) k!t / => id| c1 c2 c3 / => --| -------- / => 1 | 1 4 7 / => 2 | 3 5 8 / => 3 | 3 6 9 / We can also use this shortcut for defining keyed tables kt:([id:1 2 3]c1:1 2 3;c2:4 5 6;c3:7 8 9) / Records can then be retrieved based on this key kt[1] / => c1| 1 / => c2| 4 / => c3| 7 kt[`id!1] / => c1| 1 / => c2| 4 / => c3| 7 //////////////////////////////////// //////// Functions //////// //////////////////////////////////// / In q the function is similar to a mathematical map, mapping inputs to outputs / curly braces {} are used for function definition / and square brackets [] for calling functions (just like list indexing) / a very minimal function f:{x+x} f[2] / => 4 / Functions can be anonymous and called at point of definition {x+x}[2] / => 4 / By default the last expression is returned / colon (:) can be used to specify return {x+x}[2] / => 4 {:x+x}[2] / => 4 / semi-colon (;) separates expressions {r:x+x;:r}[2] / => 4 / Function arguments can be specified explicitly (separated by ;) {[arg1;arg2] arg1+arg2}[1;2] / => 3 / or if omitted will default to x, y and z {x+y+z}[1;2;3] / => 6 / Built in functions are no different, and can be called the same way (with []) +[1;2] / => 3 <[1;2] / => 1b / Functions are first class in q, so can be returned, stored in lists etc. {:{x+y}}[] / => {x+y} (1;"hi";{x+y}) / => 1 / => "hi" / => {x+y} / There is no overloading and no keyword arguments for custom q functions / however using a dictionary as a single argument can overcome this / allows for optional arguments or differing functionality d:`arg1`arg2`arg3!(1.0;2;"my function argument") {x[`arg1]+x[`arg2]}[d] / => 3f / Functions in q see the global scope a:1 {:a}[] / => 1 / However local scope obscures this a:1 {a:2;:a}[] / => 2 a / => 1 / Functions cannot see nested scopes (only local and global) {local:1;{:local}[]}[] / throws error as local is not defined in inner function / A function can have one or more of its arguments fixed (projection) f:+[4] f[4] / => 8 f[5] / => 9 f[6] / => 10 //////////////////////////////////// ////////// q-sql ////////// //////////////////////////////////// / q has its own syntax for manipulating tables, similar to standard SQL / This contains the usual suspects of select, insert, update etc. / and some new functionality not typically available / q-sql has two significant differences (other than syntax) to normal SQL: / - q tables have well defined record orders / - tables are stored as a collection of columns / (so vectorized column operations are fast) / a full description of q-sql is a little beyond the scope of this intro / so we will just cover enough of the basics to get you going / First define ourselves a table t:([]name:`Arthur`Thomas`Polly;age:35 32 52;height:180 175 160;sex:`m`m`f) / equivalent of SELECT * FROM t select from t / (must be lower case, and the wildcard is not necessary) / => name age height sex / => --------------------- / => Arthur 35 180 m / => Thomas 32 175 m / => Polly 52 160 f / Select specific columns select name,age from t / => name age / => ---------- / => Arthur 35 / => Thomas 32 / => Polly 52 / And name them (equivalent of using AS in standard SQL) select charactername:name, currentage:age from t / => charactername currentage / => ------------------------ / => Arthur 35 / => Thomas 32 / => Polly 52 / This SQL syntax is integrated with the q language / so q can be used seamlessly in SQL statements select name, feet:floor height*0.032, inches:12*(height*0.032) mod 1 from t / => name feet inches / => ------------------ / => Arthur 5 9.12 / => Thomas 5 7.2 / => Polly 5 1.44 / Including custom functions select name, growth:{[h;a]h%a}[height;age] from t / => name growth / => --------------- / => Arthur 5.142857 / => Thomas 5.46875 / => Polly 3.076923 / The where clause can contain multiple statements separated by commas select from t where age>33,height>175 / => name age height sex / => --------------------- / => Arthur 35 180 m / The where statements are executed sequentially (not the same as logical AND) select from t where age<40,height=min height / => name age height sex / => --------------------- / => Thomas 32 175 m select from t where (age<40)&(height=min height) / => name age height sex / => ------------------- / The by clause falls between select and from / and is equivalent to SQL's GROUP BY select avg height by sex from t / => sex| height / => ---| ------ / => f | 160 / => m | 177.5 / If no aggregation function is specified, last is assumed select by sex from t / => sex| name age height / => ---| ----------------- / => f | Polly 52 160 / => m | Thomas 32 175 / Update has the same basic form as select update sex:`male from t where sex=`m / => name age height sex / => ---------------------- / => Arthur 35 180 male / => Thomas 32 175 male / => Polly 52 160 f / As does delete delete from t where sex=`m / => name age height sex / => -------------------- / => Polly 52 160 f / None of these sql operations are carried out in place t / => name age height sex / => --------------------- / => Arthur 35 180 m / => Thomas 32 175 m / => Polly 52 160 f / Insert however is in place, it takes a table name, and new data `t insert (`John;25;178;`m) / => ,3 t / => name age height sex / => --------------------- / => Arthur 35 180 m / => Thomas 32 175 m / => Polly 52 160 f / => John 25 178 m / Upsert is similar (but doesn't have to be in-place) t upsert (`Chester;58;179;`m) / => name age height sex / => ---------------------- / => Arthur 35 180 m / => Thomas 32 175 m / => Polly 52 160 f / => John 25 178 m / => Chester 58 179 m / it will also upsert dicts or tables t upsert `name`age`height`sex!(`Chester;58;179;`m) t upsert (`Chester;58;179;`m) / => name age height sex / => ---------------------- / => Arthur 35 180 m / => Thomas 32 175 m / => Polly 52 160 f / => John 25 178 m / => Chester 58 179 m / And if our table is keyed kt:`name xkey t / upsert will replace records where required kt upsert ([]name:`Thomas`Chester;age:33 58;height:175 179;sex:`f`m) / => name | age height sex / => -------| -------------- / => Arthur | 35 180 m / => Thomas | 33 175 f / => Polly | 52 160 f / => John | 25 178 m / => Chester| 58 179 m / There is no ORDER BY clause in q-sql, instead use xasc/xdesc `name xasc t / => name age height sex / => --------------------- / => Arthur 35 180 m / => John 25 178 m / => Polly 52 160 f / => Thomas 32 175 m / Most of the standard SQL joins are present in q-sql, plus a few new friends / see http://code.kx.com/q4m3/9_Queries_q-sql/#99-joins / the two most important (commonly used) are lj and aj / lj is basically the same as SQL LEFT JOIN / where the join is carried out on the key columns of the left table le:([sex:`m`f]lifeexpectancy:78 85) t lj le / => name age height sex lifeexpectancy / => ------------------------------------ / => Arthur 35 180 m 78 / => Thomas 32 175 m 78 / => Polly 52 160 f 85 / => John 25 178 m 78 / aj is an asof join. This is not a standard SQL join, and can be very powerful / The canonical example of this is joining financial trades and quotes tables trades:([]time:10:01:01 10:01:03 10:01:04;sym:`msft`ibm`ge;qty:100 200 150) quotes:([]time:10:01:00 10:01:01 10:01:01 10:01:03; sym:`ibm`msft`msft`ibm; px:100 99 101 98) aj[`time`sym;trades;quotes] / => time sym qty px / => --------------------- / => 10:01:01 msft 100 101 / => 10:01:03 ibm 200 98 / => 10:01:04 ge 150 / for each row in the trade table, the last (prevailing) quote (px) for that sym / is joined on. / see http://code.kx.com/q4m3/9_Queries_q-sql/#998-as-of-joins //////////////////////////////////// ///// Extra/Advanced ////// //////////////////////////////////// ////// Adverbs ////// / You may have noticed the total lack of loops to this point / This is not a mistake! / q is a vector language so explicit loops (for, while etc.) are not encouraged / where possible functionality should be vectorized (i.e. operations on lists) / adverbs supplement this, modifying the behaviour of functions / and providing loop type functionality when required / (in q functions are sometimes referred to as verbs, hence adverbs) / the "each" adverb modifies a function to treat a list as individual variables first each (1 2 3;4 5 6;7 8 9) / => 1 4 7 / each-left (\:) and each-right (/:) modify a two-argument function / to treat one of the arguments and individual variables instead of a list 1 2 3 +\: 11 22 33 / => 12 23 34 / => 13 24 35 / => 14 25 36 1 2 3 +/: 11 22 33 / => 12 13 14 / => 23 24 25 / => 34 35 36 / The true alternatives to loops in q are the adverbs scan (\) and over (/) / their behaviour differs based on the number of arguments the function they / are modifying receives. Here I'll summarise some of the most useful cases / a single argument function modified by scan given 2 args behaves like "do" {x * 2}\[5;1] / => 1 2 4 8 16 32 (i.e. multiply by 2, 5 times) {x * 2}/[5;1] / => 32 (using over only the final result is shown) / If the first argument is a function, we have the equivalent of "while" {x * 2}\[{x<100};1] / => 1 2 4 8 16 32 64 128 (iterates until returns 0b) {x * 2}/[{x<100};1] / => 128 (again returns only the final result) / If the function takes two arguments, and we pass a list, we have "for" / where the result of the previous execution is passed back into the next loop / along with the next member of the list {x + y}\[1 2 3 4 5] / => 1 3 6 10 15 (i.e. the running sum) {x + y}/[1 2 3 4 5] / => 15 (only the final result) / There are other iterators and uses, this is only intended as quick overview / http://code.kx.com/q4m3/6_Functions/#67-iterators ////// Scripts ////// / q scripts can be loaded from a q session using the "\l" command / for example "\l learnkdb.q" will load this script / or from the command prompt passing the script as an argument / for example "q learnkdb.q" ////// On-disk data ////// / Tables can be persisted to disk in several formats / the two most fundamental are serialized and splayed t:([]a:1 2 3;b:1 2 3f) `:serialized set t / saves the table as a single serialized file `:splayed/ set t / saves the table splayed into a directory / the dir structure will now look something like: / db/ / ├── serialized / └── splayed / ├── a / └── b / Loading this directory (as if it was as script, see above) / loads these tables into the q session \l . / the serialized table will be loaded into memory / however the splayed table will only be mapped, not loaded / both tables can be queried using q-sql select from serialized / => a b / => --- / => 1 1 / => 2 2 / => 3 3 select from splayed / (the columns are read from disk on request) / => a b / => --- / => 1 1 / => 2 2 / => 3 3 / see http://code.kx.com/q4m3/14_Introduction_to_Kdb+/ for more ////// Frameworks ////// / kdb+ is typically used for data capture and analysis. / This involves using an architecture with multiple processes / working together. kdb+ frameworks are available to streamline the setup / and configuration of this architecture and add additional functionality / such as disaster recovery, logging, access, load balancing etc. / https://github.com/DataIntellectTech/TorQ ``` ## Want to know more? * [*q for mortals* q language tutorial](http://code.kx.com/q4m3/) * [*Introduction to Kdb+* on disk data tutorial](http://code.kx.com/q4m3/14_Introduction_to_Kdb+/) * [q language reference](https://code.kx.com/q/ref/) * [TorQ production framework](https://github.com/DataIntellectTech/TorQ) ================================================ FILE: ko/bash.md ================================================ --- contributors: - ["Max Yankov", "https://github.com/golergka"] - ["Darren Lin", "https://github.com/CogBear"] - ["Alexandre Medeiros", "http://alemedeiros.sdf.org"] - ["Denis Arh", "https://github.com/darh"] - ["akirahirose", "https://twitter.com/akirahirose"] - ["Anton Strömkvist", "http://lutic.org/"] - ["Rahil Momin", "https://github.com/iamrahil"] - ["Gregrory Kielian", "https://github.com/gskielian"] - ["Etan Reisner", "https://github.com/deryni"] - ["Jonathan Wang", "https://github.com/Jonathansw"] - ["Leo Rudberg", "https://github.com/LOZORD"] - ["Betsy Lorton", "https://github.com/schbetsy"] - ["John Detter", "https://github.com/jdetter"] translators: - ["Wooseop Kim", "https://github.com/linterpreteur"] --- Bash는 유닉스 셸의 이름이며, 리눅스와 맥 OS X의 기본 셸로 그리고 GNU 운영체제를 위한 셸로서 배포되었습니다. 이하의 거의 모든 예시들은 셸 스크립트의 일부이거나 셸에서 바로 실행할 수 있습니다. ```bash #!/bin/bash # 스크립트의 첫 줄은 시스템에게 스크립트의 실행법을 알려주는 '셔뱅'입니다. # https://ko.wikipedia.org/wiki/%EC%85%94%EB%B1%85 # 이미 보았듯이 주석은 #으로 시작합니다. 셔뱅 또한 주석입니다. # 간단한 헬로 월드 echo 헬로 월드! # 각각의 명령어는 개행 혹은 세미콜론 이후에 시작됩니다. echo '첫번째 줄'; echo '두번째 줄' # 변수 선언은 다음과 같습니다. Variable="어떤 문자열" # 하지만 다음은 틀린 형태입니다. Variable = "어떤 문자열" # Bash는 Variable이 실행해야 하는 명령어라고 판단할 것이고, 해당 명령어를 찾을 # 수 없기 때문에 에러를 발생시킬 것입니다. # 다음도 같습니다. Variable= '어떤 문자열' # Bash는 '어떤 문자열'이 실행해야 하는 명령어라고 판단하여 에러를 발생시킬 것입니다. # (이 경우에 'Variable=' 부분은 '어떤 문자열' 명령어의 스코프에서만 유효한 # 변수 할당으로 해석됩니다.) # 변수 사용은 다음과 같습니다. echo $Variable echo "$Variable" echo '$Variable' # 할당, 내보내기 등 변수 자체를 사용할 때에는 $ 없이 이름을 적습니다. # 변수의 값을 사용할 때에는 $를 사용해야 합니다. # 작은 따옴표는 변수를 확장시키지 않는다는 사실에 주의하세요. # (역자 주: '$Variable'은 변수 Variable의 값이 아닌 문자열 "$Variable"입니다.) # 인수 확장은 ${ }입니다. echo ${Variable} # 이는 인수 확장의 간단한 예시입니다. # 인수 확장은 변수로부터 값을 받아 그 값을 "확장"하거나 출력합니다. # 확장을 통해 인수나 그 값이 변경될 수 있습니다. # 이하는 확장에 대한 다른 예시들입니다. # 변수에서의 문자열 치환 echo ${Variable/Some/A} # 처음으로 나타나는 "Some"를 "A"로 치환합니다. # 변수의 부분열 Length=7 echo ${Variable:0:Length} # 변수 값에서 처음 7개 문자만을 반환합니다. # 변수의 기본값 echo ${Foo:-"Foo가_없거나_비어_있을_때의_기본값"} # null(Foo=) 값이나 빈 문자열(Foo="")일 경우에만 작동합니다. 0은 (Foo=0)은 0입니다. # 기본값을 반환할 뿐 변수 값을 변경하지는 않는다는 사실에 주목하세요. # 중괄호 확장 { } # 임의의 문자열을 생성합니다. echo {1..10} echo {a..z} # 시작 값으로부터 끝 값까지의 범위를 출력합니다. # 내장 변수 # 유용한 내장 변수들이 있습니다. echo "마지막 프로그램의 반환값: $?" echo "스크립트의 PID: $$" echo "스크립트에 넘겨진 인자의 개수: $#" echo "스크립트에 넘겨진 모든 인자: $@" echo "각각 변수로 쪼개진 스크립트 인자: $1 $2..." # echo와 변수의 사용법을 알게 되었으니, # bash의 기초를 조금 더 배워봅시다! # 현재 디렉토리는 `pwd` 명령어로 알 수 있습니다. # `pwd`는 "print working directory(작업 디렉토리 출력)"의 약자입니다. # 내장 변수`$PWD`를 사용할 수도 있습니다. # 이하는 모두 동일합니다. echo "I'm in $(pwd)" # `pwd`를 실행하여 문자열에 보간 echo "I'm in $PWD" # 변수를 보간 # 터미널이나 결과의 출력물이 너무 많다면 # 명령어 `clear`를 이용해 화면을 지울 수 있습니다. clear # 컨트롤+L 또한 화면을 지울 수 있습니다. # 입력 값 읽기 echo "이름이 뭐에요?" read Name # 변수 선언이 필요 없다는 데 주목하세요. echo $Name님, 안녕하세요! # 평범한 if 구조도 있습니다. # 'man test'로 조건문에 대해 더 알아보세요. if [ $Name != $USER ] then echo "사용자가 아닙니다." else echo "사용자입니다." fi # $Name이 비어 있다면, bash는 위의 조건을 다음과 같이 인식합니다. if [ != $USER ] # 이는 문법적으로 유효하지 않습니다. # 따라서 bash에서 비어 있을 수 있는 변수를 "안전하게" 사용하는 법은 다음과 같습니다. if [ "$Name" != $USER ] ... # $Name이 비어 있다면 bash는 if [ "" != $USER ] ... # 와 같이 인식하여 예상한 대로 동작합니다. # 조건부 실행도 있습니다. echo "항상 실행" || echo "첫 명령어가 실패해야 실행" echo "항상 실행" && echo "첫 명령어가 실패하지 않아야 실행" # if문과 함께 &&와 ||을 사용하려면, 대괄호가 여러 쌍 필요합니다. if [ "$Name" == "철수" ] && [ "$Age" -eq 15 ] then echo "$Name이 철수이고 $Age가 15일 때 실행" fi if [ "$Name" == "민희" ] || [ "$Name" == "상민" ] then echo "$Name이 민희이거나 상민일 때 실행" fi # 표현식은 다음 형식으로 표기됩니다. echo $(( 10 + 5 )) # 다른 프로그래밍 언어와는 달리, bash는 셸이기 때문에 현재 디렉토리의 컨텍스트에서 # 실행됩니다. 현재 디렉토리의 파일과 디렉토리를 ls 명령어로 나열할 수 있습니다. ls # 다음은 실행을 제어하는 옵션의 예시입니다. ls -l # 모든 파일과 디렉토리를 분리된 줄에 나열 ls -t # 디렉토리 내용을 마지막으로 수정된 날짜(내림차순)에 따라 정렬 ls -R # 이 디렉토리와 그 안의 모든 디렉토리에 대해 재귀적으로 `ls` 실행 # 이전 명령어의 결과는 다음 명령어에 입력될 수 있습니다. # grep 명령어는 입력을 주어진 패턴에 따라 필터링합니다. 다음은 현재 디렉토리의 # .txt 파일을 나열하는 방법입니다. ls -l | grep "\.txt" # `cat`을 이용해 stdout으로 파일을 출력합니다. cat file.txt # `cat`으로 파일을 읽을 수도 있습니다. Contents=$(cat file.txt) echo "파일 시작\n$Contents\n파일 끝" # `cp`를 이용해 파일이나 디렉토리를 다른 곳으로 복사할 수 있습니다. # `cp`는 원본의 새로운 버전을 생성하므로 사본을 편집하는 것은 # 원본에 영향을 주지 않으며 그 반대도 마찬가지입니다. # 목표 위치에 이미 파일이 있다면 덮어쓰게 됩니다. cp srcFile.txt clone.txt cp -r srcDirectory/ dst/ # 재귀적으로 복사 # 컴퓨터 간에 파일을 공유하려고 한다면 `scp` 혹은 `sftp`를 사용합니다. # `scp`는 `cp`와 매우 유사하게 동작하며 # `sftp`는 더 상호작용적입니다. # `mv`로 파일 혹은 디렉토리를 다른 곳으로 이동합니다. # `mv`는 `cp`와 유사하지만 원본을 삭제합니다. # 또한 `mv`로 파일의 이름을 바꿀 수도 있습니다. mv s0urc3.txt dst.txt # sorry, l33t hackers... # bash는 현재 디렉토리의 컨텍스트에서 실행되기 때문에, 다른 디렉토리에서 명령어를 # 실행하고 싶으실 수 있습니다. cd를 이용해 위치를 변경합니다. cd ~ # 홈 디렉토리로 변경 cd .. # 한 디렉토리 위로 이동 # (즉 /home/username/Downloads에서 /home/username로) cd /home/username/Documents # 특정 디렉토리로 이동 cd ~/Documents/.. # 아직도 홈 디렉토리... 아닌가?? # 서브셸로 디렉토리를 넘어서 작업할 수도 있습니다. (echo "처음엔 여기 $PWD") && (cd 어딘가; echo "이제는 여기 $PWD") pwd # 아직도 첫 디렉토리에 있음 # `mkdir`로 새 디렉토리를 만듭니다. mkdir myNewDir # `-p` 플래그는 필요하다면 해당 디렉토리의 경로 중간에 있는 디렉토리를 생성합니다. mkdir -p myNewDir/with/intermediate/directories # (stdin, stdout, stderr로) 명령어의 입출력을 리디렉션할 수 있습니다. # stdin의 내용을 ^EOF$까지 읽고 hello.py에 그 내용을 덮어씁니다. cat > hello.py << EOF #!/usr/bin/env python from __future__ import print_function import sys print("#stdout", file=sys.stdout) print("#stderr", file=sys.stderr) for line in sys.stdin: print(line, file=sys.stdout) EOF # stdin, stdoutk, stderr을 다양한 방법으로 리디렉션하여 hello.py를 실행합니다. python hello.py < "input.in" python hello.py > "output.out" python hello.py 2> "error.err" python hello.py > "output-and-error.log" 2>&1 python hello.py > /dev/null 2>&1 # 출력 오류는 이미 파일이 있을 경우 덮어쓰지만, # 덮어쓰는 대신에 내용에 추가하고 싶다면 ">>"를 사용합니다. python hello.py >> "output.out" 2>> "error.err" # output.out에 덮어쓰고, error.err에 추가하고, 줄을 세기 info bash 'Basic Shell Features' 'Redirections' > output.out 2>> error.err wc -l output.out error.err # 명령어를 실행하고 그 파일 디스크립터를 출력 (예: /dev/fd/123) # man fd 참고 echo <(echo "#helloworld") # output.out을 "#helloworld"으로 덮어쓰기 cat > output.out <(echo "#helloworld") echo "#helloworld" > output.out echo "#helloworld" | cat > output.out echo "#helloworld" | tee output.out >/dev/null # 임시 파일을 지울 수 있습니다. ('-i'로 대화식 실행) # 경고: `rm` 명령어는 되돌릴 수 없습니다. rm -v output.out error.err output-and-error.log rm -r tempDir/ # 재귀적으로 삭제 # 다른 명령어에서 $()을 이용해 명령어를 치환할 수도 있습니다. # 다음 명령어는 현재 디렉토리의 파일 및 디렉토리의 수를 표시합니다. echo "$(ls | wc -l)개 항목이 있습니다." # 백틱(``)을 이용할 수도 있지만 이 방식을 이용하면 중첩할 수 없기 때문에 # $()을 사용하는 것이 더 좋습니다. echo "`ls | wc -l`개 항목이 있습니다." # 자바나 C++의 switch와 비슷하게 동작하는 case 문을 사용할 수 있습니다. case "$Variable" in # 충족시킬 조건을 나열 0) echo "0입니다.";; 1) echo "1입니다.";; *) echo "널이 아닌 값입니다.";; esac # for 반복문은 주어진 인자만큼 반복합니다. # 다음은 $Variable을 세 번 출력합니다. for Variable in {1..3} do echo "$Variable" done # 혹은 "전통적인 for 반복문" 방식을 쓸 수도 있습니다. for ((a=1; a <= 3; a++)) do echo $a done # 파일에도 적용될 수 있습니다. # 다음은 file1과 file2에 'cat' 명령어를 실행합니다. for Variable in file1 file2 do cat "$Variable" done # 혹은 명령어의 결과에도 이용할 수 있습니다. # 다음은 ls의 결과를 cat합니다. for Output in $(ls) do cat "$Output" done # while 반복문 while [ true ] do echo "반복문 몸체" break done # 함수를 정의할 수도 있습니다. # 정의: function foo () { echo "인자는 함수 인자처럼 작동합니다. $@" echo "그리고 $1 $2..." echo "함수입니다." return 0 } # 혹은 단순하게 bar () { echo "함수를 선언하는 다른 방법" return 0 } # 함수 호출 foo "My name is" $Name # 몇 가지 유용한 명령어를 알아두면 좋습니다. # file.txt의 마지막 10줄 출력 tail -n 10 file.txt # file.txt의 첫 10줄 출력 head -n 10 file.txt # file.txt 줄 별로 정렬 sort file.txt # 중복되는 줄을 생략하거나 -d를 이용하여 보고 uniq -d file.txt # ',' 문자 이전의 첫 열만 출력 cut -d ',' -f 1 file.txt # file.txt에서 'okay'를 모두 'great'로 교체 (정규식 호환) sed -i 's/okay/great/g' file.txt # file.txt에서 정규식에 맞는 모든 줄을 stdin에 출력 # 다음 예시는 "foo"로 시작해 "bar"로 끝나는 줄 출력 grep "^foo.*bar$" file.txt # "-c" 옵션을 넘겨 줄 번호를 대신 출력 grep -c "^foo.*bar$" file.txt # 다른 유용한 옵션 grep -r "^foo.*bar$" someDir/ # 재귀적으로 `grep` grep -n "^foo.*bar$" file.txt # 줄 번호 매기기 grep -rI "^foo.*bar$" someDir/ # 재귀적으로 `grep`하되 바이너리 파일은 무시 # 같은 검색으로 시작하여 "baz"를 포함하는 줄만 필터 grep "^foo.*bar$" file.txt | grep -v "baz" # 정규식이 아니라 문자열로 검색하고 싶다면 # fgrep 혹은 grep -F fgrep "foobar" file.txt # trap 명령어로 스크립트에서 신호를 받을 때 명령어를 실행할 수 있습니다. # 다음 명령어는 셋 중 한 가지 신호를 받으면 rm 명령어를 실행합니다. trap "rm $TEMP_FILE; exit" SIGHUP SIGINT SIGTERM # `sudo`를 통해 슈퍼이용자로 명령어를 실행합니다. NAME1=$(whoami) NAME2=$(sudo whoami) echo "$NAME1였다가 더 강한 $NAME2가 되었다" # 'help' 명령어로 내장 문서를 읽을 수 있습니다. help help help help for help return help source help . # man으로 매뉴얼을 읽을 수도 있습니다. apropos bash man 1 bash man bash # info 명령어로 문서를 읽습니다. (?로 도움말) apropos info | grep '^info.*(' man info info info info 5 info # bash의 info 문서를 읽어 보세요. info bash info bash 'Bash Features' info bash 6 info --apropos bash ``` [(영어) 이곳에서 더 알아보세요.](https://www.gnu.org/software/bash/manual/bashref.html) ================================================ FILE: ko/bf.md ================================================ --- filename: learnbf.bf contributors: - ["Prajit Ramachandran", "http://prajitr.github.io/"] - ["Mathias Bynens", "http://mathiasbynens.be/"] translators: - ["JongChan Choi", "http://0xABCDEF.com/"] - ["Peter Lee", "http://peterjlee.com/"] --- Brainfuck(문장을 시작하는 단어가 아닌이상 첫글자는 대문자를 사용하지 않습니다)은 여덟가지 명령어만으로 튜링-완전한 최소주의 프로그래밍 언어입니다. ```bf "><+-.,[]" 이외의 문자들은 무시됩니다. (쌍따옴표는 제외) 브레인퍽은 30,000 칸 짜리의 0으로 초기화된 배열과, 현재 칸을 가르키는 포인터로 표현됩니다. 여덟가지의 명령어는 다음과 같습니다: + : 포인터가 가르키는 현재 칸의 값을 1 증가시킵니다. - : 포인터가 가르키는 현재 칸의 값을 1 감소시킵니다. > : 포인터가 다음 칸(오른쪽 칸)을 가르키도록 이동시킵니다. < : 포인터가 이전 칸(왼쪽 칸)을 가르키도록 이동시킵니다. . : 현재 칸의 값을 ASCII 문자로 출력합니다. (즉, 65 = 'A') , : 하나의 문자를 입력받고 그 값을 현재 칸에 대입합니다. [ : 현재 칸의 값이 0이면 짝이 맞는 ] 명령으로 넘어갑니다. 0이 아니면 다음 명령어로 넘어갑니다. ] : 현재 칸의 값이 0이면 다음 명령어로 넘어갑니다. 0이 아니면 짝이 맞는 [ 명령으로 다시 돌아갑니다. [이랑 ]은 while 루프를 만들어냅니다. 무조건, 짝이 맞아야 합니다. 몇가지 간단한 브레인퍽 프로그램을 보겠습니다. ++++++ [ > ++++++++++ < - ] > +++++ . 이 프로그램은 문자 'A'를 출력합니다. 처음에는, 반복할 횟수를 정하기 위한 값을 만들기 위해 첫번째 칸의 값을 6으로 증가시킵니다. 그리고 루프로 들어가서([) 두번째 칸으로 넘어갑니다. 루프 안에서는 두번째 칸의 값을 10 증가시키고, 다시 첫번째 칸으로 넘어가서 값을 1 감소시킵니다. 이 루프는 여섯번 돕니다. (첫번째 칸의 값을 6번 감소시켜서 0이 될 때 까지는 ] 명령을 만날 때마다 루프의 시작 지점으로 돌아갑니다) 이 시점에서, 두번째 칸의 값은 60이고, 포인터는 값이 0인 첫번째 칸에 위치합니다. 여기서 두번째 칸으로 넘어간 다음 값을 5 증가시키면 두번째 칸의 값이 65가 되고, 65는 문자 'A'에 대응하는 아스키 코드이기 때문에, 두번째 칸의 값을 출력하면 터미널에 'A'가 출력됩니다. , [ > + < - ] > . 이 프로그램은 사용자로부터 문자 하나를 입력받아 첫번째 칸에 집어넣습니다. 그리고 루프에 들어가서, 두번째 칸으로 넘어가 값을 한 번 증가시킨 다음, 다시 첫번째 칸으로 넘어가서 값을 한 번 감소시킵니다. 이는 첫번째 칸의 값이 0이 될 때까지 지속되며, 두번째 칸은 첫번째 칸이 갖고있던 값을 가지게 됩니다. 루프가 종료되면 포인터는 첫번째 칸을 가르키기 때문에 두번째 칸으로 넘어가고, 해당 아스키 코드에 대응하는 문자를 출력합니다. 또한 공백문자는 순전히 가독성을 위해서 작성되었다는 것을 기억하세요. 다음과 같이 작성해도 똑같이 돌아갑니다: ,[>+<-]>. 한 번 돌려보고 아래의 프로그램이 실제로 무슨 일을 하는지 맞춰보세요: ,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >> 이 프로그램은 두 개의 숫자를 입력받은 뒤, 그 둘을 곱합니다. 위 코드는 일단 두 번의 입력을 받고, 첫번째 칸의 값만큼 바깥 루프를 돕니다. 그리고 루프 안에서 다시 두번째 칸의 값만큼 안쪽의 루프를 돕니다. 그리고 그 루프에서는 세번째 칸의 값을 증가시키는데, 문제가 하나 있습니다: 내부 루프가 한 번 끝나게 되면 두번째 칸의 값은 0이 됩니다. 그럼 다시 바깥 루프를 돌 때에 안쪽의 루프를 돌지 않게 되는데, 이를 해결하려면 네번째 칸의 값도 같이 증가시킨 다음, 그 값을 두번째 칸으로 옮기면 됩니다. 그러면 세번째 칸에 곱셈의 결과가 남습니다. ``` 여기까지 브레인퍽이었습니다. 참 쉽죠? 재미삼아 브레인퍽 프로그램이나 다른 언어로 브레인퍽 인터프리터를 작성해보세요. 인터프리터 구현은 간단한 편인데, 사서 고생하는 것을 즐기는 편이라면 한 번 작성해보세요… 브레인퍽으로. ================================================ FILE: ko/clojure-macros.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] translators: - ["Eunpyoung Kim", "https://github.com/netpyoung"] --- 다른 모든 Lisp와 마찬가지로, Clojure가 가진 [동형성(homoiconicity)](https://en.wikipedia.org/wiki/Homoiconic)은 "매크로"라고 불리는 코드 생성 루틴을 작성할 수 있도록 언어의 전체적인 범위에 접근할 수 있게 해줍니다. 매크로는 필요에 맞게 언어를 바꿀 수 있는 강력한 방법을 제공합니다. 주의하시기 바랍니다. 함수로도 충분히 해결할 수 있는 문제를 매크로로 작성하게 된다면, 좋은 코드라고 할 수 없습니다. 인자가 평가되는 시점을 제어해야 할 때만 매크로를 사용하는게 좋습니다. Clojure랑 친해지면 쉽게 따라갈 수 있습니다. [Clojure in Y Minutes](../clojure/)를 한번 읽어보세요. ```clojure ;; defmacro로 매크로를 정의합니다. ;; 매크로는 clojure 코드로 평가될 수 있는 리스트를 반환해야 합니다. ;; ;; 다음 매크로는 (reverse "Hello World") 라고 쓴 것과 같습니다. (defmacro my-first-macro [] (list reverse "Hello World")) ;; macroexpand나 macroexpand-1을 사용해서 매크로의 결과를 확인할 수 있습니다. ;; ;; 호출하는 부분이 '(quote)된 것을 주목합니다. (macroexpand '(my-first-macro)) ;; -> (# "Hello World") ;; macroexpand의 결과를 바로 평가할 수 있습니다. (eval (macroexpand '(my-first-macro))) ; -> (\d \l \o \r \W \space \o \l \l \e \H) ;; 하지만, 함수와 같이 좀 더 간결한 구문을 이용하는게 좋습니다: (my-first-macro) ; -> (\d \l \o \r \W \space \o \l \l \e \H) ;; 더 간결한 quote 구문 ( ' )을 이용하여, 보다 편리하게 매크로 안에서 리스트를 만들 수 있습니다: (defmacro my-first-quoted-macro [] '(reverse "Hello World")) (macroexpand '(my-first-quoted-macro)) ;; -> (reverse "Hello World") ;; reverse는 더 이상 함수 객체가 아니라 심볼이라는 것에 주목하세요. ;; 매크로는 인자를 받을 수 있습니다. (defmacro inc2 [arg] (list + 2 arg)) (inc2 2) ; -> 4 ;; 하지만, quote된 리스트를 사용하면 에러가 발생합니다. ;; 인자도 quote되기 때문입니다. ;; 이를 해결하기 위해, clojure는 매크로를 quote할 수 있는 방법을 제공합니다: `. ;; ` 안에서 ~를 사용하면 외부 스코프에 접근할 수 있습니다. (defmacro inc2-quoted [arg] `(+ 2 ~arg)) (inc2-quoted 2) ;; destructuring args도 사용할 수 있습니다. ~@를 사용하여 리스트 변수를 확장할 수 있습니다. (defmacro unless [arg & body] `(if (not ~arg) (do ~@body))) ; do를 빼먹지 마세요! (macroexpand '(unless true (reverse "Hello World"))) ;; -> ;; (if (clojure.core/not true) (do (reverse "Hello World"))) ;; (unless)는 첫 번째 인자가 false일 때, body를 평가하고 반환합니다. ;; 그렇지않으면, nil을 반환합니다. (unless true "Hello") ; -> nil (unless false "Hello") ; -> "Hello" ;; 주의하지 않으면, 매크로는 변수를 덮어쓰는 등 큰 문제를 일으킬 수 있습니다. (defmacro define-x [] '(do (def x 2) (list x))) (def x 4) (define-x) ; -> (2) (list x) ; -> (2) ;; 이를 피하기 위해, gensym을 이용하여 고유한 식별자를 얻을 수 있습니다. (gensym 'x) ; -> x1281 (혹은 다른 식별자) (defmacro define-x-safely [] (let [sym (gensym 'x)] `(do (def ~sym 2) (list ~sym)))) (def x 4) (define-x-safely) ; -> (2) (list x) ; -> (4) ;; ` 안에서 #를 사용하면 자동으로 각 심볼에 대한 gensym을 생성할 수 있습니다. (defmacro define-x-hygienically [] `(do (def x# 2) (list x#))) (def x 4) (define-x-hygienically) ; -> (2) (list x) ; -> (4) ;; 매크로를 만들 때는 보통 헬퍼 함수를 많이 이용합니다. ;; 인라인 산술 문법을 지원하는 몇 개의 헬퍼 함수를 만들어 봅시다. (declare inline-2-helper) (defn clean-arg [arg] (if (seq? arg) (inline-2-helper arg) arg)) (defn apply-arg "Given args [x (+ y)], return (+ x y)" [val [op arg]] (list op val (clean-arg arg))) (defn inline-2-helper [[arg1 & ops-and-args]] (let [ops (partition 2 ops-and-args)] (reduce apply-arg (clean-arg arg1) ops))) ;; 매크로를 만들지 않고, 바로 테스트해볼 수 있습니다. (inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5)) ; 하지만, 이 함수를 컴파일 타임에 실행하려면 매크로로 만들어야 합니다. (defmacro inline-2 [form] (inline-2-helper form)) (macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1))) ; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1) (inline-2 (1 + (3 / 2) - (1 / 2) + 1)) ; -> 3 (실제로는 3N이라는 결과가 나옵니다. / 연산자를 사용하면 숫자가 유리수로 캐스팅되기 때문입니다.) ``` ### 더 읽어볼거리 - [Writing Macros](http://www.braveclojure.com/writing-macros/) - [Official docs](http://clojure.org/macros) - [When to use macros?](https://lispcast.com/when-to-use-a-macro/) ================================================ FILE: ko/clojure.md ================================================ --- contributors: - ["Adam Bard", "http://adambard.com/"] translators: - ["netpyoung", "http://netpyoung.github.io/"] --- Clojure는 Java 가상머신을 위해 개발된 Lisp 계통의 언어입니다 이는 Common Lisp보다 순수 [함수형 프로그래밍](https://en.wikipedia.org/wiki/Functional_programming)을 더욱 강조했으며, 상태를 있는 그대로 다루기 위해 다양한 [STM](https://en.wikipedia.org/wiki/Software_transactional_memory) 을 지원하는 프로그램들을 갖췄습니다. 이를 조합하여, 병행처리(concurrent processing)를 매우 단순하게 처리할 수 있으며, 대게 자동으로 처리될 수 있도록 만들 수 있습니다. (Clojure 1.2 이상의 버전이 필요로 합니다.) ```clojure ; 주석은 세미콜론(;)으로 시작합니다. ; Clojure는 "폼(forms)"으로 구성되었으며, ; 폼은 괄호로 감싸져있으며, 공백으로 구분된 것들이 나열된 것입니다. ; ; clojure의 reader는 첫번째로 오는 것을 ; 함수 혹은 매크로를 호출하는 것, 그리고 나머지를 인자라고 가정합니다. ; namespace를 지정하기 위해, 파일에서 우선적으로 호출해야될 것은 ns입니다. (ns learnclojure) ; 간단한 예제들: ; str 은 인자로 받은 것들을 하나의 문자열로 만들어줍니다. (str "Hello" " " "World") ; => "Hello World" ; 직관적인 수학 함수들을 갖고 있습니다. (+ 1 1) ; => 2 (- 2 1) ; => 1 (* 1 2) ; => 2 (/ 2 1) ; => 2 ; = 로 동일성을 판별할 수 있습니다. (= 1 1) ; => true (= 2 1) ; => false ; 논리연산을 위한 not 역시 필요합니다. (not true) ; => false ; 중첩된 폼(forms)은 기대한대로 동작합니다. (+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2 ; 타입 ;;;;;;;;;;;;; ; Clojure는 부울(boolean), 문자열, 숫자를 위해 Java의 object 타입을 이용합니다. ; `class` 를 이용하여 이를 확인할 수 있습니다. (class 1) ; 정수는 기본적으로 java.lang.Long입니다. (class 1.); 소수는 java.lang.Double입니다. (class ""); 문자열은 쌍따옴표로 감싸져 있으며, java.lang.String입니다. (class false) ; 부울값은 java.lang.Boolean입니다. (class nil); nil은 "null"값입니다. ; 데이터 리스트 자체를 만들고자 한다면, ; '를 이용하여 평가(evaluate)되지 않도록 막아야 합니다. '(+ 1 2) ; => (+ 1 2) ; (quote (+ 1 2)) 를 줄여서 쓴것 ; quote 가 된 리스트를 평가할 수 도 있습니다. (eval '(+ 1 2)) ; => 3 ; 컬렉션(Collections) & 시퀀스(Sequences) ;;;;;;;;;;;;;;;;;;; ; 리스트(List)는 연결된(linked-list) 자료구조이며, 벡터(Vector)는 배열이 뒤로붙는(array-backed) 자료구조입니다. ; 리스트와 벡터 모두 java 클래스입니다! (class [1 2 3]); => clojure.lang.PersistentVector (class '(1 2 3)); => clojure.lang.PersistentList ; 간단하게 (1 2 3)로 리스트를 나타낼 수 있지만, ; reader가 함수라고 여기지 못하게 quote(')를 해줘야 합니다. ; 따라서, (list 1 2 3)는 '(1 2 3)와 같습니다. ; "컬렉션"은 단순하게 데이터의 그룹입니다. ; 리스트와 벡터 모두 컬렉션입니다: (coll? '(1 2 3)) ; => true (coll? [1 2 3]) ; => true ; "시퀀스" (seq) 는 데이터 리스트를 추상적으로 기술한 것입니다. ; 리스트는 시퀀스입니다. (seq? '(1 2 3)) ; => true (seq? [1 2 3]) ; => false ; 시퀀스는 접근하고자 하는 항목만 제공해주면 됩니다. ; 따라서, 시퀀스는 lazy 할 수 있습니다 -- 무한하게 늘어나는 것을 정의할 수 있습니다: (range 4) ; => (0 1 2 3) (range) ; => (0 1 2 3 4 ...) (an infinite series) (take 4 (range)) ; (0 1 2 3) ; cons 를 이용하여 리스트나 벡터의 시작부에 항목을 추가할 수 있습니다. (cons 4 [1 2 3]) ; => (4 1 2 3) (cons 4 '(1 2 3)) ; => (4 1 2 3) ; conj 는 컬렉션에 가장 효율적인 방식으로 항목을 추가합니다. ; 리스트는 시작부분에 삽입하고, 벡터는 끝부분에 삽입합니다. (conj [1 2 3] 4) ; => [1 2 3 4] (conj '(1 2 3) 4) ; => (4 1 2 3) ; concat 을 이용하여 리스트와 벡터를 서로 합칠 수 있습니다. (concat [1 2] '(3 4)) ; => (1 2 3 4) ; filter, map 을 이용하여 컬렉션을 다룰 수 있습니다. (map inc [1 2 3]) ; => (2 3 4) (filter even? [1 2 3]) ; => (2) ; reduce 를 이용하여 줄여나갈 수 있습니다. (reduce + [1 2 3 4]) ; = (+ (+ (+ 1 2) 3) 4) ; => 10 ; reduce 는 초기 값을 인자로 취할 수 도 있습니다. (reduce conj [] '(3 2 1)) ; = (conj (conj (conj [] 3) 2) 1) ; => [3 2 1] ; 함수 ;;;;;;;;;;;;;;;;;;;;; ; fn 을 이용하여 함수를 만들 수 있습니다 . ; 함수는 항상 마지막 문장을 반환합니다. (fn [] "Hello World") ; => fn ; (정의한 것을 호출하기 위해선, 괄호가 더 필요합니다.) ((fn [] "Hello World")) ; => "Hello World" ; def 를 이용하여 var 를 만들 수 있습니다. (def x 1) x ; => 1 ; var 에 함수를 할당시켜보겠습니다. (def hello-world (fn [] "Hello World")) (hello-world) ; => "Hello World" ; defn 을 이용하여 짧게 쓸 수 도 있습니다. (defn hello-world [] "Hello World") ; [] 는 함수의 인자 목록을 나타냅니다. (defn hello [name] (str "Hello " name)) (hello "Steve") ; => "Hello Steve" ; 약자(shorthand)를 써서 함수를 만들 수 도 있습니다: (def hello2 #(str "Hello " %1)) (hello2 "Fanny") ; => "Hello Fanny" ; 함수가 다양한 인자를 받도록 정의할 수 도 있습니다. (defn hello3 ([] "Hello World") ([name] (str "Hello " name))) (hello3 "Jake") ; => "Hello Jake" (hello3) ; => "Hello World" ; 함수는 여러 인자를 시퀀스로 취할 수 있습니다. (defn count-args [& args] (str "You passed " (count args) " args: " args)) (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" ; 개별적으로 받는 것과, 시퀀스로 취하는 것을 같이 쓸 수 도 있습니다. (defn hello-count [name & args] (str "Hello " name ", you passed " (count args) " extra args")) (hello-count "Finn" 1 2 3) ; => "Hello Finn, you passed 3 extra args" ; 맵(Maps) ;;;;;;;;;; ; 해쉬맵(hash map)과 배열맵(array map)은 공통된 인터페이스를 공유합니다. ; 해쉬맵은 찾기가 빠르지만, 키의 순서가 유지되지 않습니다. (class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap (class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap ; 배열맵은 여러 연산을 거쳐 자연스레 해쉬맵이 됩니다. ; 만일 이게 커진다 하더라도, 걱정할 필요가 없습니다. ; 맵은 해쉬가 가능한 타입이라면 어떠한 것이든 키로써 활용이 가능하지만, 보통 키워드를 이용하는 것이 가장 좋습니다. ; 키워드(Keyword)는 문자열과 비슷하지만, 보다 효율적인 면이 있습니다. (class :a) ; => clojure.lang.Keyword (def stringmap {"a" 1, "b" 2, "c" 3}) stringmap ; => {"a" 1, "b" 2, "c" 3} (def keymap {:a 1, :b 2, :c 3}) keymap ; => {:a 1, :c 3, :b 2} ; 여기서, 쉽표가 공백으로 취급되며, 아무 일도 하지 않는다는 것을 주목하시기 바랍니다. ; 맵에서 값을 얻어오기 위해선, 함수로써 맵을 호출해야 합니다. (stringmap "a") ; => 1 (keymap :a) ; => 1 ; 키워드 역시 맵에서 함수를 얻어올 때 사용할 수 있습니다! (:b keymap) ; => 2 ; 하지만, 문자열로는 하면 안됩니다. ;("a" stringmap) ; => Exception: java.lang.String cannot be cast to clojure.lang.IFn ; 없는 값을 얻어오고자 하면, nil이 반환됩니다. (stringmap "d") ; => nil ; assoc 를 이용하여 해쉬맵에 새로운 키를 추가할 수 있습니다. (def newkeymap (assoc keymap :d 4)) newkeymap ; => {:a 1, :b 2, :c 3, :d 4} ; 하지만, 변경할 수 없는(immutable) clojure 타입이라는 것을 기억해야 합니다! keymap ; => {:a 1, :b 2, :c 3} ; dissoc 를 이용하여 키를 제거할 수 있습니다. (dissoc keymap :a :b) ; => {:c 3} ; 쎗(Set:집합) ;;;;;; (class #{1 2 3}) ; => clojure.lang.PersistentHashSet (set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3} ; conj 로 항목을 추가할 수 있습니다. (conj #{1 2 3} 4) ; => #{1 2 3 4} ; disj 로 제거할 수 도 있습니다. (disj #{1 2 3} 1) ; => #{2 3} ; 존재하는지 확인할 목적으로, 쎗을 함수로 사용할 수 도 있습니다. (#{1 2 3} 1) ; => 1 (#{1 2 3} 4) ; => nil ; clojure.sets 네임스페이스(namespace)에는 더 많은 함수들이 있습니다. ; 유용한 폼(forms) ;;;;;;;;;;;;;;;;; ; clojure에선, if 와 매크로(macro)를 가지고, ; 다른 여러 논리 연산들을 만들 수 있습니다. (if false "a" "b") ; => "b" (if false "a") ; => nil ; let 을 이용하여 임시적으로 바인딩(binding)을 구축할 수 있습니다. (let [a 1 b 2] (> a b)) ; => false ; do 로 문단을 묶을 수 도 있습니다. (do (print "Hello") "World") ; => "World" (prints "Hello") ; 함수는 암시적으로 do 를 가지고 있습니다. (defn print-and-say-hello [name] (print "Saying hello to " name) (str "Hello " name)) (print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff") ; let 역시 그러합니다. (let [name "Urkel"] (print "Saying hello to " name) (str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel") ; 모듈(Modules) ;;;;;;;;;;;;;;; ; "use" 를 이용하여 module에 있는 모든 함수들을 얻어올 수 있습니다. (use 'clojure.set) ; 이제 쎗(set:집합)연산을 사용 할 수 있습니다. (intersection #{1 2 3} #{2 3 4}) ; => #{2 3} (difference #{1 2 3} #{2 3 4}) ; => #{1} ; 함수들 중에 일 부분만을 가져올 수 도 있습니다. (use '[clojure.set :only [intersection]]) ; require 를 이용하여 모듈을 import할 수 있습니다. (require 'clojure.string) ; / 를 이용하여 모듈에 있는 함수를 호출 할 수 있습니다. ; 여기, clojure.string 라는 모듈에, blank? 라는 함수가 있습니다. (clojure.string/blank? "") ; => true ; import시, 모듈에 짧은 이름을 붙여줄 수 있습니다. (require '[clojure.string :as str]) (str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst." ; (#"" denotes a regular expression literal) ; :require 를 이용하여, 네임스페이스에서 require 를 사용할 수 있습니다. ; 아레와 같은 방법을 이용하면, 모듈을 quote하지 않아도 됩니다. (ns test (:require [clojure.string :as str] [clojure.set :as set])) ; Java ;;;;;;;;;;;;;;;;; ; Java는 유용한 많은 표준 라이브러리를 가지고 있으며, ; 이를 어떻게 활용할 수 있는지 알아보도록 하겠습니다. ; import 로 java 모듈을 불러올 수 있습니다. (import java.util.Date) ; ns 와 함께 import 를 할 수 도 있습니다. (ns test (:import java.util.Date java.util.Calendar)) ; 새로운 인스턴스를 만들기 위해선, 클래스 이름 끝에 "."을 찍습니다. (Date.) ; ; . 을 이용하여 메소드를 호출할 수 있습니다. ; 아니면, 줄여서 ".메소드"로도 호출 할 수 있습니다. (. (Date.) getTime) ; (.getTime (Date.)) ; exactly the same thing. ; / 를 이용하여 정적메소드를 호출 할 수 있습니다. (System/currentTimeMillis) ; (system is always present) ; doto 를 이용하여 상태가 변하는(mutable) 클래스들을 좀 더 편하게(tolerable) 다룰 수 있습니다. (import java.util.Calendar) (doto (Calendar/getInstance) (.set 2000 1 1 0 0 0) .getTime) ; => A Date. set to 2000-01-01 00:00:00 ; STM ;;;;;;;;;;;;;;;;; ; Software Transactional Memory 는 clojure가 영구적인(persistent) 상태를 다루는 방식입니다. ; clojure가 이용하는 몇몇 자료형(construct)이 있습니다. ; 가장 단순한 것은 atom 입니다. 초기 값을 넣어보도록 하겠습니다. (def my-atom (atom {})) ; swap! 으로 atom을 갱신(update)할 수 있습니다! ; swap! 은 함수를 인자로 받아, 그 함수에 대해 현재 atom에 들어있는 값을 첫번째 인자로, ; 나머지를 두번째 인자로 하여 호출합니다. (swap! my-atom assoc :a 1) ; Sets my-atom to the result of (assoc {} :a 1) (swap! my-atom assoc :b 2) ; Sets my-atom to the result of (assoc {:a 1} :b 2) ; '@' 를 이용하여 atom을 역참조(dereference)하여 값을 얻을 수 있습니다. my-atom ;=> Atom<#...> (atom 객체가 반환됩니다.) @my-atom ; => {:a 1 :b 2} ; 여기 atom을 이용한 단순한 카운터가 있습니다. (def counter (atom 0)) (defn inc-counter [] (swap! counter inc)) (inc-counter) (inc-counter) (inc-counter) (inc-counter) (inc-counter) @counter ; => 5 ; STM을 구성하는 다른 것들에는 ref 와 agent 가 있습니다. ; Refs: http://clojure.org/refs ; Agents: http://clojure.org/agents ``` ### 읽어볼거리 부족한 것이 많았지만, 다행히도 채울 수 있는 것들이 많이 있습니다. Clojure.org에 많은 문서들이 보관되어 있습니다: [http://clojure.org/](http://clojure.org/) Clojuredocs.org는 core 함수들에 대해 다양한 예제와 문서를 보유하고 있습니다: [http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core) 4Clojure는 clojure/FP 스킬을 올릴 수 있는 좋은 길입니다: [https://4clojure.oxal.org/](https://4clojure.oxal.org/) Clojure-doc.org는 많고 많은 문서들을 보유하고 있습니다: [http://clojure-doc.org/](http://clojure-doc.org/) ================================================ FILE: ko/coffeescript.md ================================================ --- contributors: - ["Tenor Biel", "http://github.com/L8D"] translators: - ["wikibook", "http://wikibook.co.kr"] --- ``` coffeescript # 커피스크립트(CoffeeScript)는 최신 유행을 따르는 언어입니다. # 커피스크립트는 여러 현대 언어의 트렌드를 따르는데, # 그래서 주석을 작성할 때는 루비나 파이썬과 같이 해시를 씁니다. ### 블록 주석은 이처럼 작성하며, 자바스크립트 코드로 만들어지도록 '/ *'와 '* /'로 직접적으로 변환됩니다. 계속하기에 앞서 자바스크립트 시맨틱을 대부분 이해하고 있어야 합니다. ### # 할당: number = 42 #=> var number = 42; opposite = true #=> var opposite = true; # 조건문: number = -42 if opposite #=> if(opposite) { number = -42; } # 함수: square = (x) -> x * x #=> var square = function(x) { return x * x; } # 범위: list = [1..5] #=> var list = [1, 2, 3, 4, 5]; # 객체: math = root: Math.sqrt square: square cube: (x) -> x * square x #=> var math = { # "root": Math.sqrt, # "square": square, # "cube": function(x) { return x * square(x); } #} # 가변 인자(splat): race = (winner, runners...) -> print winner, runners # 존재 여부 확인: alert "I knew it!" if elvis? #=> if(typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); } # 배열 조건 제시법(comprehensions): cubes = (math.cube num for num in list) #=> ... ``` ================================================ FILE: ko/common-lisp.md ================================================ --- contributors: - ["Paul Nathan", "https://github.com/pnathan"] - ["Paul Khuong", "https://github.com/pkhuong"] - ["Rommel Martinez", "https://ebzzry.io"] translators: - ["Eunpyoung Kim", "https://github.com/netpyoung"] --- 커먼 리스프(Common Lisp, CL)는 다양한 산업 어플리케이션에 적합한 범용적인 멀티페러다임 언어입니다. 프로그래밍할 수 있는 프로그래밍 언어로서 자주 언급되곤 합니다. 처음 접하기 좋은책은 [Practical Common Lisp](http://www.gigamonkeys.com/book/)입니다. 또 다른 유명한 책으로는 최근에 나온 [Land of Lisp](http://landoflisp.com/)입니다. 베스트 프렉틱스에 관한 [Common Lisp Recipes](http://weitz.de/cl-recipes/) 책도 최근에 출판되었습니다. ```lisp ;;;----------------------------------------------------------------------------- ;;; 0. 구문 (Syntax, 신택스) ;;;----------------------------------------------------------------------------- ;;; 일반적인 폼(form) ;;; CL은 2개의 근본이 되는 구문 요소를 가집니다: ATOM 과 S-EXPRESSION. ;;; 일반적으로, 괄호로 묶인 S-expressions를 `폼(form)`이라고 부릅니다. 10 ; atom; 그 자체로 평가됩니다 :thing ; atom; 심볼 :thing로 평가됩니다 t ; atom, 참을 나타냅니다 (+ 1 2 3 4) ; s-expression '(4 :foo t) ; s-expression ;;; 주석 ;;; 한줄주석은 세미콜론으로 시작합니다( ; ) ;;; 파일 단위로는 4개, 구획(section) 설명으로는 3개, 정의(definition) 안에서는 2개, ;;; 한 라인에 대해서는 1개를 사용합니다. 예를들면, ;;;; life.lisp ;;; Foo bar baz, because quu quux. Optimized for maximum krakaboom and umph. ;;; Needed by the function LINULUKO. (defun meaning (life) "LIFE의 의미를 계산하여 반환합니다." (let ((meh "abc")) ;; Invoke krakaboom (loop :for x :across meh :collect x))) ; 값을 x에 저장한 다음, 이를 반환합니다. ;;; 반면, 블록주석은 자유롭게 쓸 수 있습니다. ;;; #| 와 |# 로 구역을 나눌 수 있습니다. #| 이것은 블록 주석이며, 여러 줄로 쓸 수 있으며 #| 중첩하여 사용할 수 있습니다! |# |# ;;; 환경 ;;; 여러 종류의 구현체들이 있습니다; ;;; 대부분 표준을 따르지만, SBCL이 처음 시작하기에 좋습니다. ;;; Quicklisp를 이용하여 서드파티 라이브러리들을 쉽게 설치할 수 있습니다. ;;; CL을 개발할때 텍스트 편집기와 ;;; 읽고(Read) 평가하고(Eval) 출력(Print)을 반복(Loop)하는 REPL을 동시에 활용하여 개발합니다. ;;; REPL은 프로그램이 "실행되고 있는 중(live)"에 프로그램과 상호작용을 할 수 있도록 만들어 줍니다. ;;;----------------------------------------------------------------------------- ;;; 1. 주요 데이터 타입 및 연산자 ;;;----------------------------------------------------------------------------- ;;; 심볼 'foo ; => FOO 자동으로 심볼이 대문자로 된 것을 주목하시기 바랍니다. ;;; INTERN은 문자열을 심볼로 만들어 줍니다. (intern "AAAA") ; => AAAA (intern "aaa") ; => |aaa| ;;; 숫자 9999999999999999999999 ; 정수 #b111 ; 2진수 => 7 #o111 ; 8진수 => 73 #x111 ; 16진수 => 273 3.14159s0 ; single 3.14159d0 ; double 1/2 ; 분수 #C(1 2) ; 복소수 ;;; 함수 적용 ;;; (f x y z ...)에서 f는 함수이며, x, y, z, ... 인자입니다. (+ 1 2) ; => 3 ;;; 데이터 그 자체를 만들기 원한다면, ;;; QUOTE를 이용하여 평가를 막을 수 있습니다. (quote (+ 1 2)) ; => (+ 1 2) (quote a) ; => A ;;; QUOTE을 짧게 쓰면 ( ' )입니다. '(+ 1 2) ; => (+ 1 2) 'a ; => A ;;; 기본 산술 연산자 (+ 1 1) ; => 2 (- 8 1) ; => 7 (* 10 2) ; => 20 (expt 2 3) ; => 8 ;; exponentiation: 제곱 (mod 5 2) ; => 1 ;; modulo: 나머지 연산 (/ 35 5) ; => 7 (/ 1 3) ; => 1/3 (+ #C(1 2) #C(6 -4)) ; => #C(7 -2) ;;; 불리언(Boolean) t ; 참 ; NIL이 아니면 참. nil ; 거짓; 빈 리스트: () 역시 거짓. (not nil) ; => T (and 0 t) ; => T (or 0 nil) ; => 0 ;;; 문자 #\A ; => #\A #\λ ; => #\GREEK_SMALL_LETTER_LAMDA #\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA ;;; 문자열은 고정된 길이의 배열속에 문자들이 들어있는 것입니다. "Hello, world!" "Benjamin \"Bugsy\" Siegel" ; 역슬래쉬(\)는 이스케이프 문자입니다. ;;; 문자열을 연결(concatenate)시킬 수 도 있습니다. (concatenate 'string "Hello, " "world!") ; => "Hello, world!" ;;; 문자열을 마치 문자들이 나열된것처럼 취급할 수도 있습니다. (elt "Apple" 0) ; => #\A ;;; FORMAT은 형식화된 출력을 만들기 위해 사용됩니다. ;;; 간단한 스트링 인터폴레이션(string interpolation)부터 반복문이나 조건문까지 다양한 기능을 제공합니다. ;;; FORMAT의 첫번째 인자는 포맷팅된 문자열이 어디로 갈지 결정합니다 ;;; 만약 NIL이라면, FORMAT은 포맷팅된 문자열을 반환합니다; ;;; 만약 T라면, FORMAT은 표준 출력, 일반적으로 스크린에 출력한 다음 NIL을 반환합니다. (format nil "~A, ~A!" "Hello" "world") ; => "Hello, world!" (format t "~A, ~A!" "Hello" "world") ; => NIL ;;;----------------------------------------------------------------------------- ;;; 2. 변수 ;;;----------------------------------------------------------------------------- ;;; DEFVAR와 DEFPARAMETER를 이용하여 전역 (동적 스코프) 변수를 만들 수 있습니다. ;;; 변수 이름은 다음을 제외한 모든 문자를 사용할 수 있습니다: ()",'`;#|\ ;;; DEFVAR와 DEFPARAMETER의 차이점으로는, DEFVAR 표현식을 다시 평가하더라도 변수의 값이 변경되지 않는다는 것입니다. ;;; 반면 DEFPARAMETER는 변경됩니다. ;;; 관례상, 동적 스코프 변수는 이름에는 귀마개(earmuffs)를 씌워줍니다. (defparameter *some-var* 5) *some-var* ; => 5 ;;; 유니코드 문자 역시 사용할 수 있습니다. (defparameter *AΛB* nil) ;;; 이전에 바인딩되지 않은 변수에 접근하면 UNBOUND-VARIABLE 에러가 발생하지만, 이것은 정의된 동작입니다. ;;; 바인딩되지 않은 변수에는 접근하지 마세요. ;;; LET 으로 지역 바인딩을 만들 수 있습니다. ;;; 다음 코드에서 (let ...) 안에서 "dance with you"는 `me`로 바인딩됩니다. ;;; LET은 항상 LET 폼의 마지막 `form`의 값을 반환합니다. (let ((me "dance with you")) me) ; => "dance with you" ;;;-----------------------------------------------------------------------------; ;;; 3. 구조체와 컬렉션 ;;;-----------------------------------------------------------------------------; ;;; 구조체 (defstruct dog name breed age) (defparameter *rover* (make-dog :name "rover" :breed "collie" :age 5)) *rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5) (dog-p *rover*) ; => T (dog-name *rover*) ; => "rover" ;;; DOG-P, MAKE-DOG, DOG-NAME은 모두 DEFSTRUCT에 의해 자동으로 생성됩니다. ;;; 페어(쌍, Pair) ;;; CONS는 페어를 만듭니다. CAR와 CDR은 페어의 head와 tail을 반환합니다. (cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB) (car (cons 'SUBJECT 'VERB)) ; => SUBJECT (cdr (cons 'SUBJECT 'VERB)) ; => VERB ;;; 리스트 ;;; 리스트는 CONS 페어로 만들어진 링크드 리스트 데이터 구조입니다. ;;; 리스트의 끝은 NIL (또는 '())로 표시됩니다. (cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3) ;;; LIST는 리스트를 위한 가변인자 생성자입니다. (list 1 2 3) ; => '(1 2 3) ;;; CONS에 첫번째 인자가 원자이고 두번째 인자는 리스트일때, ;;; CONS는 새로운 CONS-페어를 반환하게 되는데, ;;; 첫번째 인자를 첫번째 아이템으로, 두번째 인자를 CONS-페어의 나머지로 하게됩니다. (cons 4 '(1 2 3)) ; => '(4 1 2 3) ;;; APPEND를 사용하여 리스트를 연결할 수 있습니다. (append '(1 2) '(3 4)) ; => '(1 2 3 4) ;;; 또는 CONCATENATE (concatenate 'list '(1 2) '(3 4)) ; => '(1 2 3 4) ;;; 리스트는 매우 중요한 타입이며, 다양한 기능들이 있습니다. ;;; 몇 가지 예를 들어보겠습니다: (mapcar #'1+ '(1 2 3)) ; => '(2 3 4) (mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33) (remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4) (every #'evenp '(1 2 3 4)) ; => NIL (some #'oddp '(1 2 3 4)) ; => T (butlast '(subject verb object)) ; => (SUBJECT VERB) ;;; 벡터 ;;; 벡터는 고정길이 배열입니다. #(1 2 3) ; => #(1 2 3) ;;; CONCATENATE를 사용하여 벡터를 연결할 수 있습니다. (concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) ;;; 배열 ;;; 벡터와 스트링은 배열의 특이 케이스입니다. ;;; 2차원 배열 (make-array (list 2 2)) ; => #2A((0 0) (0 0)) (make-array '(2 2)) ; => #2A((0 0) (0 0)) (make-array (list 2 2 2)) ; => #3A(((0 0) (0 0)) ((0 0) (0 0))) ;;; 주의: MAKE-ARRAY의 기본 초기값은 구현체에 따라 다릅니다. ;;; 명시적으로 지정하려면 다음과 같이하면 됩니다: (make-array '(2) :initial-element 'unset) ; => #(UNSET UNSET) ;;; 1, 1, 1에 있는 요소에 접근하기: (aref (make-array (list 2 2 2)) 1 1 1) ; => 0 ;;; 반환되는 값은 구현체에 따라 다릅니다: ;;; SBCL과 CCL에서는 0, ECL에서는 NIL ;;; 조절 가능한 벡터(adjustable vector) ;;; 조절 가능한 벡터는 고정길이 벡터와 동일한 출력 결과를 갖습니다. (defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3) :adjustable t :fill-pointer t)) *adjvec* ; => #(1 2 3) ;;; 새로운 요소 추가하기 (vector-push-extend 4 *adjvec*) ; => 3 *adjvec* ; => #(1 2 3 4) ;;; 셋(Set)은 단순히 리스트입니다: (set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1) (intersection '(1 2 3 4) '(4 5 6 7)) ; => 4 (union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7) (adjoin 4 '(1 2 3 4)) ; => (1 2 3 4) ;;; 하지만, 많은 데이터 셋을 다룰 경우, ;;; 링크드리스트 보다 더 나은 데이터 구조를 필요로 할 것입니다. ;;; 딕션어리는 해쉬태이블로 만들어졌습니다. ;;; 해쉬 테이블 만들기 (defparameter *m* (make-hash-table)) ;;; 값 설정 (setf (gethash 'a *m*) 1) ;;; 값 받아오기 (gethash 'a *m*) ; => 1, T ;;; CL의 표현식은 여러개의 값을 반환 할 수 있습니다. (values 1 2) ; => 1, 2 ;;; MULTIPLE-VALUE-BIND로 연결(bind)지을 수 있습니다. (multiple-value-bind (x y) (values 1 2) (list y x)) ; => '(2 1) ;;; GETHASH는 여러 값을 반환하는 함수의 예입니다. ;;; 첫번째 반환값은 해쉬 테이블의 키의 값입니다; ;;; 만약 키가 발견되지 않으면 NIL을 반환합니다. ;;; 두번째 반환값은 키가 해쉬 테이블에 존재하는지 여부를 결정합니다. ;;; 테이블에서 키를 찾지 못하면 NIL을 반환합니다. ;;; 이러한 동작은 키의 값이 실제로 NIL인지 확인할 수 있도록 해줍니다. (gethash 'd *m*) ;=> NIL, NIL ;;; 키가 없을때를 대비한 기본값을 설정할 수 있습니다; (gethash 'd *m* :not-found) ; => :NOT-FOUND ;;; 반환된 값들을 처리해보겠습니다. (multiple-value-bind (a b) (gethash 'd *m*) (list a b)) ; => (NIL NIL) (multiple-value-bind (a b) (gethash 'a *m*) (list a b)) ; => (1 T) ;;;----------------------------------------------------------------------------- ;;; 3. 함수 ;;;----------------------------------------------------------------------------- ;;; 익명 함수를 만들기 위해 LAMBDA를 사용합니다. ;;; 함수는 항상 마지막 표현식의 값을 반환합니다. ;;; 함수의 출력방식은 구현체마다 다릅니다. (lambda () "Hello World") ; => # ;;; 익명 함수를 호출하기 위해 FUNCALL을 사용합니다. (funcall (lambda () "Hello World")) ; => "Hello World" (funcall #'+ 1 2 3) ; => 6 ;;; 리스트의 앞에 lambda표현식을 넣으면, 암시적으로 FUNCALL을 호출합니다. ((lambda () "Hello World")) ; => "Hello World" ((lambda (val) val) "Hello World") ; => "Hello World" ;;; 인자가 미리 주어져 있으면 FUNCALL을 사용하고, 그렇지 않으면 APPLY를 사용합니다. (apply #'+ '(1 2 3)) ; => 6 (apply (lambda () "Hello World") nil) ; => "Hello World" ;;; 함수에 이름을 붙이려면 DEFUN을 사용합니다. (defun hello-world () "Hello World") (hello-world) ; => "Hello World" ;;; 위 정의에서 ()는 인자 리스트입니다. (defun hello (name) (format nil "Hello, ~A" name)) (hello "Steve") ; => "Hello, Steve" ;;; 함수는 선택적(optional) 인자를 가질 수 있습니다; 기본값은 NIL입니다. (defun hello (name &optional from) (if from (format t "Hello, ~A, from ~A" name from) (format t "Hello, ~A" name))) (hello "Jim" "Alpacas") ; => Hello, Jim, from Alpacas ;;; 기본값을 다음과 같이 지정할 수도 있습니다. (defun hello (name &optional (from "The world")) (format nil "Hello, ~A, from ~A" name from)) (hello "Steve") ; => Hello, Steve, from The world (hello "Steve" "the alpacas") ; => Hello, Steve, from the alpacas ;;; 함수는 키워드 인자를 이용하여 위치와 상관없는 인자를 가질 수도 있습니다. (defun generalized-greeter (name &key (from "the world") (honorific "Mx")) (format t "Hello, ~A ~A, from ~A" honorific name from)) (generalized-greeter "Jim") ; => Hello, Mx Jim, from the world (generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr") ; => Hello, Mr Jim, from the alpacas you met last summer ;;;----------------------------------------------------------------------------- ;;; 4. 동등성(Equality) ;;;----------------------------------------------------------------------------- ;;; CL은 정교한 동등성 시스템을 가지고 있습니다. ;;; 그 중 일부를 여기서 다뤄보도록 하겠습니다. ;;; 숫자에 대해서는 ( = )를 사용합니다. (= 3 3.0) ; => T (= 2 1) ; => NIL ;;; 객체 식별에 대해서는 EQL을 사용합니다. (eql 3 3) ; => T (eql 3 3.0) ; => NIL (eql (list 3) (list 3)) ; => NIL ;;; 리스트, 스트링, 비트-벡터에 대해서는 EQUAL을 사용합니다. (equal (list 'a 'b) (list 'a 'b)) ; => T (equal (list 'a 'b) (list 'b 'a)) ; => NIL ;;;----------------------------------------------------------------------------- ;;; 5. 제어 흐름(Control Flow) ;;;----------------------------------------------------------------------------- ;;; 조건문 (if t ; 구문: 조건 "참입니다" ; 구문: 그러면 "거짓입니다") ; 구문: 그렇지 않으면 ; => "참입니다" ;;; 조건문에서, NIL이 아닌 모든 값은 참으로 취급됩니다. (member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO) (if (member 'Groucho '(Harpo Groucho Zeppo)) 'yep 'nope) ; => 'YEP ;;; COND는 일련의 테스트를 실행하며, 결과를 선택합니다. (cond ((> 2 2) (error "wrong!")) ((< 2 2) (error "wrong again!")) (t 'ok)) ; => 'OK ;;; TYPECASE는 값의 타입에 따라 분기합니다. (typecase 1 (string :string) (integer :int)) ; => :int ;;; 루프(loop) ;;; 재귀(recursion) (defun fact (n) (if (< n 2) 1 (* n (fact(- n 1))))) (fact 5) ; => 120 ;;; 반복(iteration) (defun fact (n) (loop :for result = 1 :then (* result i) :for i :from 2 :to n :finally (return result))) (fact 5) ; => 120 (loop :for x :across "abcd" :collect x) ; => (#\a #\b #\c #\d) (dolist (i '(1 2 3 4)) (format t "~A" i)) ; => 1234 ;;;----------------------------------------------------------------------------- ;;; 6. 변경(Mutation) ;;;----------------------------------------------------------------------------- ;;; 기존 변수에 새 값을 할당하기 위해선 SETF를 사용합니다. ;;; 해쉬 테이블 예제에서도 한번 나왔었습니다. (let ((variable 10)) (setf variable 2)) ; => 2 ;;; 좋은 리스프 스타일은 파괴적인 함수의 사용을 최소화하고, ;;; 변경을 되도록 피하는 것입니다. ;;;----------------------------------------------------------------------------- ;;; 7. 클래스와 객체 ;;;----------------------------------------------------------------------------- ;;; 더 이상 animal 클래스는 없습니다. ;;; 인간을 동력수단으로 삼는 운송기계 ;;; (Human-Powered Mechanical Conveyances)를 만들어보겠습니다. (defclass human-powered-conveyance () ((velocity :accessor velocity :initarg :velocity) (average-efficiency :accessor average-efficiency :initarg :average-efficiency)) (:documentation "A human powered conveyance")) ;;; DEFCLASS의 인자의 순서는 다음과 같습니다: ;;; 1. 클래스 이름 ;;; 2. 슈퍼클래스 목록 ;;; 3. 슬롯 목록 ;;; 4. 선택적 지정자 ;;; 이 때 슈퍼클래스 목록이 설정되지 않으면, 빈 목록이 표준 객체 클래스로 기본 설정됩니다. ;;; 이것은 변경할 수도 있지만, 어떻게 돌아가는지 알기전에는 변경하지 않습니다. ;;; 그러면, 메타오브젝트 프로토콜의 예술(Art of the Metaobject Protocol)에 대해 좀 더 살펴보도록 하겠습니다. (defclass bicycle (human-powered-conveyance) ((wheel-size :accessor wheel-size :initarg :wheel-size :documentation "Diameter of the wheel.") (height :accessor height :initarg :height))) (defclass recumbent (bicycle) ((chain-type :accessor chain-type :initarg :chain-type))) (defclass unicycle (human-powered-conveyance) nil) (defclass canoe (human-powered-conveyance) ((number-of-rowers :accessor number-of-rowers :initarg :number-of-rowers))) ;;; REPL에서 HUMAN-POWERED-CONVEYANCE 클래스에 대해 DESCRIBE를 호출하면 다음과 같은 결과를 얻게됩니다: (describe 'human-powered-conveyance) ; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE ; [symbol] ; ; HUMAN-POWERED-CONVEYANCE names the standard-class #: ; Documentation: ; A human powered conveyance ; Direct superclasses: STANDARD-OBJECT ; Direct subclasses: UNICYCLE, BICYCLE, CANOE ; Not yet finalized. ; Direct slots: ; VELOCITY ; Readers: VELOCITY ; Writers: (SETF VELOCITY) ; AVERAGE-EFFICIENCY ; Readers: AVERAGE-EFFICIENCY ; Writers: (SETF AVERAGE-EFFICIENCY) ;;; 주목할 점은 리플렉션이 가능하다는 것입니다. ;;; CL은 대화형 시스템으로 설계되었습니다. ;;; 메서드를 정의하기 앞서, 자전거 바퀴의 둘레가 얼마나 되는 공식을 살펴봅시다: ;;; C = d * pi (defmethod circumference ((object bicycle)) (* pi (wheel-size object))) ;;; PI는 CL에 미리 정의되어 있습니다. ;;; 카누에 있는 노 젓는 사람들의 수의 효율성 값이 대략 로그함수적이라는 것을 안다고 가정해봅시다. ;;; 이와 같은 정보는 생성자/초기화자에서 설정하는 것이 좋습니다. ;;; CL이 인스턴스를 생성한 다음에(after), 인스턴스를 초기화하기 위해선: (defmethod initialize-instance :after ((object canoe) &rest args) (setf (average-efficiency object) (log (1+ (number-of-rowers object))))) ;;; 그런 다음 인스턴스를 생성하고, 평균 효율을 확인합니다... (average-efficiency (make-instance 'canoe :number-of-rowers 15)) ; => 2.7725887 ;;;----------------------------------------------------------------------------- ;;; 8. 매크로 ;;;----------------------------------------------------------------------------- ;;; 매크로는 언어의 구문을 확장할 수 있게 해줍니다. ;;; CL에는 WHILE 루프가 없지만, 새로 작성하는 것은 간단합니다. ;;; 어셈블러의 명령어를 따라가자면, 다음과 같이 될 것입니다: (defmacro while (condition &body body) "While `condition` is true, `body` is executed. `condition` is tested prior to each execution of `body`" (let ((block-name (gensym)) (done (gensym))) `(tagbody ,block-name (unless ,condition (go ,done)) (progn ,@body) (go ,block-name) ,done))) ;;; 좀 더 고수준 버전을 살펴보겠습니다: (defmacro while (condition &body body) "While `condition` is true, `body` is executed. `condition` is tested prior to each execution of `body`" `(loop while ,condition do (progn ,@body))) ;;; 하지만, 현대의 컴파일러에서는 이것이 필요하지 않습니다; ;;; LOOP 폼은 동일하게 잘 컴파일되며 읽기 쉽습니다. ;;; Note that ``` is used, as well as `,` and `@`. ``` is a quote-type operator ;;; known as quasiquote; it allows the use of `,` . `,` allows "unquoting" ;;; variables. @ interpolates lists. ;;; GEMSYM은 다른 곳에서 사용되지 않는 것이 보장된 시스템에서 유일한 심볼을 생성합니다. ;;; 컴파일 타임에 매크로가 확장되는데, 매크로에서 선언된 변수가 ;;; 일반 코드에서 사용되는 변수와 충돌할 가능성이 있기 때문입니다. ;;; 매크로에 대해 더 자세한 정보를 얻고 싶으시다면, Practical Common Lisp와 On Lisp를 살펴보시기 바랍니다. ``` ## 더 읽어볼거리 - [Practical Common Lisp](http://www.gigamonkeys.com/book/) - [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf) ## 추가 정보 - [CLiki](http://www.cliki.net/) - [common-lisp.net](https://common-lisp.net/) - [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl) - [Lisp Lang](http://lisp-lang.org/) ================================================ FILE: ko/erlang.md ================================================ --- contributors: - ["Giovanni Cappellotto", "http://www.focustheweb.com/"] translators: - ["Taesung Jung", "https://github.com/tsj"] --- ```erlang % 퍼센트 기호는 한 줄 주석을 시작한다. %% 두 개의 퍼센트 문자는 함수의 주석에 사용된다. %%% 세 개의 퍼센트 문자는 모듈의 주석에 사용된다. % Erlang에선 3가지 유형의 문장 부호를 사용한다. % 쉼표(`,`)는 함수 호출에서 인수, 데이터 생성자(constructors), 패턴을 구분한다. % 마침표(`.`)(다음에 오는 공백)는 셸에서 함수 전체와 식을 구분한다. % 세미콜론(`;`)은 절을 구분한다. 몇 가지 문맥(contexts)에서 절이 발견된다: % 함수 정의와 `case`, `if`, `try..catch`, 그리고 `receive` 식 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 1. 변수와 패턴 매칭 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Erlang에서 새로운 변수는 `=` 문장에 의해 바인딩 된다. Num = 42. % 모든 변수 이름은 반드시 대문자로 시작해야 한다. % Erlang은 단일 할당 변수(single-assignment variables)를 가진다; % 만약 다른 값을 `Num` 변수에 할당하려고 시도하면 오류가 발생한다. Num = 43. % ** 예외 오류: 우변의 값 43과 매칭되지 않음 % 대부분 언어에서 `=`는 할당문을 나타낸다. 그러나 Erlang에서 % `=`는 패턴 매칭 연산자를 나타낸다. 비어 있는 변수가 `=` 연산자의 좌변에 % 사용되면 바인드(할당) 된다, 그러나 바인드 변수가 좌변에 사용된 경우에 % 다음 행동은 그 바인드 변수가 관측된다. % `Lhs = Rhs`의 진짜 의미: 우변(`Rhs`)을 평가하고, 그리고 % 그 결과를 좌변(`Lhs`)의 패턴과 매치시켜라. Num = 7 * 6. % 부동 소수점 수. Pi = 3.14159. % Atom은 숫자가 아닌 서로 다른 상숫값을 표현하는 데 사용한다. Atom은 % 소문자로 시작하고, 연속적인 영숫자(alphanumeric) 문자나 밑줄(`_`) 또는 % 골뱅이(`@`) 기호가 따라온다. Hello = hello. OtherNode = example@node. % 영숫자 값이 아닌 Atom은 작은따옴표로 묶여서 작성될 수 있다. AtomWithSpace = 'some atom with space'. % Tuple은 C의 struct와 비슷하다. Point = {point, 10, 45}. % Tuple에서 어떤 값을 추출하려면, 패턴 매칭 연산자 `=`를 사용한다. {point, X, Y} = Point. % X = 10, Y = 45 % 관심 없는 변수를 위해 자리 표시자(placeholder) `_`를 사용할 수 있다. % 기호 `_`는 익명 변수(anonymous variable)라 부른다. 일반적인 변수들과 % 다르게 같은 패턴에서 여러 번 나오더라도 동일한 값으로 바인드되지 않아도 된다. Person = {person, {name, {first, joe}, {last, armstrong}}, {footsize, 42}}. {_, {_, {_, Who}, _}, _} = Person. % Who = joe % List를 만들기 위해서 List의 원소는 대괄호([])로 둘러싸고 쉼표(,)로 구분한다. % List의 각각의 원소는 어떤 타입도 가능하다. % List의 첫 번째 원소는 List의 HEAD이다. 만약 List의 HEAD를 제거하면, % 남은 부분은 List의 TAIL이라 부른다. ThingsToBuy = [{apples, 10}, {pears, 6}, {milk, 3}]. % 만약 `T`가 List이면, `[H|T]`도 HEAD가 `H`이고 TAIL이 `T`인 List이다. % 세로 막대(`|`)는 List의 HEAD와 TAIL을 분리한다. `[]`는 빈 List다. % List의 원소들은 패턴 매칭 연산으로 추출할 수 있다. % 만약 비어있지 않은 List `L`이 있을 때, `[X|Y] = L` 식의 `X`와 `Y`가 % 바인드되지 않은 변수이면, List의 HEAD는 X에 그리고 TAIL은 Y로 추출된다. [FirstThing|OtherThingsToBuy] = ThingsToBuy. % FirstThing = {apples, 10} % OtherThingsToBuy = [{pears, 6}, {milk, 3}] % Erlang에는 문자열(String)이 없다. 문자열은 사실 정수의 List일 뿐이다. % 문자열은 큰따옴표(`"`)로 묶인다. Name = "Hello". [72, 101, 108, 108, 111] = "Hello". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 2. 순차 프로그래밍 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Erlang에서 Module은 코드의 기본 단위이다. 우리가 작성한 모든 함수는 % Module에 담긴다. Module은 확장자가 `.erl`인 파일에 저장된다. % 코드가 실행되기 전에 Module은 컴파일되어야 한다. 컴파일된 Module은 % `.beam` 확장자를 가진다. -module(geometry). -export([area/1]). % Module로부터 내보내진(exported) 함수의 List % 함수 `area`는 두 개의 절로 구성된다. 절은 세미콜론(`;`)으로 구분되며, % 마지막 절은 마침표-공백(dot-whitespace)으로 끝난다. % 각 절은 서문(head)과 본문(body)을 가진다. 서문은 함수의 이름에 이어서 % 패턴이(괄호 속에) 따라온다. 본문은 연속적인 식으로 구성되고, % 연속적인 식은 서문의 패턴과 호출한 인수가 성공적으로 매치되면 평가된다. % 패턴은 함수 정의가 나타나는 순서대로 매치된다. area({rectangle, Width, Ht}) -> Width * Ht; area({circle, R}) -> 3.14159 * R * R. % geometry.erl 파일의 코드 컴파일 c(geometry). % {ok,geometry} % 호출하려는 함수를 정확히 알아내기 위해 함수 이름을 Module 이름과 함께 % 명시하는 것이 필요하다. geometry:area({rectangle, 10, 5}). % 50 geometry:area({circle, 1.4}). % 6.15752 % Erlang에서, 같은 Module에 이름이 같고 Arity(인수의 갯수)가 다른 % 두 함수는 전혀 다른 함수를 나타낸다. -module(lib_misc). -export([sum/1]). % Arity가 1인 내보내진(export) 함수 `sum` % 하나의 인수만 받음: 정수의 List sum(L) -> sum(L, 0). sum([], N) -> N; sum([H|T], N) -> sum(T, H+N). % Fun은 "익명(anonymous)" 함수다. 이름이 없어서 이렇게 부른다. % 그러나, 변수에 할당될 수 있다. Double = fun(X) -> 2 * X end. % `Double`은 익명 함수를 가리킨다: % #Fun Double(2). % 4 % 함수는 인수로 Fun을 받거나, Fun을 반환할 수 있다. Mult = fun(Times) -> ( fun(X) -> X * Times end ) end. Triple = Mult(3). Triple(5). % 15 % List 해석(List comprehensions)은 Fun, Map, Filter 없이 List를 만드는 식이다. % 표기법 `[F(X) || X <- L]`은 `F(X)`의 List라는 의미이다. % 이때 `X`는 List `L`로부터 가져온다. L = [1,2,3,4,5]. [2 * X || X <- L]. % [2,4,6,8,10] % List 해석은 Generator와 생성된 값들의 부분 집합을 선택하는 Filter를 가질 수 있다. EvenNumbers = [N || N <- [1, 2, 3, 4], N rem 2 == 0]. % [2, 4] % Guard는 패턴 매칭의 능력을 향상시키는데 사용할 수 있는 구조다. % Guard를 사용하면, 패턴에 있는 변수에 대해 간단한 검사와 비교를 수행할 수 있다. % 함수 정의의 서문(head)에 `when` 키워드로 시작되는 Guard를 사용할 수도 있고, % 또는 식이 허용되는 언어의 어떤 곳에도 사용될 수 있다. max(X, Y) when X > Y -> X; max(X, Y) -> Y. % Guard는 쉼표(`,`)로 구분된 연속된 Guard 식이다. % 모든 Guard 식 `GuardExpr1`, `GuardExpr2`, ..., `GuardExprN`이 % `true`로 평가된다면, Guard `GuardExpr1`, `GuardExpr2`, ..., `GuardExprN`는 % 참이다. is_cat(A) when is_atom(A), A =:= cat -> true; is_cat(A) -> false. is_dog(A) when is_atom(A), A =:= dog -> true; is_dog(A) -> false. % `=:=` 연산자는 여기서 자세히 다루지 않을 것이다; 두 개의 Erlang 식의 값이 같고 % *그리고* 같은 타입인지 검사하는 데 사용된다고만 알면 된다. % `==` 연산자의 작동과 대조할 것: 1 + 2 =:= 3. % true 1 + 2 =:= 3.0. % false 1 + 2 == 3.0. % true % 연속적인 Guard는 단일 Guard 또는 세미콜론(`;`)으로 구분된 연속된 Guard다. % Guard `G1; G2; ...; Gn` 중에 적어도 하나의 Guard가 `true`로 평가된다면, % 연속적인 Guard `G1; G2; ...; Gn`는 참이다. is_pet(A) when is_atom(A), (A =:= dog);(A =:= cat) -> true; is_pet(A) -> false. % 주의: 모든 유효한 Erlang 식이 Guard 식으로 사용될 수 있는 것은 아니다; % 특히, 함수 `is_cat`과 `is_dog`는 `is_pet`의 정의 안에 있는 % 연속적인 Guard 사이에 사용될 수 없다. % 연속적인 Guard에 허용되는 식의 자세한 설명은 Erlang 레퍼런스 메뉴얼 % [section](http://erlang.org/doc/reference_manual/expressions.html#id81912) % 을 참조하라. % Record는 Tuple 안에 이름과 특정 요소를 연결하는 방법을 제공한다. % Record 정의는 Erlang 소스 코드 파일에 포함되거나 Erlang 소스 코드 파일에 % 포함될 수 있는 확장자가 `.hrl`인 파일에 집어넣을 수 있다. -record(todo, { status = reminder, % 기본 값 who = joe, text }). % Record를 사용할 수 있기 전에 Record 정의를 반드시 셸로 읽어 들여야 한다. % 셸로 읽어 들이기 위해 셸 함수 `rr`(read records의 약자)을 사용한다. rr("records.hrl"). % [todo] % Record 생성과 수정 X = #todo{}. % #todo{status = reminder, who = joe, text = undefined} X1 = #todo{status = urgent, text = "Fix errata in book"}. % #todo{status = urgent, who = joe, text = "Fix errata in book"} X2 = X1#todo{status = done}. % #todo{status = done, who = joe, text = "Fix errata in book"} % `case` 식 % `filter`는 List `L`의 원소 `X` 중에서 `P(X)`가 참인 모든 `X`의 List를 반환한다. filter(P, [H|T]) -> case P(H) of true -> [H|filter(P, T)]; false -> filter(P, T) end; filter(P, []) -> []. filter(fun(X) -> X rem 2 == 0 end, [1, 2, 3, 4]). % [2, 4] % `if` 식. max(X, Y) -> if X > Y -> X; X < Y -> Y; true -> nil end. % 주의: 적어도 if 식의 Guard 중의 하나는 반드시 `true`로 평가되어야 한다. % 그렇지 않으면 예외가 발생한다. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 3. 예외 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 예외는 내부에 에러가 생겼거나 명시적으로 `throw(Exception)`, % `exit(Exception)` 또는 `erlang:error(Exception)`를 호출하면 % 시스템에 의해 발생한다. generate_exception(1) -> a; generate_exception(2) -> throw(a); generate_exception(3) -> exit(a); generate_exception(4) -> {'EXIT', a}; generate_exception(5) -> erlang:error(a). % Erlang은 예외를 잡는 두 가지 방법을 가지고 있다. 한 가지는 % 예외를 발생시키는 함수의 호출 부분을 `try...catch` 식으로 감싸는 것이다. catcher(N) -> try generate_exception(N) of Val -> {N, normal, Val} catch throw:X -> {N, caught, thrown, X}; exit:X -> {N, caught, exited, X}; error:X -> {N, caught, error, X} end. % 다른 방법은 그 호출 부분을 `catch` 식으로 감싸는 것이다. % 예외를 잡았을 때, 그 예외는 오류를 설명하는 Tuple로 변환된다. catcher(N) -> catch generate_exception(N). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 4. 병행성 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Erlang은 병행성을 위해 Actor 모델을 사용한다. Erlang에서 병행 프로그램을 % 작성하는 데 필요한 모든 것은 3가지 기본 형식(primitivies)이다: % 프로세스 생성, 메시지 보내기, 메시지 받기 % 새로운 프로세스를 시작하기 위해, 함수를 인수로 받는 `spawn` 함수를 사용한다. F = fun() -> 2 + 2 end. % #Fun spawn(F). % <0.44.0> % `spawn`은 pid(프로세스 식별자)를 반환한다. 이 pid를 프로세스로 % 메시지를 보내는 데 사용할 수 있다. 메시지 전달을 위해, `!` 연산자를 사용한다. % 위의 기능이 유용하려면, 메시지를 받을 수 있어야 한다. 메시지를 받는 것은 % `receive` 메커니즘을 사용한다. -module(calculateGeometry). -compile(export_all). calculateArea() -> receive {rectangle, W, H} -> W * H; {circle, R} -> 3.14 * R * R; _ -> io:format("We can only calculate area of rectangles or circles.") end. % Module을 컴파일하고 셸에서 `calculateArea`를 평가한 프로세스를 생성한다. c(calculateGeometry). CalculateArea = spawn(calculateGeometry, calculateArea, []). CalculateArea ! {circle, 2}. % 12.56000000000000049738 % 셸도 마찬가지로 프로세스이다. 현재 pid를 얻기 위해서 `self`를 사용할 수 있다. self(). % <0.41.0> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 5. EUnit과 테스트 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % EUnit의 테스트 생성기(generators)와 assert 매크로를 이용해 % 단위 테스트를 작성할 수 있다. -module(fib). -export([fib/1]). -include_lib("eunit/include/eunit.hrl"). fib(0) -> 1; fib(1) -> 1; fib(N) when N > 1 -> fib(N-1) + fib(N-2). fib_test_() -> [?_assert(fib(0) =:= 1), ?_assert(fib(1) =:= 1), ?_assert(fib(2) =:= 2), ?_assert(fib(3) =:= 3), ?_assert(fib(4) =:= 5), ?_assert(fib(5) =:= 8), ?_assertException(error, function_clause, fib(-1)), ?_assert(fib(31) =:= 2178309) ]. % EUnit은 Erlang 셸에서 테스트를 실행할 수 있게 % 자동으로 test() 함수를 내보낸다(export). fib:test() % Erlang의 유명한 빌드 툴인 Rebar는 EUnit과 호환된다. % ``` % rebar eunit % ``` ``` ## 참조 * ["Learn You Some Erlang for great good!"](http://learnyousomeerlang.com/) * ["Programming Erlang: Software for a Concurrent World" by Joe Armstrong](http://pragprog.com/book/jaerlang/programming-erlang) * [조 암스트롱, 김석준 역, "프로그래밍 얼랭: Software for a Concurrent World", 인사이트](http://ebook.insightbook.co.kr/book/23) * [Erlang/OTP Reference Documentation](http://www.erlang.org/doc/) * [Erlang - Programming Rules and Conventions](http://www.erlang.se/doc/programming_rules.shtml) ================================================ FILE: ko/go.md ================================================ --- contributors: - ["Sonia Keys", "https://github.com/soniakeys"] - ["Christopher Bess", "https://github.com/cbess"] - ["Jesse Johnson", "https://github.com/holocronweaver"] - ["Quint Guvernator", "https://github.com/qguv"] translators: - ["Jongmin Kim", "http://github.com/atomaths"] - ["Peter Lee", "http://github.com/ins429"] --- Go는 어떤 일을 잘 끝낼 수 있도록 하기위해 만들어졌다. Go가 잘 알려진 최신의 트렌드는 아니지만, 실세계의 문제들을 해결하기 위해서는 가장 새롭고 빠른 방법이다. Go는 정적 타이핑(static typing)의 명령형 언어들(imperative languages)이 갖고 있는 특징과 유사한 개념들을 가지고 있다. Go는 컴파일과 실행속도가 빠르며, 오늘날의 멀티코어 CPU를 위해 이해하기 쉬운 동시성(concurrency) 기능이 추가되었다. 그리고 큰 스케일의 프로그래밍에도 도움이 되는 기능들을 가지고 있다. 또한 Go에는 훌륭한 표준 라이브러리와 열정적인 커뮤니티가 있다. ```go // 한 줄 주석 /* 여러 줄 주석 */ // 모든 Go 소스 파일은 package로 시작한다. // 패키지 이름 중 main은 라이브러리가 아닌 실행파일을 선언하는 특별한 이름이다. package main // import는 이 Go 소스 파일 내에서 참조하는 라이브러리 패키지들을 선언한다. import ( "fmt" // Go 표준 라이브러리에 있는 패키지 "net/http" // 표준 라이브러리에는 웹 서버 패키지도 있다! (클라이언트도 있음) "strconv" // 문자열 변환 패키지 ) // 함수 선언. main은 실행 프로그램에서 시작점이 되는 특별한 함수다. // 중괄호를 사용한다. func main() { // Println은 표준 출력으로 개행을 출력한다. // fmt 패키지를 통해 이용할 수 있다. fmt.Println("Hello world!") // 다른 함수를 호출한다. beyondHello() } // 함수에 파라미터가 없더라도 빈 괄호는 있어야 한다. func beyondHello() { var x int // 변수 선언. 변수는 사용하기 전에 선언해야 한다. x = 3 // 변수에 값 할당. // 짧은 선언(short declaration)으로 := 를 사용하는데, // 이렇게 값을 할당하면 값의 타입에 따라 변수의 타입이 결정된다. y := 4 sum, prod := learnMultiple(x, y) // 함수는 두 개 이상의 리턴 값을 줄 수 있다. fmt.Println("sum:", sum, "prod:", prod) // 간단한 출력 learnTypes() // 잠시 후에 좀더 자세히! } // 함수는 파라미터들을 가질 수 있고, 복수개의 값을 리턴할 수 있다. func learnMultiple(x, y int) (sum, prod int) { return x + y, x * y // 두 개의 값을 리턴. } // 내장 타입과 리터럴 func learnTypes() { // 짧은 선언은 유용하다. s := "Learn Go!" // string 타입 s2 := `역따옴표 안의 string 리터럴은 개행을 포함할 수 있다.` // 같은 string 타입 // non-ASCII 리터럴. Go 소스는 UTF-8로 작성해야 한다. g := 'Σ' // 유니코드 코드 포인트를 담고 있고, int32 타입의 가칭(alias)인 rune 타입 f := 3.14159 // float64, an IEEE-754 64-bit 부동소수 타입 c := 3 + 4i // complex128, 내부적으로는 두 개의 float64 타입으로 표현됨 // 초기값과 함께 사용하는 var 키워드. var u uint = 7 // unsigned, 하지만 int에 따른 구현의존적인 크기 var pi float32 = 22. / 7 // 짧은 선언으로 변환(conversion)하는 문법. // Go에서는 type casting 이라고 하지않고 type conversion 이라고 함. n := byte('\n') // byte는 uint8의 가칭(alias) // 배열은 컴파일 시에 크기가 정해진다. var a4 [4]int // 모두 0으로 초기화되는 int 타입 4개짜리 배열 a3 := [...]int{3, 1, 5} // 3, 1, 5로 초기화되는 int 타입 3개짜리 배열 // 슬라이스(slice)라고 하는 타입은 배열에 대한 가변 크기를 가진다. // 배열, 슬라이스 각자 장점이 있지만, 슬라이스가 더 많이 사용된다. s3 := []int{4, 5, 9} // 위의 a3와 비교해보면 생략부호(...)가 없다. s4 := make([]int, 4) // 모두 0으로 초기화되는 int 4개에 대한 슬라이스를 할당. var d2 [][]float64 // 여기에서는 선언만 있고 할당은 없다. bs := []byte("a slice") // string 타입을 byte 슬라이스 타입으로 형변환(type conversion) p, q := learnMemory() // int에 대한 포인터 타입인 p와 q를 선언 fmt.Println(*p, *q) // C에서처럼 *는 포인터를 따라가 값을 참조한다. 여기서는 두 개의 int를 출력. // 맵(map)은 다른 언어의 해시(hash)나 딕셔너리(dictionary)처럼 가변의 연관배열 타입. m := map[string]int{"three": 3, "four": 4} m["one"] = 1 // 선언만 하고 사용하지 않는 변수가 있다면 Go에서는 컴파일 시 에러가 난다. // 언더바를 이용해서 변수를 사용한 것처럼 하고 그 값은 무시해버릴 수 있다. _, _, _, _, _, _, _, _, _ = s2, g, f, u, pi, n, a3, s4, bs // 물론 출력을 하면 변수로 취급한다. fmt.Println(s, c, a4, s3, d2, m) learnFlowControl() // 잠시 후에 다시 나옴 } // Go는 가비지 컬렉션 기능을 JVM 같은 곳이 아닌 실행파일 런타임에 포함하고 있다. // 그리고 포인터는 있지만, 포인터 연산(*p++ 같은)은 없다. // 그래서 nil 포인터 접근같은 것 때문에 실수를 할 수는 있지만 // 포인터 연산으로 인한 실수는 없게 된다. func learnMemory() (p, q *int) { // 지명된 리턴 값(named return value)인 p와 q는 int에 대한 포인터 타입이다. p = new(int) // 내장함수인 new는 메모리를 할당해준다. // 메모리 할당된 int는 0으로 초기화 되고, p는 이제 nil이 아니다. s := make([]int, 20) // 메모리의 단일 블록으로 20개의 int 공간을 할당한다. s[3] = 7 // 그중 하나에 값을 준다. r := -2 // 또다른 로컬 변수를 선언한다. return &s[3], &r // &는 어떤 대상체의 메모리 주소를 가져오게 된다. } func expensiveComputation() int { return 1e6 } func learnFlowControl() { // if문에 중괄호는 필요하지만, 조건이 들어갈 곳에 소괄호는 쓰지 않는다. if true { fmt.Println("told ya") } // 모든 Go 소스의 코드 포맷팅은 "go fmt" 커맨드라인 명령으로 소스코드의 포맷을 맞춘다. if false { // pout } else { // gloat } // if-else 체인 형태보다 switch 사용이 권장된다. x := 1 switch x { case 0: case 1: // case 안에서는 break가 없어도 자동으로 다음 case로 내려가지 않는다. // 자동으로 내려가게 하려면 fallthrough 키워드를 사용한다. case 2: // x는 1이므로 여기는 실행되지 않음. } // if 에서처럼 for 에서도 양쪽에 소괄호를 쓰지 않는다. for x := 0; x < 3; x++ { // ++ 은 실행을 제어하는 하나의 구문(statement)이다. fmt.Println("iteration", x) } // 여기서 x는 1이다. 위 for에서 x는 for 안의 블록 범위에 있기 때문. // For is the only loop statement in Go, but it has alternate forms. // for 는 Go에서 유일한 루프 구문이지만 다양한 형태로 조건을 주거나 while // 처럼 쓸 수도 있다. for { // 무한루프 break // 여기서 곧바로 break를 한 건 단지 continue // break, continue를 루프 안에서 쓸 수 있다는 것을 보여주기 위함. } // for 에서처럼 if 에서 := 를 사용하는것은 y에 먼저 값을 대입하고, // 그리고 y > x를 검사한다는 의미. if y := expensiveComputation(); y > x { x = y } // 함수 리터럴은 클로저다. xBig := func() bool { return x > 100 // 위 switch 문 바로 위에 있는 x를 참조한다. } fmt.Println("xBig:", xBig()) // true (x에 1e6를 대입했었다.) x /= 1e5 // x는 10이 된다. fmt.Println("xBig:", xBig()) // 이제 xBig()의 결과는 false가 된다. // `goto`가 필요하다면, 좋아하게 될지도... goto love love: learnDefer() // defer에 대해 learnInterfaces() // 곧이어서 좋은 기능에 대한 설명이 나올 거다. } func learnDefer() (ok bool) { // deferred statements are executed just before the function returns. // 연기된(deferred) 구문은 함수가 리턴하기 직전에 실행된다. defer fmt.Println("deferred statements execute in reverse (LIFO) order.") // 연기된 구문은 LIFO순으로 실행된다. defer fmt.Println("\nThis line is being printed first because") // 이 줄이 먼저 실행된다. // defer는 주로 파일을 닫는데 사용된다. // 파일을 닫는함수를 파일을 여는함수에 가까이 둘수 있다. return true } // String 이라는 메서드 하나를 가진 Stringer 라는 인터페이스 타입을 정의하자. type Stringer interface { String() string } // x와 y라는 이름의 int 타입 필드를 가진 pair라는 struct를 정의하자. type pair struct { x, y int } // pair 타입에 메서드 String을 정의하자. // 이제 pair는 Stringer 인터페이스를 구현(implement)한 것이 되었다. func (p pair) String() string { // 여기서 p는 리시버(receiver)라고 부른다. // Sprintf는 fmt 패키지 안에 있는 외부로 공개된(exported) 함수다. // 점(.)으로 p의 필드들을 참조할 수 있다. return fmt.Sprintf("(%d, %d)", p.x, p.y) } func learnInterfaces() { // 중괄호 문법은 "구조체 리터럴(struct literal)"인데, 초기화된 구조체로 // 취급하게 해준다. := 문법으로 p를 이 구조체로 선언하고 초기화한다. p := pair{3, 4} fmt.Println(p.String()) // 타입 pair인 p의 String 메서드를 호출. var i Stringer // Stringer 인터페이스 타입 i를 선언. i = p // pair는 Stringer를 구현했기 때문에 이 대입은 유효하다. // 타입 Stringer인 i의 String 메서드 호출. 결과는 위와 같다. fmt.Println(i.String()) // fmt 패키지의 함수들을 통해 어떤 객체를 출력해보려고 할 때, // fmt 패키지 내에서는 그 객체가 가진 String 메서드를 호출하도록 되어 있다. fmt.Println(p) // 결과는 위와 같다. Println은 String 메서드를 호출한다. fmt.Println(i) // 결과는 위와 같다. learnVariadicParams("great", "learning", "here!") } // 함수는 가변 인수(variadic) 파라미터를 가질수 있다. func learnVariadicParams(myStrings ...interface{}) { // 가변 인수를 차례로 반복한다. // 여기서 언더바(언더스코어, `_`)는 배열의 인덱스 인수를 무시한다. // The underbar here is ignoring the index argument of the array. for _, param := range myStrings { fmt.Println("param:", param) } // 가변 인수 값을 가변인수 파라미터로 보내기. fmt.Println("params:", fmt.Sprintln(myStrings...)) learnErrorHandling() } func learnErrorHandling() { // ", ok" (comma okay)표현은 무언가가 맞는 것인지 아닌지 확인하는데 사용된다. m := map[int]string{3: "three", 4: "four"} if x, ok := m[1]; !ok { // 이 map 안에 키가 1인 것은 없으므로 ok는 false가 된다. fmt.Println("no one there") } else { fmt.Print(x) // 만일 1이 map에 있었다면 x는 키 1의 값이 들어가게 된다. } // Go에서는 함수가 복수 개의 리턴 값을 줄 수 있다는 점을 활용해 함수의 두 번째 리턴 // 값으로 error를 리턴해주고 그 error가 nil 인지 아닌지 확인하는 관례가 있다. // 이때 이 error 값은 단지 위에서처럼 함수의 결과가 성공했는지 실패했는지를 확인하는 // 것뿐만 아니라 실패 시 어떤 문제가 있었는지 확인할 수 있는 수단도 된다. if _, err := strconv.Atoi("non-int"); err != nil { // _ 는 값을 안 쓰고 버린다는 의미. // "strconv.ParseInt: parsing "non-int": invalid syntax" 이런 에러가 출력된다. fmt.Println(err) } // 인터페이스에 대해 잠시 후에 다시 잠깐 볼 것이다. learnConcurrency() } // c는 goroutine 간의 통신을 위한 채널(channel)이다. func inc(i int, c chan int) { c <- i + 1 // 채널이 <- 이 연산자 왼쪽에 온다면 그 채널로 데이터를 보낸다는 의미다. } // 우리는 어떤 숫자들을 동시에 증가시키기 위해 inc 함수를 사용할 것이다. func learnConcurrency() { // make는 slice, map, channel 타입들에 대해 메모리를 할당하고 초기화를 한다. // Go에는 메모리 할당 방법으로 new와 make가 있다. c := make(chan int) // 3개의 동시에 실행되는 goroutine를 시작한다. 만약 실행하고 있는 머신이 // 멀티코어 CPU를 가지고 있고 올바르게 설정되어(GOMAXPROCS) 있다면 // 숫자가 정말로 병렬적으로 증가하게 될 것이다. go inc(0, c) // go는 새로운 goroutine을 시작하는 구문이다. go inc(10, c) go inc(-805, c) // 채널로부터 3개의 결과를 읽어 출력한다. // 결과가 어떤 순서로 오는지는 알 수 없다. fmt.Println(<-c, <-c, <-c) // 채널이 <- 연산자 오른쪽에 있는 건, 채널로부터 데이터를 받는 연산이다. cs := make(chan string) // string을 다루는 또 다른 채널 cc := make(chan chan string) // string 채널의 채널 go func() { c <- 84 }() // c 채널로 값을 보내는 goroutine 시작. go func() { cs <- "wordy" }() // cs 채널로 값을 보내느 goroutine 시작. // select 구문은 switch 문과 비슷하지만, case에서 채널 연산에 관한 일을 한다. // select의 case들은 채널통신을 할 준비가 된 case 하나가 무작위로 선택되어 // 그 부분이 실행된다. select { case i := <-c: // 채널로부터 받아진 값은 변수에 대입할 수 있다. fmt.Printf("it's a %T", i) case <-cs: // 또는 받은 값을 그냥 버릴 수도 있다. fmt.Println("it's a string") case <-cc: // 통신할 준비가 되어 있지 않은 비어있는 채널. fmt.Println("didn't happen.") } // 여기서는 c나 cs 채널로부터 값 하나를 받을 수 있다. 위에서 실행한 두 개의 // goroutine 중 하나가 완료되면 다른 하나는 블락된 상태로 있게 된다. learnWebProgramming() // Go에서는 웹 서버쪽 개발도 쉽게 할 수 있다. } // http 패키지의 함수 하나로 웹 서버를 실행시킨다. func learnWebProgramming() { // ListenAndServe의 첫 번째 파라미터는 listen 하기 위한 TCP 주소고, // 두 번째 파라미터는 http.Handler 인터페이스다. err := http.ListenAndServe(":8080", pair{}) fmt.Println(err) // don't ignore errors } // http.Handler의 하나 뿐인 메서드, ServeHTTP를 pair에서 구현한다. func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { // http.ResponseWriter의 메서드로 클라이언트에게 데이터를 보낸다. w.Write([]byte("You learned Go in Y minutes!")) } ``` ## 더 읽어볼 것들 Go에 대한 모든 것들은 [Go 공식 웹 사이트](https://go.dev/)를 참고하자. 여기에는 따라해볼 튜토리얼, 웹 기반의 인터랙티브 실행환경과 많은 읽을거리들이 있다. Go 언어 자체에 대한 스펙도 읽어보기를 적극 추천한다. 읽기 쉽게 되어있고 그리 길지는 않다. Go 소스코드에 대해 좀더 알아보고 싶다면 [Go 표준 라이브러리](https://go.dev/src/)를 분석해보기 바란다. 이해하기 쉽게 문서화되어 있고, Go 스타일 그리고 Go에서의 관례 배우기에 가장 좋은 방법일 것이다. 또는 [문서](https://go.dev/pkg/) 안에서 함수 이름 하나를 클릭해보면 소스코드를 브라우저에서 살펴볼 수도 있다. Go를 배울수 있는 또하나의 좋은 방법은 [Go by example](https://gobyexample.com/). ================================================ FILE: ko/java.md ================================================ --- contributors: - ["Jake Prather", "http://github.com/JakeHP"] translators: - ["wikibook", "http://wikibook.co.kr"] --- 자바는 일반 목적으로 사용할 수 있고 동시성을 지원하며, 클래스 기반의 객체지향 컴퓨터 프로그래밍 언어입니다. [더 자세한 사항](http://docs.oracle.com/javase/tutorial/java/index.html) ```java // 한 줄짜리 주석은 //로 시작합니다. /* 여러 줄 주석은 다음과 같은 형태입니다. */ /** 자바독(JavaDoc) 주석은 이렇게 생겼습니다. 자바독 주석은 클래스나 클래스의 다양한 속성을 기술하는 데 사용됩니다. */ // java.util 패키지 안에 있는 ArrayList 클래스를 임포트합니다. import java.util.ArrayList; // java.security 패키지 안에 있는 모든 클래스를 임포트합니다. import java.security.*; // 각 .java 파일에는 공용(public) 클래스가 들어 있으며, 클래스의 이름은 // 파일명과 동일합니다. public class LearnJava { // 프로그램에는 반드시 진입점 역할을 하는 main 메서드가 하나 있어야 합니다. public static void main (String[] args) { // System.out.println을 이용해 한 줄을 출력합니다. System.out.println("Hello World!"); System.out.println( "Integer: " + 10 + " Double: " + 3.14 + " Boolean: " + true); // 줄바꿈 없이 뭔가를 출력하려면 System.out.print를 사용합니다. System.out.print("Hello "); System.out.print("World"); /////////////////////////////////////// // 타입 & 변수 /////////////////////////////////////// // <타입> <이름>과 같은 형태로 변수를 선언합니다. // Byte - 부호가 있는 8비트 2의 보수 정수 // (-128 <= byte <= 127) byte fooByte = 100; // Short - 부호가 있는 16비트 2의 보수 정수 // (-32,768 <= short <= 32,767) short fooShort = 10000; // Integer - 부호가 있는 32비트 2의 보수 정수 // (-2,147,483,648 <= int <= 2,147,483,647) int fooInt = 1; // Long - 부호가 있는 64비트 2의 보수 정수 // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) long fooLong = 100000L; // L은 이 변수의 값이 Long 타입임을 나타내는 데 사용됩니다. // L이 없는 것들은 기본적으로 정수로 간주됩니다. // 참고: 자바에는 부호 없는(unsigned) 타입이 없습니다. // Float - 단정도 32비트 IEEE 754 부동 소수점 수 float fooFloat = 234.5f; // f는 이 변수의 값이 float 타입임을 나타내는 데 사용됩니다. // f를 지정하지 않으면 double로 간주됩니다. // Double - 배정도 64비트 IEEE 754 부동 소수점 수 double fooDouble = 123.4; // Boolean - 참(true) & 거짓(false) boolean fooBoolean = true; boolean barBoolean = false; // Char - 단일 16비트 유니코드 문자 char fooChar = 'A'; // 변수를 변경할 수 없게 만들려면 final을 지정합니다. final int HOURS_I_WORK_PER_WEEK = 9001; // 문자열 String fooString = "My String Is Here!"; // \n은 새로운 줄을 시작하는 이스케이프 문자입니다. String barString = "Printing on a new line?\nNo Problem!"; // \t는 탭 문자를 추가하는 이스케이프 문자입니다. String bazString = "Do you want to add a tab?\tNo Problem!"; System.out.println(fooString); System.out.println(barString); System.out.println(bazString); // 배열 // 배열의 크기는 반드시 선언할 때 결정해야 합니다. // 배열을 선언하는 형식은 다음과 같습니다. //<자료형> [] <변수명> = new <자료형>[<배열 크기>]; int [] intArray = new int[10]; String [] stringArray = new String[1]; boolean [] booleanArray = new boolean[100]; // 배열을 선언하고 초기화하는 또 다른 방법 int [] y = {9000, 1000, 1337}; // 배열 인덱스 - 요소에 접근 System.out.println("intArray @ 0: " + intArray[0]); // 배열의 인덱스는 0에서부터 시작하며 변경 가능합니다. intArray[1] = 1; System.out.println("intArray @ 1: " + intArray[1]); // => 1 // 기타 참고할 만한 자료구조 // ArrayLists - 좀 더 많은 기능을 제공하고 크기를 변경 가능하다는 점을 // 제외하면 배열과 비슷합니다. // LinkedLists // Maps // HashMaps /////////////////////////////////////// // 연산자 /////////////////////////////////////// System.out.println("\n->Operators"); int i1 = 1, i2 = 2; // 다중 선언의 축약형 // 산술 연산은 이해하기 어렵지 않습니다. System.out.println("1+2 = " + (i1 + i2)); // => 3 System.out.println("2-1 = " + (i2 - i1)); // => 1 System.out.println("2*1 = " + (i2 * i1)); // => 2 System.out.println("1/2 = " + (i1 / i2)); // => 0 (0.5를 잘라 버립니다) // 나눗셈 System.out.println("11%3 = "+(11 % 3)); // => 2 // 비교 연산자 System.out.println("3 == 2? " + (3 == 2)); // => false System.out.println("3 != 2? " + (3 != 2)); // => true System.out.println("3 > 2? " + (3 > 2)); // => true System.out.println("3 < 2? " + (3 < 2)); // => false System.out.println("2 <= 2? " + (2 <= 2)); // => true System.out.println("2 >= 2? " + (2 >= 2)); // => true // 비트 연산자! /* ~ 단항 보수 연산 << 산술적 왼쪽 시프트 >> 산술적 오른쪽 시프트 >>> 논리적 오른쪽 시프트 & 비트 단위 논리곱(AND) ^ 비트 단위 배타적 논리합(OR) | 비트 단위 논리합(OR) */ // 증감 연산자 int i = 0; System.out.println("\n->Inc/Dec-rementation"); System.out.println(i++); //i = 1. 후치 증가 연산 System.out.println(++i); //i = 2. 전치 증가 연산 System.out.println(i--); //i = 1. 후치 감소 연산 System.out.println(--i); //i = 0. 전치 감소 연산 /////////////////////////////////////// // 제어 구조 /////////////////////////////////////// System.out.println("\n->Control Structures"); // if 문은 C 언어와 비슷합니다. int j = 10; if (j == 10){ System.out.println("I get printed"); } else if (j > 10) { System.out.println("I don't"); } else { System.out.println("I also don't"); } // while 루프 int fooWhile = 0; while(fooWhile < 100) { // System.out.println(fooWhile); // 카운터를 증가 // 99번 반복, fooWhile 0->99 fooWhile++; } System.out.println("fooWhile Value: " + fooWhile); // do-while 루프 int fooDoWhile = 0; do { // System.out.println(fooDoWhile); // 카운터를 증가 // 99번 반복, fooDoWhile 0->99 fooDoWhile++; }while(fooDoWhile < 100); System.out.println("fooDoWhile Value: " + fooDoWhile); // for 루프 int fooFor; // for 루프 구조 => for(<초기식>; <조건식>; <증감식>) for(fooFor=0; fooFor<10; fooFor++){ // System.out.println(fooFor); // 10번 반복, fooFor 0->9 } System.out.println("fooFor Value: " + fooFor); // switch-case 문 // switch는 byte, short, char, int 자료형을 대상으로 동작합니다. // 아울러 열거형을 비롯해 String 클래스 및 원시 타입을 감싼 Character, // Byte, Short, Integer와 같은 몇 가지 특별한 클래스에 대해서도 동작합니다. int month = 3; String monthString; switch (month){ case 1: monthString = "January"; break; case 2: monthString = "February"; break; case 3: monthString = "March"; break; default: monthString = "Some other month"; break; } System.out.println("Switch Case Result: " + monthString); /////////////////////////////////////// // 자료형 변환과 형변환 /////////////////////////////////////// // 데이터 변환 // 문자열에서 정수로 변환 Integer.parseInt("123");// 정수 버전의 "123"을 반환 // 정수를 문자열로 변환 Integer.toString(123);// 문자열 버전의 123을 반환 // 다른 변환에 대해서는 아래 클래스를 확인해 보세요. // Double // Long // String // 형변환 // 자바 객체 또한 형변환할 수 있으며, 이와 관련해서 알아야 할 세부사항이 // 많을뿐더러 다소 중급 수준에 해당하는 개념들도 다뤄야 합니다. // 이와 관련된 사항은 아래 링크를 참고하세요. // http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html /////////////////////////////////////// // 클래스와 함수 /////////////////////////////////////// System.out.println("\n->Classes & Functions"); // (Bicycle 클래스의 정의) // 클래스를 인스턴스화하려면 new를 사용합니다. Bicycle trek = new Bicycle(); // 객체의 메서드를 호출합니다. trek.speedUp(3); // 항상 설정자 메서드와 접근자 메서드를 사용해야 합니다. trek.setCadence(100); // 현재 객체의 값을 표시할 때는 관례적으로 toString을 사용합니다. System.out.println("trek info: " + trek.toString()); } // main 메서드 끝 } // LearnJava 클래스 끝 // .java 파일 안에 다른 비공개 클래스를 포함할 수 있습니다. // 클래스 선언 문법: // class <클래스명>{ // // 데이터 필드, 생성자, 함수가 모두 이곳에 들어갑니다. // // 자바에서는 함수를 메서드라고 부릅니다. // } class Bicycle { // Bicycle의 필드와 변수 public int cadence; // Public: 어느 곳에서도 접근할 수 있습니다. private int speed; // Private: 클래스 안에서만 접근할 수 있습니다. protected int gear; // Protected: 현재 클래스와 하위 클래스에서 접근할 수 있습니다. String name; // default: 현재 패키지 안에서만 접근할 수 있습니다. // 생성자는 클래스를 생성하는 방법 중 하나입니다. // 다음은 기본 생성자입니다. public Bicycle() { gear = 1; cadence = 50; speed = 5; name = "Bontrager"; } // 다음은 구체화된 생성자입니다(인자를 담고 있습니다) public Bicycle(int startCadence, int startSpeed, int startGear, String name) { this.gear = startGear; this.cadence = startCadence; this.speed = startSpeed; this.name = name; } // 함수 문법: // <반환형> <함수명>(<인자>) // 자바 클래스는 필드에 대해 접근자 메서드와 설정자 메서드를 구현할 때가 많습니다. // 메서드 선언 문법: // <유효범위> <반환형> <메서드명>(<인자>) public int getCadence() { return cadence; } // void 메서드는 반환형이 필요하지 않습니다. public void setCadence(int newValue) { cadence = newValue; } public void setGear(int newValue) { gear = newValue; } public void speedUp(int increment) { speed += increment; } public void slowDown(int decrement) { speed -= decrement; } public void setName(String newName) { name = newName; } public String getName() { return name; } // 현재 객체의 속성값을 표시하는 메서드 @Override public String toString() { return "gear: " + gear + " cadence: " + cadence + " speed: " + speed + " name: " + name; } } // Bicycle 클래스의 끝 // PennyFarthing은 Bicycle의 하위 클래스입니다. class PennyFarthing extends Bicycle { // (페니 파딩은 앞바퀴가 굉장히 큰 자전거입니다. 기어가 없죠.) public PennyFarthing(int startCadence, int startSpeed){ // super를 이용해 부모 생성자를 호출합니다. super(startCadence, startSpeed, 0, "PennyFarthing"); } // @annotation을 이용해 재정의하는 메서드를 표시해야 합니다. // 애노테이션과 애노테이션의 용도에 관한 자세한 내용은 아래 링크를 참고하세요. // 애노테이션: http://docs.oracle.com/javase/tutorial/java/annotations/ @Override public void setGear(int gear) { gear = 0; } } ``` ## 기타 참고자료 다음 링크를 통해 다양한 주제를 이해하고 구글을 통해 구체적인 예제들을 찾아보세요. 공부할 만한 기타 주제: * [썬/오라클의 자바 자습서](http://docs.oracle.com/javase/tutorial/index.html) * [자바 접근 제한자](http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html) * [객체 지향 프로그래밍 개념](http://docs.oracle.com/javase/tutorial/java/concepts/index.html): * [상속(Inheritance)](http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html) * [다형성(Polymorphism)](http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html) * [추상화(Abstraction)](http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html) * [예외(Exceptions)](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) * [인터페이스(Interfaces)](http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html) * [제네릭(Generics)](http://docs.oracle.com/javase/tutorial/java/generics/index.html) * [자바 코딩 관례(Java Code Conventions)](http://www.oracle.com/technetwork/java/codeconv-138413.html) ================================================ FILE: ko/javascript.md ================================================ --- contributors: - ["Leigh Brenecki", "https://leigh.net.au"] translators: - ["wikibook", "http://wikibook.co.kr"] --- 자바스크립트는 넷스케이프의 브렌던 아이크(Brendan Eich)가 1995년에 만들었습니다. 원래 자바스크립트는 웹사이트를 위한 단순한 스크립트 언어를 목표로 만들어졌는데, 좀 더 복잡한 웹 애플리케이션을 만들기 위해 자바를 보완하는 역할이었지만 웹 페이지와의 긴밀한 상호작용과 브라우저에 대한 지원 기능 덕분에 웹 프론트엔드에서 자바보다 훨씬 더 보편적으로 쓰이게 됐습니다. 그렇지만 자바스크립트는 웹 브라우저에만 국한되지 않습니다. 구글 크롬의 V8 자바스크립트 엔진을 위한 독립형 런타임을 제공하는 Node.js는 점점 인기를 얻고 있습니다. ```js // 주석은 C와 비슷합니다. 한 줄짜리 주석은 두 개의 슬래시로 시작하고, /* 여러 줄 주석은 슬래시 별표로 시작해서 별표 슬래시로 끝납니다. */ // 구문은 세미콜론(;)으로 끝낼 수 있습니다. doStuff(); // 하지만 꼭 그럴 필요는 없는데, 특정 경우를 제외하고 // 새 줄이 시작할 때마다 세미콜론이 자동으로 삽입되기 때문입니다. doStuff() // 여기서는 세미콜론을 생략하겠습니다. 세미콜론을 생략할지 여부는 // 개인적인 취향이나 프로젝트의 스타일 가이드를 따릅니다. /////////////////////////////////// // 1. 숫자, 문자열, 연산자 // 자바스크립트에는 단 하나의 숫자 타입(64비트 IEEE 754 배정도 숫자)만이 // 있습니다. 3 // = 3 1.5 // = 1.5 // 모든 기초 산술 연산은 기대한 대로 동작합니다. 1 + 1 // = 2 8 - 1 // = 7 10 * 2 // = 20 35 / 5 // = 7 // 나누어 떨어지지 않는 나눗셈도 포함됩니다. 5 / 2 // = 2.5 // 비트 연산도 지원됩니다. float을 대상으로 비트 연산을 수행하면 // 32비트까지 부호가 있는 int로 변환됩니다. 1 << 2 // = 4 // 괄호를 이용하면 우선순위를 지정할 수 있습니다. (1 + 3) * 2 // = 8 // 실제 숫자가 아닌 특별한 세 가지 값이 있습니다. Infinity // 1/0 1/0과 같은 연산의 결과 -Infinity // -1/0과 같은 연산의 결과 NaN // 0/0과 같은 연산의 결과 // 불린 타입도 있습니다. true false // 문자열은 '나 "로 생성합니다. 'abc' "Hello, world" // 부정 연산에는 ! 기호를 이용합니다. !true // = false !false // = true // 동일성 연산은 == 1 == 1 // = true 2 == 1 // = false // 불일치 연산은 != 1 != 1 // = false 2 != 1 // = true // 그 밖의 비교 연산 1 < 10 // = true 1 > 10 // = false 2 <= 2 // = true 2 >= 2 // = true // 문자열은 +로 연결할 수 있습니다. "Hello " + "world!" // = "Hello world!" // 그리고 <와 >로 비교할 수 있습니다. "a" < "b" // = true // 비교 시 타입 강제변환이 수행됩니다. "5" == 5 // = true // ===를 쓰지 않는다면 말이죠. "5" === 5 // = false // charAt을 이용하면 문자열 내의 문자에 접근할 수 있습니다. "This is a string".charAt(0) // null과 undefined도 있습니다. null // 의도적으로 값이 아님을 나타내는 데 사용합니다. undefined // 값이 아직 설정되지 않음을 나타내는 데 사용합니다. // null, undefinded, NaN, 0, ""은 거짓이며, 그 밖의 다른 모든 값은 참입니다. // 참고로 0은 거짓이며, "0"은 참입니다(심지어 0 == "0"이더라도). /////////////////////////////////// // 2. 변수, 배열, 객체 // 변수는 var 키워드로 선언합니다. 자바스크립트는 동적 타입 언어라서 // 타입을 지정할 필요가 없습니다. 값을 할당할 때는 = 문자 하나를 사용합니다. var someVar = 5 // var 키워드를 지정하지 않아도 오류는 발생하지 않습니다. someOtherVar = 10 // 그렇지만 변수가 여러분이 정의한 유효범위가 아니라 // 전역 유효범위에 생성됩니다. // 값을 할당하지 않은 채로 선언한 변수는 undefined로 설정됩니다. var someThirdVar // = undefined // 변수에 수학 연산을 수행하는 축약형 표현은 다음과 같습니다. someVar += 5 // someVar = someVar + 5;와 같음. 이제 someVar는 10. someVar *= 10 // somVar는 100 // 1을 더하거나 빼는 훨씬 더 짧은 표현도 있습니다. someVar++ // 이제 someVar는 101 someVar-- // 다시 100으로 되돌아감 // 배열은 순차적인 임의 타입 값의 목록입니다. var myArray = ["Hello", 45, true] // 배열의 멤버는 대괄호로 둘러싼 인덱스를 이용해 접근할 수 있습니다. // 배열의 인덱스는 0부터 시작합니다. myArray[1] // = 45 // 자바스크립트의 객체는 다른 언어의 '사전'이나 '맵'과 같습니다. // 즉, 키-값 쌍으로 구성된 비순차 컬렉션입니다. {key1: "Hello", key2: "World"} // 키는 문자열이지만 유효한 자바스크립트 식별자일 경우 // 작은따옴표는 필요하지 않습니다. 값은 어떤 타입이든 사용할 수 있습니다. var myObj = {myKey: "myValue", "my other key": 4} // 객체 속성에도 인덱스를 이용해 접근할 수 있습니다. myObj["my other key"] // = 4 // 또는 키가 유효한 식별자일 경우 점 표기법을 이용해 접근할 수 있습니다. myObj.myKey // = "myValue" // 객체는 변경 가능합니다. 즉, 값을 변경하거나 새 키를 추가할 수 있습니다. myObj.myThirdKey = true // 설정되지 않은 값에 접근하려고 하면 undefined가 반환됩니다. myObj.myFourthKey // = undefined /////////////////////////////////// // 3. 로직과 제어 구조 // if 구조는 여러분이 예상한 대로 동작합니다. var count = 1 if (count == 3){ // count가 3일 경우 평가됨 } else if (count == 4) { // count가 4일 경우 평가됨 } else { // count가 3이나 4가 아닌 경우에 평가됨 } // while도 마찬가지입니다. while (true) { // 무한 루프! } // do-while 문은 항상 최소 한 번은 실행된다는 점을 제외하면 // while 문과 비슷합니다. var input do { input = getInput() } while (!isValid(input)) // for 문은 C와 자바의 for 문과 같습니다. // 초기화식; 지속 조건; 증감식 for (var i = 0; i < 5; i++){ // 5번 실행됨 } // &&는 논리 and이고 ||는 논리 or입니다. if (house.size == "big" && house.colour == "blue"){ house.contains = "bear" } if (colour == "red" || colour == "blue"){ // 색은 빨강이거나 파랑 } // &&와 ||은 "단축 평가"를 수행하는데, 기본값을 설정할 때 유용합니다. var name = otherName || "default" /////////////////////////////////// // 4. 함수, 유효범위, 클로저 // 자바스크립트 함수는 function 키워드로 선언합니다. function myFunction(thing){ return thing.toUpperCase() } myFunction("foo") // = "FOO" // 함수는 "익명"으로, 즉 이름 없이 정의할 수도 있습니다. function(thing){ return thing.toLowerCase() } // (함수를 가리키는 이름이 없기 때문에 함수를 호출할 수 없습니다) // 자바스크립트 함수는 일급 객체이므로 다른 변수에 재할당하고 // 다른 함수에 인자로 전달할 수 있습니다. 가령, 이벤트 핸들러를 만들 경우 function myFunction(){ // 이 코드는 5초 내에 호출됨 } setTimeout(myFunction, 5000) // 다른 함수를 호출할 때 직접적으로 함수 구문을 작성할 수도 있습니다. setTimeout(function myFunction(){ // 이 코드는 5초 내에 호출됨 }, 5000) // 자바스크립트에는 함수 유효범위가 있습니다. // 함수는 자체적인 유효범위를 가지지만 다른 블록은 유효범위를 가지지 않습니다. if (true){ var i = 5 } i // = 5 - 블록 유효범위를 지원하는 언어에서는 undefined가 아닙니다. // 이것은 "즉시 실행되는 익명 함수"라는 공통 패턴으로 이어지는데, // 이 패턴은 임시 변수가 전역 유효범위로 유출되는 것을 방지합니다. (function(){ var temporary = 5 // '전역 객체'에 할당하는 식으로 전역 유효범위에 접근할 수 있는데, // 브라우저에서 전역 객체는 항상 'window'입니다. 전역 객체는 // Node.js와 같은 브라우저가 아닌 환경에서는 다른 이름일 수도 있습니다. window.permanent = 10 // 또는 앞에서 언급했다시피 var 키워드를 뺄 수도 있습니다. permanent2 = 15 })() temporary // ReferenceError 발생 permanent // = 10 permanent2 // = 15 // 자바스크립트의 강력한 기능 중 하나는 클로저(closure)입니다. // 함수가 다른 함수 안에서 정의되면 안쪽에 정의된 함수는 바깥 함수의 // 모든 변수에 접근할 수 있습니다. function sayHelloInFiveSeconds(name){ var prompt = "Hello, " + name + "!" function inner(){ alert(prompt) } setTimeout(inner, 5000) // setTimeout은 비동기적으로 동작하므로 이 함수는 5초 동안 // 기다리지 않고 실행을 마칩니다. 하지만 5초가 지나면 inner에서도 // prompt의 값에 접근할 수 있습니다. } sayHelloInFiveSeconds("Adam") // 5초 내로 "Hello, Adam!"이라고 적힌 팝업이 표시됨 /////////////////////////////////// // 5. 객체 심화; 생성자와 프로토타입 // 객체는 함수를 포함할 수 있습니다. var myObj = { myFunc: function(){ return "Hello world!" } } myObj.myFunc() // = "Hello world!" // 객체에 포함된 함수가 호출되면 함수에서는 this 키워드를 이용해 // 해당 함수가 포함된 객체에 접근할 수 있습니다. myObj = { myString: "Hello world!", myFunc: function(){ return this.myString } } myObj.myFunc() // = "Hello world!" // 여기서 설정한 것은 함수가 정의된 곳이 아닌 함수가 호출되는 // 방식과 관련이 있습니다. 그래서 아래 함수는 객체 컨텍스트에서 // 호출되지 않으면 동작하지 않습니다. var myFunc = myObj.myFunc myFunc() // = undefined // 반대로 함수는 객체에 할당하고 this를 통해 해당 객체에 접근할 수 있습니다. // 함수를 정의할 때 객체에 추가되지 않았더라도 마찬가지입니다. var myOtherFunc = function(){ return this.myString.toUpperCase() } myObj.myOtherFunc = myOtherFunc myObj.myOtherFunc() // = "HELLO WORLD!" // new 키워드로 함수를 호출하면 새로운 객체가 생성되고 this를 통해 // 함수에서 사용할 수 있게 됩니다. 이런 식으로 설계된 함수를 생성자라 합니다. var MyConstructor = function(){ this.myNumber = 5 } myNewObj = new MyConstructor() // = {myNumber: 5} myNewObj.myNumber // = 5 // 모든 자바스크립트 객체는 'prototype'을 가지고 있습니다. 어떤 객체에 대해 // 실제 객체에는 존재하지 않는 프로퍼티에 접근하면 인터프리터는 프로로타입에서 // 해당 프로퍼티를 찾습니다. // 일부 자바스크립트 구현체에서는 __proto__라는 마법의 프로퍼티로 // 객체의 프로토타입에 접근하는 것을 허용하기도 합니다. 프로토타입을 // 설명하기에는 이런 내용도 도움되겠지만 __proto__는 표준에 포함돼 // 있지 않습니다. 나중에 프로토타입을 사용하는 표준 방법을 살펴보겠습니다. var myObj = { myString: "Hello world!", } var myPrototype = { meaningOfLife: 42, myFunc: function(){ return this.myString.toLowerCase() } } myObj.__proto__ = myPrototype myObj.meaningOfLife // = 42 // 이 방법은 함수에도 통합니다. myObj.myFunc() // = "hello world!" // 물론 프로퍼티가 프로토타입에 존재하지 않으면 // 프로토타입의 프로토타입을 찾는 식으로 진행됩니다. myPrototype.__proto__ = { myBoolean: true } myObj.myBoolean // = true // 여기서 복사는 일어나지 않습니다. 각 객체에는 프로토타입에 대한 // 참조가 보관돼 있습니다. 이는 프로토타입을 변경하면 변경사항이 // 모든 곳에 반영된다는 의미입니다. myPrototype.meaningOfLife = 43 myObj.meaningOfLife // = 43 // 앞에서 __proto__가 표준에 포함돼 있지 않다고 이야기했는데, // 기존 객체의 프로토타입을 변경하는 표준 방법은 없습니다. // 하지만 특정 프로토타입을 가지고 새로운 객체를 생성하는 두 가지 // 방법이 있습니다. // 첫 번째 방법은 Object.create를 이용하는 것인데, // Object.create는 최근에 자바스크립트에 추가된 것이라서 아직까지 // 모든 구현체에서 이용할 수 있는 것은 아닙니다. var myObj = Object.create(myPrototype) myObj.meaningOfLife // = 43 // 두 번째 방법은 어디서나 통하는 방법인데, 생성자와 관련이 있습니다. // 생성자에는 prototype이라는 프로퍼티가 있습니다. 이 프로퍼티는 // 생성자 함수 자체의 프로토타입이 *아니고* 생성자와 new 키워드를 이용해 // 객체가 생성될 때 새로운 객체가 받는 프로토타입입니다. myConstructor.prototype = { getMyNumber: function(){ return this.myNumber } } var myNewObj2 = new myConstructor() myNewObj2.getMyNumber() // = 5 // 문자열과 숫자와 같은 내장 타입에도 동등한 래퍼 객체를 // 생성하는 생성자가 있습니다. var myNumber = 12 var myNumberObj = new Number(12) myNumber == myNumberObj // = true // 하지만 정확히 같지는 않습니다. typeof myNumber // = 'number' typeof myNumberObj // = 'object' myNumber === myNumberObj // = false if (0){ // 0은 거짓이라서 이 코드는 실행되지 않습니다. } // 하지만 래퍼 객체와 일반 내장 함수는 프로토타입을 공유하기 때문에 // 가령 문자열에 실제로 기능을 추가할 수 있습니다. String.prototype.firstCharacter = function(){ return this.charAt(0) } "abc".firstCharacter() // = "a" // 이러한 사실은 기존 자바스크립트 버전에서 자바스크립트의 // 새로운 기능을 구현하는 "폴리필(polyfilling)"에 자주 이용되므로 // 오래된 버전의 브라우저와 같이 기존 환경에서 사용될 수 있습니다. // 예를 들어, Object.create가 모든 구현체에서 사용 가능한 것은 아니라고 // 했지만 아래의 폴리필을 이용해 Object.create를 여전히 사용할 수 있습니다. if (Object.create === undefined){ // 이미 존재하면 덮어쓰지 않음 Object.create = function(proto){ // 올바른 프로토타입을 가지고 임시 생성자를 만듬 var Constructor = function(){} Constructor.prototype = proto // 그런 다음 임시 생성자를 이용해 새로운 적절한 프로토타입을 // 포함한 객체를 생성 return new Constructor() } } ``` ## 기타 참고 자료 [모질라 개발자 네트워크](https://developer.mozilla.org/en-US/docs/Web/JavaScript)에서는 자바스크립트에 대한 훌륭한 문서를 제공합니다. 더불어 위키 형식이라서 좀 더 많은 사항을 배우게 되면 여러분만의 지식을 공유함으로써 다른 사람들에게 도움을 줄 수도 있습니다. MDN의 ['자바스크립트 재입문'](https://developer.mozilla.org/ko/docs/A_re-introduction_to_JavaScript)에서는 여기서 다룬 개념의 상당수를 더욱 자세히 다루고 있습니다. 이 자료에서는 자바스크립트 언어 자체에 대해서만 상당히 신중하게 다뤘습니다. 웹 페이지에서 자바스크립트를 사용하는 방법을 배우고 싶다면 [문서 객체 모델(Document Object Model)](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core)에 관해 배우는 것으로 시작하길 바랍니다. [자바스크립트 가든](https://shamansir.github.io/JavaScript-Garden/)에서는 자바스크립트 언어에서 직관에 어긋나는 모든 부분들을 심도 있게 다룹니다. 더불어 이 글에 직접적으로 기여한 분들로, 내용 중 일부는 이 사이트에 있는 루이 딘(Louie Dihn)의 파이썬 튜토리얼과 모질라 개발자 네트워크에 있는 [자바스크립트 튜토리얼](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)을 참고했습니다. ================================================ FILE: ko/json.md ================================================ --- contributors: - ["Anna Harren", "https://github.com/iirelu"] - ["Marco Scannadinari", "https://github.com/marcoms"] - ["himanshu", "https://github.com/himanshu81494"] - ["Michael Neth", "https://github.com/infernocloud"] translators: - ["Wooseop Kim", "https://github.com/linterpreteur"] --- JSON은 아주 간단한 데이터 교환 포맷입니다. [json.org](http://json.org/json-ko.html)에 의하면, 사람이 읽고 쓰기 쉬우며 기계가 분석하고 생성하기 쉽습니다. JSON 한 개는 반드시 이하의 둘 중 하나를 나타내야 합니다. * 이름과 값 쌍의 모임(`{ }`). 이는 다양한 언어에서 객체, 레코드, 구조체, 딕셔너리, 해시 테이블, 키 리스트, 혹은 연관 배열로 구현됩니다. * 값에 순서가 있는 리스트 (`[ ]`). 이는 다양한 언어에서 배열, 벡터, 리스트, 시퀀스로 구현됩니다. 순수한 JSON은 사실 주석이 없지만 대부분의 파서는 C 스타일의 주석(`//`, `/* */`)도 받아들일 겁니다. 일부 파서는 꼬리에 오는 쉼표, 즉 배열의 마지막 원소 혹은 객체의 마지막 속성 다음에 오는 쉼표도 인정하겠지만, 호환성을 위해 쓰지 않는 것이 좋습니다. 이 튜토리얼의 목적에 따라 모든 것은 100% 유효한 JSON입니다. 다행스럽게도 JSON은 다소 자기서술적입니다. 지원하는 데이터 형: * 문자열: `"안녕"`, `"\"따옴표.\""`, `"\u0abe"`, `"개행 문자.\n"` * 수: `23`, `0.11`, `12e10`, `3.141e-10`, `1.23e+4` * 객체: `{ "키": "값" }` * 배열: `["값 값 값"]` * 기타: `true`, `false`, `null` ```json { "키": "값", "키는": "반드시 큰따옴표 안에 있어야 합니다.", "수": 0, "문자열": "Hellø, wørld. 모든 유니코드와 \"탈출 문자\"가 지원됩니다.", "부울도 있나?": true, "아무 것도 없는 건": null, "큰 수": 1.2e+100, "객체": { "주석": "문서 구조의 대부분은 객체가 될 것입니다.", "배열": [0, 1, 2, 3, "배열 안에는 무엇이든 올 수 있습니다.", 5], "다른 객체": { "주석": "객체는 객체를 포함할 수 있습니다. 아주 유용하죠." } }, "장난이지롱": [ { "칼륨이 풍부한": ["바나나"] }, [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, "neo"], [0, 0, 0, 1] ] ], "다른 방식": { "주석": "여기 보세요!" , "쉼표의 위치는": "상관 없습니다. 다음 키 전에만 온다면 유효합니다." , "다른 주석": "참 좋죠" }, "공백은": "상관이 없습니다.", "짧았죠": "끝입니다. JSON의 모든 것을 터득하셨습니다." } ``` ## 더 읽기 * [JSON.org](http://json.org/json-ko.html) 플로우차트와 같은 그래픽을 이용해 설명한 JSON의 모든 것. ================================================ FILE: ko/kotlin.md ================================================ --- contributors: - ["S Webber", "https://github.com/s-webber"] translators: - ["Alan Jeon", "https://github.com/skyisle"] --- Kotlin 은 정적 타입 프로그래밍 언어로 JVM, 안드로이드, 브라우져를 지원하며 Java 와 100% 상호 운용이 가능합니다. [자세한 내용은 다음을 참고하세요.](https://kotlinlang.org/) ```kotlin // 한 줄짜리 주석은 // 로 시작합니다. /* 여러 줄 주석은 이와 같이 표시합니다. */ // "package" 예약어는 자바와 동일하게 사용됩니다. package com.learnxinyminutes.kotlin /* Kotlin 프로그램의 진입점은 main 이라는 함수명으로 지정됩니다. 이 함수에 명령행 인수가 배열로 전달됩니다. */ fun main(args: Array) { /* 값을 선언할때는 "var" 또는 "val"이 사용됩니다. "var"와는 다르게 "val"로 선언된 변수에는 값을 재할당 할 수 없습니다. */ val fooVal = 10 // fooVal 에 다른 값을 다시 할당 할 수 없습니다. var fooVar = 10 fooVar = 20 // fooVar 에는 선언 이후에도 다른 값을 할당 할 수 있습니다 /* 대부분의 경우, Kotlin 에서는 변수 타입을 판단할 수 있기때문에 명시적으로 지정해 주지 않을 수 있습니다. 다음과 같이 변수의 타입을 명시적으로 지정할 수 있습니다. */ val foo: Int = 7 /* 문자형은 Java와 비슷하게 표시될 수 있습니다. 이스케이핑에는 백슬래시를 사용합니다. */ val fooString = "My String Is Here!" val barString = "Printing on a new line?\nNo Problem!" val bazString = "Do you want to add a tab?\tNo Problem!" println(fooString) println(barString) println(bazString) /* Raw 문자열은 쌍따옴표 3개(""")로 표기합니다. Raw 문자열에는 줄바꿈이나 모든 다른 문자들을 사용할 수 있습니다. */ val fooRawString = """ fun helloWorld(val name : String) { println("Hello, world!") } """ println(fooRawString) /* 문자열은 템플릿 표현식을 포함할 수 있습니다. 템플릿은 달러 기호($)로 시작합니다. */ val fooTemplateString = "$fooString has ${fooString.length} characters" println(fooTemplateString) /* 변수가 null 값을 가지려면 이를 명시적으로 선언해야 합니다. 변수 선언시 타입에 ? 표시를 붙여 nullable 을 표시합니다. ?. 연산자를 사용해 nullable 변수에 접근합니다. ?: 연산자를 이용해서 변수 값이 null 일때 사용할 값을 지정합니다. */ var fooNullable: String? = "abc" println(fooNullable?.length) // => 3 println(fooNullable?.length ?: -1) // => 3 fooNullable = null println(fooNullable?.length) // => null println(fooNullable?.length ?: -1) // => -1 /* 함수는 "fun" 예약어를 사용해 선언합니다. 함수명 이후 괄호 안에 인자를 기술합니다. 함수 인자에 기본 값을 지정할 수도 있습니다. 함수에 리턴값이 있을 때, 필요한 경우 인자 뒤에 타입을 명시합니다. */ fun hello(name: String = "world"): String { return "Hello, $name!" } println(hello("foo")) // => Hello, foo! println(hello(name = "bar")) // => Hello, bar! println(hello()) // => Hello, world! /* 함수에 가변 인자를 넘기려면 인자에 "vararg" 예약어를 사용합니다. */ fun varargExample(vararg names: Int) { println("Argument has ${names.size} elements") } varargExample() // => 인자가 0개 인 경우 varargExample(1) // => 인자가 1개인 경우 varargExample(1, 2, 3) // => 인자가 3개인 경우 /* 함수가 단일 표현식으로 이루어진 경우에 중괄호를 생략할 수 있습니다. 이때 함수 구현부는 = 기호 이후에 기술합니다. */ fun odd(x: Int): Boolean = x % 2 == 1 println(odd(6)) // => false println(odd(7)) // => true // 리턴 타입이 유추 가능한 경우 이를 명시하지 않아도 됩니다. fun even(x: Int) = x % 2 == 0 println(even(6)) // => true println(even(7)) // => false // 함수는 함수를 인자를 받을 수 있고 함수를 리턴할 수 있습니다. fun not(f: (Int) -> Boolean): (Int) -> Boolean { return {n -> !f.invoke(n)} } // 함수는 :: 연산자를 사용해서 다른 함수에 인자로 넘길 수 있습니다. val notOdd = not(::odd) val notEven = not(::even) // 람다식을 인자로 사용할 수 있습니다. val notZero = not {n -> n == 0} /* 하나의 인자를 가지는 람다식의 선언부와 -> 연산자는 생략될 수 있습니다. 이때 그 인자명은 it로 지정됩니다. */ val notPositive = not {it > 0} for (i in 0..4) { println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}") } // "class" 예약어는 클래스를 선언할 때 사용됩니다. class ExampleClass(val x: Int) { fun memberFunction(y: Int): Int { return x + y } infix fun infixMemberFunction(y: Int): Int { return x * y } } /* 새로운 객체를 생성하기 위해서는 생성자를 바로 호출합니다. Kotlin 에서는 new 예약어가 없다는 걸 기억하세요. */ val fooExampleClass = ExampleClass(7) // 맴버 함수는 dot 표기로 호출할 수 있습니다. println(fooExampleClass.memberFunction(4)) // => 11 /* 함수 선언에 "infix" 예약어를 사용하면 이 함수를 중위 표현식(infix notation)으로 호출할 수 있습니다 */ println(fooExampleClass infixMemberFunction 4) // => 28 /* 데이터 클래스로 데이터만을 가지고 있는 클래스를 손쉽게 선언할 수 있습니다. "hashCode"/"equals" 와 "toString" 는 자동으로 생성됩니다. */ data class DataClassExample (val x: Int, val y: Int, val z: Int) val fooData = DataClassExample(1, 2, 4) println(fooData) // => DataClassExample(x=1, y=2, z=4) // 데이터 클래스는 copy 함수를 가지고 있습니다. val fooCopy = fooData.copy(y = 100) println(fooCopy) // => DataClassExample(x=1, y=100, z=4) // 객체를 여러 변수로 분리할 수 있습니다. val (a, b, c) = fooCopy println("$a $b $c") // => 1 100 4 // "for" 루프에서 변수 분리 하기 for ((a, b, c) in listOf(fooData)) { println("$a $b $c") // => 1 100 4 } val mapData = mapOf("a" to 1, "b" to 2) // Map.Entry 또한 키와 값으로 분리가 가능합니다. for ((key, value) in mapData) { println("$key -> $value") } // "with" 함수는 JavaScript 의 "with" 구문과 비슷하게 사용됩니다. data class MutableDataClassExample (var x: Int, var y: Int, var z: Int) val fooMutableData = MutableDataClassExample(7, 4, 9) with (fooMutableData) { x -= 2 y += 2 z-- } println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8) /* "listOf" 함수로 리스트를 만들 수 있습니다. 리스트는 변경 불가능(immutable)하게 만들어져 항목의 추가 삭제가 불가능합니다. */ val fooList = listOf("a", "b", "c") println(fooList.size) // => 3 println(fooList.first()) // => a println(fooList.last()) // => c // 각 항목은 인덱스로 접근이 가능합니다. println(fooList[1]) // => b // 변경가능한(mutable) 리스트는 "mutableListOf" 함수로 만들 수 있습니다. val fooMutableList = mutableListOf("a", "b", "c") fooMutableList.add("d") println(fooMutableList.last()) // => d println(fooMutableList.size) // => 4 // 집합(set)은 "setOf" 함수로 만들 수 있습니다. val fooSet = setOf("a", "b", "c") println(fooSet.contains("a")) // => true println(fooSet.contains("z")) // => false // 맵은 "mapOf" 함수로 만들 수 있습니다. val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9) // 맵은 키를 통해 그 값에 접근할 수 있습니다. Map values can be accessed by their key. println(fooMap["a"]) // => 8 /* 시퀀스는 지연 평가되는 컬랙션을 말합니다. Sequences represent lazily-evaluated collections. "generateSequence" 를 사용해 시퀀스를 만들 수 있습니다. We can create a sequence using the "generateSequence" function. */ val fooSequence = generateSequence(1, { it + 1 }) val x = fooSequence.take(10).toList() println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 다음은 시퀀스를 사용해서 피보나치 수열을 생성하는 예입니다. fun fibonacciSequence(): Sequence { var a = 0L var b = 1L fun next(): Long { val result = a + b a = b b = result return a } return generateSequence(::next) } val y = fibonacciSequence().take(10).toList() println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] // Kotlin 은 컬랙션에서 사용할 수 있는 고차(higher-order)함수를 제공합니다. val z = (1..9).map {it * 3} .filter {it < 20} .groupBy {it % 2 == 0} .mapKeys {if (it.key) "even" else "odd"} println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]} // "for" 루프는 이터레이터를 제공하는 어떤 것과도 함께 사용할 수 있습니다. for (c in "hello") { println(c) } // "while" 루프는 다른 언어들과 동일하게 사용됩니다. var ctr = 0 while (ctr < 5) { println(ctr) ctr++ } do { println(ctr) ctr++ } while (ctr < 10) /* "if"는 값을 리턴하는 표현으로 사용될 수 있습니다. 그래서 Kotlin 에서는 삼항 ?: 연산자가 필요하지 않습니다. */ val num = 5 val message = if (num % 2 == 0) "even" else "odd" println("$num is $message") // => 5 is odd // "when"은 "if-else if" 를 대체할때 사용할 수 있습니다. val i = 10 when { i < 7 -> println("first block") fooString.startsWith("hello") -> println("second block") else -> println("else block") } // "when"은 인수와 함께 사용될 수 있습니다. when (i) { 0, 21 -> println("0 or 21") in 1..20 -> println("in the range 1 to 20") else -> println("none of the above") } // "when"은 값을 리턴하는 함수처럼 사용될 수 있습니다. var result = when (i) { 0, 21 -> "0 or 21" in 1..20 -> "in the range 1 to 20" else -> "none of the above" } println(result) /* 객체가 어떤 타입인지를 확인하기 위해 "is" 연산자를 사용할 수 있습니다. 타입 체크를 통과하면 객체의 명시적인 형변환 없이도 그 타입 값으로 사용될 수 있습니다. 이를 스마트 변환(Smartcast)이라 부릅니다. */ fun smartCastExample(x: Any) : Boolean { if (x is Boolean) { // x is automatically cast to Boolean return x } else if (x is Int) { // x is automatically cast to Int return x > 0 } else if (x is String) { // x is automatically cast to String return x.isNotEmpty() } else { return false } } println(smartCastExample("Hello, world!")) // => true println(smartCastExample("")) // => false println(smartCastExample(5)) // => true println(smartCastExample(0)) // => false println(smartCastExample(true)) // => true // 스마트 변환은 when 블럭과도 함께 사용됩니다. fun smartCastWhenExample(x: Any) = when (x) { is Boolean -> x is Int -> x > 0 is String -> x.isNotEmpty() else -> false } /* 확장(Extensions)을 이용해 클래스에 새로운 기능을 추가할 수 있습니다. C#에서의 확장 매서드와 유사합니다. */ fun String.remove(c: Char): String { return this.filter {it != c} } println("Hello, world!".remove('l')) // => Heo, word! println(EnumExample.A) // => A println(ObjectExample.hello()) // => hello } // Enum 클래스는 자바의 enum 타입과 유사합니다. enum class EnumExample { A, B, C } /* "object" 예약어는 싱클톤 객체를 생성할 때 사용됩니다. 객체를 새로 생성할 수는 없지만 이름을 가지고 접근해 사용할 수 있습니다. 이는 스칼라의 싱글톤 객체와 유사합니다. */ object ObjectExample { fun hello(): String { return "hello" } } fun useObject() { ObjectExample.hello() val someRef: Any = ObjectExample // 객체의 이름을 그대로 사용합니다. } ``` ### 더 알아보기 * [Kotlin tutorials (EN)](https://kotlinlang.org/docs/tutorials/) * [Try Kotlin in your browser (EN)](http://try.kotlinlang.org/) * [A list of Kotlin resources (EN)](http://kotlin.link/) ================================================ FILE: ko/lua.md ================================================ --- contributors: - ["Tyler Neylon", "http://tylerneylon.com/"] translators: - ["wikibook", "http://wikibook.co.kr"] --- ```lua -- 대시 두 개는 한 줄짜리 주석을 의미합니다. --[[ [와 ]를 두 개씩 추가하면 여러 줄 주석이 됩니다. --]] ---------------------------------------------------- -- 1. 변수와 흐름 제어 ---------------------------------------------------- num = 42 -- 모든 숫자는 double입니다. -- 놀랄 필요는 없습니다. 64비트 double은 -- 정확한 int 값을 저장하기 위해 52비트로 구성돼 -- 있습니다. 52비트 이하의 int 값에 대해서는 -- 장비 정밀도와 관련된 문제가 생기지 않습니다. s = 'walternate' -- 파이썬과 같은 불변 문자열 t = "큰따옴표를 써도 됩니다" u = [[ 이중 대괄호는 여러 줄 문자열을 나타냅니다.]] t = nil -- 미정의 t. 루아는 가비지 컬렉션을 지원합니다. -- 블록은 do/end와 같은 키워드로 나타냅니다: while num < 50 do num = num + 1 -- ++나 += 유형의 연산자는 쓸 수 없습니다. end -- If 절: if num > 40 then print('40 이상') elseif s ~= 'walternate' then -- ~=은 '같지 않다'입니다. -- 동일성 검사는 파이썬과 마찬가지로 ==입니다. -- 문자열에도 쓸 수 있습니다. io.write('not over 40\n') -- 기본적으로 stdout에 씁니다. else -- 변수는 기본적으로 전역 변수입니다. thisIsGlobal = 5 -- 낙타 표기법이 일반적입니다. -- 변수를 지역 변수로 만드는 방법은 다음과 같습니다: local line = io.read() -- 다음 stdin 줄을 읽습니다 -- 문자열 연결에는 .. 연산자를 씁니다: print('겨울이 오고 있습니다, ' .. line) end -- 미정의 변수는 nil을 반환합니다. -- 다음 코드를 실행해도 오류가 나지 않습니다: foo = anUnknownVariable -- 이제 foo는 nil입니다. aBoolValue = false -- nil과 false만이 거짓값입니다; 0과 ''은 참입니다! if not aBoolValue then print('twas false') end -- 'or'와 'and'는 단축 평가(short-circuit)됩니다. -- 다음 코드는 C/자바스크립트의 a?b:c 연산자와 비슷합니다: ans = aBoolValue and 'yes' or 'no' --> 'no' karlSum = 0 for i = 1, 100 do -- 범위에는 마지막 요소도 포함됩니다. karlSum = karlSum + i end -- 카운트 다운을 할 때는 "100, 1, -1"을 범위로 씁니다. fredSum = 0 for j = 100, 1, -1 do fredSum = fredSum + j end -- 일반적으로 범위는 begin, end[, step]입니다. -- 또 다른 반복문 구문은 다음과 같습니다: repeat print('미래의 방식') num = num - 1 until num == 0 ---------------------------------------------------- -- 2. 함수 ---------------------------------------------------- function fib(n) if n < 2 then return n end return fib(n - 2) + fib(n - 1) end -- 클로저와 익명 함수도 사용할 수 있습니다: function adder(x) -- 반환된 함수는 adder가 호출될 때 생성되고 x의 -- 값이 유지됩니다: return function (y) return x + y end end a1 = adder(9) a2 = adder(36) print(a1(16)) --> 25 print(a2(64)) --> 100 -- 반환문, 함수 호출, 할당문은 길이가 다른 -- 값의 리스트에 대해서도 모두 동작합니다. -- 리스트에 값이 더 적을 때는 nil이 할당/반환되고 -- 리스트에 값이 더 많을 때는 나머지 값은 버려집니다. x, y, z = 1, 2, 3, 4 -- 이제 x = 1, y = 2, z = 3이고 4는 버려집니다. function bar(a, b, c) print(a, b, c) return 4, 8, 15, 16, 23, 42 end x, y = bar('zaphod') --> "zaphod nil nil"가 출력 -- 이제 x = 4, y = 8이고 15~42의 값은 버려집니다. -- 함수는 일급 객체이고, 지역/전역 유효범위를 가질 -- 수 있습니다. 아래의 두 함수는 같습니다: function f(x) return x * x end f = function (x) return x * x end -- 그리고 아래의 두 함수도 마찬가지입니다: local function g(x) return math.sin(x) end local g; g = function (x) return math.sin(x) end -- 'local g'라고 선언하면 g를 지역 함수로 만듭니다. -- 그나저나 삼각 함수는 라디안 단위로 동작합니다. -- 함수를 호출할 때 문자열 매개변수를 하나만 전달한다면 -- 괄호를 쓰지 않아도 됩니다: print 'hello' -- 잘 동작합니다. ---------------------------------------------------- -- 3. 테이블 ---------------------------------------------------- -- 테이블 = 루아의 유일한 복합 자료구조로서, 연관 배열입니다. -- PHP의 배열이나 자바스크립트의 객체와 비슷하며, -- 리스트로도 사용할 수 있는 해시 기반의 딕셔너리입니다. -- 테이블을 딕셔너리/맵으로 사용하기: -- 딕셔너리 리터럴은 기본적으로 문자열 키를 가집니다: t = {key1 = 'value1', key2 = false} -- 문자열 키에는 자바스크립트와 유사한 점 표기법을 쓸 수 있습니다: print(t.key1) -- 'value1'을 출력. t.newKey = {} -- 새 키/값 쌍을 추가. t.key2 = nil -- 테이블에서 key2를 제거. -- (nil이 아닌) 값을 키로 사용하는 리터럴 표기법: u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} print(u[6.28]) -- "tau"가 출력 -- 키 매칭은 기본적으로 숫자와 문자열에 대해서는 값으로 하지만 -- 테이블에 대해서는 식별자로 합니다. a = u['@!#'] -- 이제 a는 'qbert'입니다. b = u[{}] -- 1729를 예상했겠지만 nil입니다: -- 탐색이 실패하기 때문에 b는 nil입니다. 탐색이 실패하는 이유는 -- 사용된 키가 원본 값을 저장할 때 사용한 키와 동일한 객체가 아니기 -- 때문입니다. 따라서 문자열 및 숫자가 좀 더 이식성 있는 키입니다. -- 테이블 하나를 매개변수로 취하는 함수를 호출할 때는 괄호가 필요하지 않습니다: function h(x) print(x.key1) end h{key1 = 'Sonmi~451'} -- 'Sonmi~451'를 출력. for key, val in pairs(u) do -- 테이블 순회 print(key, val) end -- _G는 모든 전역 멤버에 대한 특별한 테이블입니다. print(_G['_G'] == _G) -- 'true'가 출력 -- 테이블을 리스트/배열로 사용하기: -- 리스트 리터럴은 암묵적으로 int 키로 설정됩니다: v = {'value1', 'value2', 1.21, 'gigawatts'} for i = 1, #v do -- #v는 리스트 v의 크기입니다. print(v[i]) -- 인덱스가 1에서 시작합니다!! 제정신이 아닙니다! end -- 'list'는 실제 타입이 아닙니다. v는 연속된 정수형 키가 포함된 -- 테이블이고 리스트로 취급될 뿐입니다. ---------------------------------------------------- -- 3.1 메타테이블과 메타메서드 ---------------------------------------------------- -- 테이블은 테이블에 연산자 오버로딩을 가능하게 하는 메타테이블을 -- 가질 수 있습니다. 나중에 메타테이블이 어떻게 자바스크립트 -- 프로토타입과 같은 행위를 지원하는지 살펴보겠습니다. f1 = {a = 1, b = 2} -- 분수 a/b를 표현 f2 = {a = 2, b = 3} -- 다음 코드는 실패합니다: -- s = f1 + f2 metafraction = {} function metafraction.__add(f1, f2) sum = {} sum.b = f1.b * f2.b sum.a = f1.a * f2.b + f2.a * f1.b return sum end setmetatable(f1, metafraction) setmetatable(f2, metafraction) s = f1 + f2 -- f1의 메타테이블을 대상으로 __add(f1, f2)를 호출 -- f1과 f2는 자바스크립트의 프로토타입과 달리 각 메타테이블에 대한 -- 키가 없어서 getmetatable(f1)과 같이 받아와야 합니다. -- 메타테이블은 __add 같은 루아가 알고 있는 키가 지정된 일반 테이블입니다. -- 그렇지만 다음 줄은 s가 메타테이블을 가지고 있지 않기 때문에 실패합니다. -- t = s + s -- 아래와 같이 클래스와 유사한 패턴은 이러한 문제가 발생하지 않습니다. -- 메타테이블에 대한 __index는 점을 이용한 탐색을 오버로드합니다: defaultFavs = {animal = 'gru', food = 'donuts'} myFavs = {food = 'pizza'} setmetatable(myFavs, {__index = defaultFavs}) eatenBy = myFavs.animal -- 동작합니다! 고마워요, 메타테이블! -- 직접적인 테이블 탐색이 실패할 경우 메타테이블의 __index 값을 이용해 -- 재시도하고, 이런 과정이 반복됩니다. -- __index 값은 좀 더 세분화된 탐색을 위해 function(tbl, key)가 -- 될 수도 있습니다. -- __index, __add, ...의 값을 메타메서드라고 합니다. -- 다음은 메타메서드를 가진 테이블의 전체 목록입니다. -- __add(a, b) for a + b -- __sub(a, b) for a - b -- __mul(a, b) for a * b -- __div(a, b) for a / b -- __mod(a, b) for a % b -- __pow(a, b) for a ^ b -- __unm(a) for -a -- __concat(a, b) for a .. b -- __len(a) for #a -- __eq(a, b) for a == b -- __lt(a, b) for a < b -- __le(a, b) for a <= b -- __index(a, b) for a.b -- __newindex(a, b, c) for a.b = c -- __call(a, ...) for a(...) ---------------------------------------------------- -- 3.2 클래스 형태의 테이블과 상속 ---------------------------------------------------- -- 루아에는 클래스가 내장돼 있지 않으며, 테이블과 메타테이블을 -- 이용해 클래스를 만드는 다양한 방법이 있습니다. -- 다음 예제에 대한 설명은 하단을 참조합니다. Dog = {} -- 1. function Dog:new() -- 2. newObj = {sound = 'woof'} -- 3. self.__index = self -- 4. return setmetatable(newObj, self) -- 5. end function Dog:makeSound() -- 6. print('I say ' .. self.sound) end mrDog = Dog:new() -- 7. mrDog:makeSound() -- 'I say woof' -- 8. -- 1. Dog는 클래스처럼 동작합니다. 실제로는 테이블입니다. -- 2. function 테이블명:fn(...)은 -- function 테이블명.fn(self, ...)과 같습니다. -- :는 self라는 첫 번째 인자를 추가할 뿐입니다. -- self가 값을 어떻게 얻는지 궁금하다면 아래의 7과 8을 읽어보세요. -- 3. newObj는 Dog 클래스의 인스턴스가 됩니다. -- 4. self = 인스턴스화되는 클래스. -- 주로 self = Dog이지만 상속을 이용하면 이것을 바꿀 수 있습니다. -- newObj의 메타테이블과 self의 __index를 모두 self에 설정하면 -- newObj가 self의 함수를 갖게 됩니다. -- 5. 참고: setmetatable은 첫 번째 인자를 반환합니다. -- 6. :는 2에서 설명한 것과 같이 동작하지만 이번에는 self가 -- 클래스가 아닌 인스턴스라고 예상할 수 있습니다. -- 7. Dog.new(Dog)과 같으므로 new()에서는 self = Dog입니다. -- 8. mrDog.makeSound(mrDog)과 같으므로 self = mrDog입니다. ---------------------------------------------------- -- 상속 예제: LoudDog = Dog:new() -- 1. function LoudDog:makeSound() s = self.sound .. ' ' -- 2. print(s .. s .. s) end seymour = LoudDog:new() -- 3. seymour:makeSound() -- 'woof woof woof' -- 4. -- 1. LoudDog은 Dog의 메서드와 변수를 갖게 됩니다. -- 2. self는 new()에서 'sound' 키를 가집니다. 3을 참고하세요. -- 3. LoudDog.new(LoudDog)과 같고, LoudDog은 'new' 키가 없지만 -- 메타테이블에서 __index = Dog이기 때문에 Dog.new(LoudDog)으로 -- 변환됩니다. -- 결과: seymour의 메타테이블은 LoudDog이고 LoudDog.__index는 -- LoudDog입니다. 따라서 seymour.key는 seymour.key, -- LoudDog.key, Dog.key와 같을 것이며, 지정한 키에 어떤 테이블이 -- 오든 상관없을 것입니다. -- 4. 'makeSound' 키는 LoudDog에서 발견할 수 있습니다. -- 이것은 LoudDog.makeSound(seymour)와 같습니다. -- 필요할 경우, 하위 클래스의 new()는 기반 클래스의 new()와 유사합니다. function LoudDog:new() newObj = {} -- newObj를 구성 self.__index = self return setmetatable(newObj, self) end ---------------------------------------------------- -- 4. 모듈 ---------------------------------------------------- --[[ 여기서 주석을 제거하면 이 스크립트의 나머지 부분은 -- 실행 가능한 상태가 됩니다. ``` ```lua -- mod.lua 파일의 내용이 다음과 같다고 가정해 봅시다. local M = {} local function sayMyName() print('이소룡') end function M.sayHello() print('안녕하세요') sayMyName() end return M -- 또 다른 파일에서는 mod.lua의 기능을 이용할 수 있습니다. local mod = require('mod') -- mod.lua 파일을 실행 -- require는 모듈을 포함시키는 표준화된 방법입니다. -- require는 다음과 같이 동작합니다: (캐싱돼 있지 않을 경우. 하단 참조) -- mod.lua가 함수의 본문처럼 되므로 mod.lua 안의 지역 멤버는 -- 밖에서 볼 수 없습니다. -- 다음 코드가 동작하는 것은 mod가 mod.lua의 M과 같기 때문입니다. mod.sayHello() -- 이소룡 씨에게 인사를 건넵니다. -- 다음 코드를 실행하면 오류가 발생합니다. -- sayMyName는 mod.lua 안에서만 존재하기 때문입니다: mod.sayMyName() -- 오류 -- require의 반환값은 캐싱되므로 require를 여러 번 실행해도 -- 파일은 최대 한 번만 실행됩니다. -- mod2.lua에 "print('Hi')"가 들어 있다고 가정해 봅시다. local a = require('mod2') -- Hi!를 출력 local b = require('mod2') -- print를 실행하지 않음. a=b -- dofile은 require와 비슷하지만 캐싱을 하지 않습니다: dofile('mod2') --> Hi! dofile('mod2') --> Hi! (require와 달리 다시 한번 실행됨) -- loadfile은 루아 파일을 읽어들이지만 실행하지는 않습니다 f = loadfile('mod2') -- f()를 호출해야 mod2.lua가 실행됩니다. -- loadstring은 문자열에 대한 loadfile입니다. g = loadstring('print(343)') -- 함수를 반환합니다. g() -- 343이 출력됩니다. 그전까지는 아무것도 출력되지 않습니다. --]] ``` ## 참고자료 루아를 배우는 일이 흥미진진했던 이유는 [LÖVE 게임 엔진](http://love2d.org/)을 이용해 게임을 만들 수 있었기 때문입니다. 이것이 제가 루아를 배운 이유입니다. 저는 [BlackBulletIV의 "프로그래머를 위한 루아"](http://nova-fusion.com/2012/08/27/lua-for-programmers-part-1/)로 시작했습니다. 그다음으로 공식 ["프로그래밍 루아"](http://www.lua.org/pil/contents.html) 책을 읽었습니다. 그렇게 루아를 배웠습니다. lua-users.org에 있는 [짧은 루아 레퍼런스](http://lua-users.org/files/wiki_insecure/users/thomasl/luarefv51.pdf)를 읽어두면 도움될지도 모르겠습니다. 여기서는 표준 라이브러리에 관해서는 다루지 않았습니다. * [`string` 라이브러리](http://lua-users.org/wiki/StringLibraryTutorial) * [`table` 라이브러리](http://lua-users.org/wiki/TableLibraryTutorial) * [`math` 라이브러리](http://lua-users.org/wiki/MathLibraryTutorial) * [`io` 라이브러리](http://lua-users.org/wiki/IoLibraryTutorial) * [`os` 라이브러리](http://lua-users.org/wiki/OsLibraryTutorial) 그나저나 이 파일 전체는 유효한 루아 프로그램입니다. 이 파일을 learn.lua로 저장한 후 "`lua learn.lua`"를 실행해 보세요! 이 글은 tylerneylon.com에 처음으로 써본 글이며, [GitHub의 Gist](https://gist.github.com/tylerneylon/5853042)에서도 확인할 수 있습니다. 루아로 즐거운 시간을 보내세요! ================================================ FILE: ko/markdown.md ================================================ --- contributors: - ["Dan Turkel", "http://danturkel.com/"] - ["Jacob Ward", "http://github.com/JacobCWard/"] --- 마크다운은 2004년에 존 그루버가 창시했습니다. HTML으로 (그리고 이제는 다른 다양한 형식으로도) 쉽게 변환되는 읽고 쓰기 쉬운 문법입니다. 마크다운은 또한 파서마다 구현이 다양합니다. 본 문서는 어떤 기능이 보편적인지, 혹은 어떤 기능이 특정 파서에 종속되어 있는지 명확히 하고자 합니다. ## HTML 요소 HTML은 마크다운의 수퍼셋입니다. 모든 HTML 파일은 유효한 마크다운이라는 것입니다. ```md ``` ## 제목 텍스트 앞에 붙이는 우물 정 기호(#)의 갯수에 따라 `

`부터 `

`까지의 HTML 요소를 손쉽게 작성할 수 있습니다. ```md #

입니다. ##

입니다. ###

입니다. ####

입니다. #####

입니다. ######
입니다. ``` 또한 h1과 h2를 나타내는 다른 방법이 있습니다. ```md h1입니다. ============= h2입니다. ------------- ``` ## 간단한 텍스트 꾸미기 마크다운으로 쉽게 텍스트를 기울이거나 굵게 할 수 있습니다. ```md *기울인 텍스트입니다.* _이 텍스트도 같습니다._ **굵은 텍스트입니다.** __이 텍스트도 같습니다.__ ***기울인 굵은 텍스트입니다.*** **_이 텍스트도 같습니다._** *__이것도 같습니다.__* ``` 깃헙 전용 마크다운에는 취소선도 있습니다. ```md ~~이 텍스트에는 취소선이 그려집니다.~~ ``` ## 문단 문단은 하나 이상의 빈 줄로 구분되는, 한 줄 이상의 인접한 텍스트입니다. ```md 문단입니다. 문단에 글을 쓰다니 재밌지 않나요? 이제 두 번째 문단입니다. 아직도 두 번째 문단입니다. 나는 세 번째 문단! ``` HTML `
` 태그를 삽입하고 싶으시다면, 두 개 이상의 띄어쓰기로 문단을 끝내고 새 문단을 시작할 수 있습니다. ```md 띄어쓰기 두 개로 끝나는 문단 (마우스로 긁어 보세요). 이 위에는 `
` 태그가 있습니다. ``` 인용문은 > 문자로 쉽게 쓸 수 있습니다. ```md > 인용문입니다. 수동으로 개행하고서 > 줄마다 `>`를 칠 수도 있고 줄을 길게 쓴 다음에 저절로 개행되게 내버려 둘 수도 있습니다. > `>`로 시작하기만 한다면 차이가 없습니다. > 한 단계 이상의 들여쓰기를 >> 사용할 수도 있습니다. > 깔끔하죠? ``` ## 목록 순서가 없는 목록은 별표, 더하기, 하이픈을 이용해 만들 수 있습니다. ```md * 이거 * 저거 * 그거 ``` 또는 ```md + 이거 + 저거 + 그거 ``` 또는 ```md - 이거 - 저거 - 그거 ``` 순서가 있는 목록은 숫자와 마침표입니다. ```md 1. 하나 2. 둘 3. 셋 ``` 숫자를 정확히 붙이지 않더라도 제대로 된 순서로 보여주겠지만, 좋은 생각은 아닙니다. ```md 1. 하나 1. 둘 1. 셋 ``` (위의 예시와 똑같이 나타납니다.) 목록 안에 목록이 올 수도 있습니다. ```md 1. 하나 2. 둘 3. 셋 * 이거 * 저거 4. 넷 ``` 심지어 할 일 목록도 있습니다. HTML 체크박스가 만들어집니다. ```md x가 없는 박스들은 체크되지 않은 HTML 체크박스입니다. - [ ] 첫 번째 할 일 - [ ] 두 번째 할 일 이 체크박스는 체크된 HTML 체크박스입니다. - [x] 완료된 일 ``` ## 코드 띄어쓰기 네 개 혹은 탭 한 개로 줄을 들여씀으로서 (` 요소를 사용하여`) 코드를 나타낼 수 있습니다. ```md puts "Hello, world!" ``` 탭을 더 치거나 띄어쓰기를 네 번 더 함으로써 코드를 들여쓸 수 있습니다. ```md my_array.each do |item| puts item end ``` 인라인 코드는 백틱 문자를 이용하여 나타냅니다. ` ```md 철수는 `go_to()` 함수가 뭘 했는지도 몰랐어! ``` 깃헙 전용 마크다운에서는 코드를 나타내기 위해 특별한 문법을 쓸 수 있습니다. ````md ```ruby def foobar puts "Hello world!" end ``` ```` 위의 경우에 들여쓰기가 필요없을 뿐 아니라 ``` 뒤에 특정해 준 언어의 문법에 따라 색을 입혀줄 것입니다. ## 수평선 수평선(`
`)은 셋 이상의 별표나 하이픈을 이용해 쉽게 나타낼 수 있습니다. 띄어쓰기가 포함될 수 있습니다. ```md *** --- - - - **************** ``` ## 링크 마크다운의 장점 중 하나는 링크를 만들기 쉽다는 것입니다. 대괄호 안에 나타낼 텍스트를 쓰고 괄호 안에 URL을 쓰면 됩니다. ```md [클릭](http://test.com/) ``` 괄호 안에 따옴표를 이용해 링크에 제목을 달 수도 있습니다. ```md [클릭](http://test.com/ "test.com으로 가기") ``` 상대 경로도 유효합니다. ```md [music으로 가기](/music/). ``` 참조하는 식으로 링크를 걸 수도 있습니다. ```md [이 ][링크]에서 더 알아보세요! [원하신다면 ][foobar]도 참고하세요. [링크]: http://test.com/ "좋아!" [foobar]: http://foobar.biz/ "됐다!" ``` 제목은 작은 따옴표나 괄호에 들어갈 수도 있고, 완전히 생략할 수도 있습니다. 참조는 문서의 어느 곳에든 올 수 있고 참조 ID는 유일하다면 무엇이든 될 수 있습니다. 링크 텍스트를 ID로 사용하는 "묵시적 이름"도 있습니다. ```md [이것][]은 링크입니다. [이것]: http://thisisalink.com/ ``` 하지만 보통 그렇게 추천하지는 않습니다. ## 이미지 이미지는 링크와 같지만 앞에 느낌표가 붙습니다. ```md ![이미지의 alt 속성](http://imgur.com/myimage.jpg "제목") ``` 참조 방식도 가능합니다. ```md ![alt 속성][이미지] [이미지]: relative/urls/cool/image.jpg "제목이 필요하다면 여기에" ``` ## 기타 ### 자동 링크 ```md 와 [http://testwebsite.com/](http://testwebsite.com/)는 동일합니다. ``` ### 이메일 자동 링크 ```md ``` ### 탈출 문자 ```md *별표 사이에 이 텍스트*를 치고 싶지만 기울이고 싶지는 않다면 이렇게 하시면 됩니다. \*별표 사이에 이 텍스트\*. ``` ### 키보드 키 깃헙 전용 마크다운에서는 `` 태그를 이용해 키보드 키를 나타낼 수 있습니다. ```md 컴퓨터가 멈췄다면 눌러보세요. Ctrl+Alt+Del ``` ### 표 표는 깃헙 전용 마크다운에서만 쓸 수 있고 다소 복잡하지만, 정말 쓰고 싶으시다면 ```md | 1열 | 2열 | 3열 | | :--------| :-------: | --------: | | 왼쪽 정렬 | 가운데 정렬 | 오른쪽 정렬 | | 머시기 | 머시기 | 머시기 | ``` 혹은 ```md 1열 | 2열 | 3열 :-- | :-: | --: 으악 너무 못생겼어 | 그만 | 둬 ``` --- 추가 정보를 위해, 존 그루버의 공식 문법 [(영어) 문서](http://daringfireball.net/projects/markdown/syntax)와 애덤 프릿차드의 훌륭한 [(영어) 치트싯](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)을 확인하세요. ================================================ FILE: ko/php.md ================================================ --- contributors: - ["Malcolm Fell", "http://emarref.net/"] - ["Trismegiste", "https://github.com/Trismegiste"] translators: - ["wikibook", "http://wikibook.co.kr"] --- 이 문서에서는 PHP 5+를 설명합니다. ```php Hello World Again! 12 $int2 = -12; // => -12 $int3 = 012; // => 10 (a leading 0 denotes an octal number) $int4 = 0x0F; // => 15 (a leading 0x denotes a hex literal) // Float (doubles로도 알려짐) $float = 1.234; $float = 1.2e3; $float = 7E-10; // 산술 연산 $sum = 1 + 1; // 2 $difference = 2 - 1; // 1 $product = 2 * 2; // 4 $quotient = 2 / 1; // 2 // 축약형 산술 연산 $number = 0; $number += 1; // $number를 1만큼 증가 echo $number++; // 1을 출력(평가 후 증가) echo ++$number; // 3 (평가 전 증가) $number /= $float; // 나눗셈 후 몫을 $number에 할당 // 문자열은 작은따옴표로 감싸야 합니다. $sgl_quotes = '$String'; // => '$String' // 다른 변수를 포함할 때를 제외하면 큰따옴표 사용을 자제합니다. $dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.' // 특수 문자는 큰따옴표에서만 이스케이프됩니다. $escaped = "This contains a \t tab character."; $unescaped = 'This just contains a slash and a t: \t'; // 필요할 경우 변수를 중괄호로 감쌉니다. $money = "I have $${number} in the bank."; // PHP 5.3부터는 여러 줄 문자열을 생성하는 데 나우닥(nowdoc)을 사용할 수 있습니다. $nowdoc = <<<'END' Multi line string END; // 히어닥(heredoc)에서는 문자열 치환을 지원합니다. $heredoc = << 1, 'Two' => 2, 'Three' => 3); // PHP 5.4에서는 새로운 문법이 도입됐습니다. $associative = ['One' => 1, 'Two' => 2, 'Three' => 3]; echo $associative['One']; // 1을 출력 // 리스트 리터럴은 암시적으로 정수형 키를 할당합니다. $array = ['One', 'Two', 'Three']; echo $array[0]; // => "One" /******************************** * 출력 */ echo('Hello World!'); // 표준출력(stdout)에 Hello World!를 출력합니다. // 브라우저에서 실행할 경우 표준출력은 웹 페이지입니다. print('Hello World!'); // echo과 동일 // echo는 실제로 언어 구성물에 해당하므로, 괄호를 생략할 수 있습니다. echo 'Hello World!'; print 'Hello World!'; // 똑같이 출력됩니다. $paragraph = 'paragraph'; echo 100; // 스칼라 변수는 곧바로 출력합니다. echo $paragraph; // 또는 변수의 값을 출력합니다. // 축약형 여는 태그를 설정하거나 PHP 버전이 5.4.0 이상이면 // 축약된 echo 문법을 사용할 수 있습니다. ?>

2 echo $z; // => 2 $y = 0; echo $x; // => 2 echo $z; // => 0 /******************************** * 로직 */ $a = 0; $b = '0'; $c = '1'; $d = '1'; // assert는 인자가 참이 아닌 경우 경고를 출력합니다. // 다음과 같은 비교는 항상 참이며, 타입이 같지 않더라도 마찬가지입니다. assert($a == $b); // 동일성 검사 assert($c != $a); // 불일치성 검사 assert($c <> $a); // 또 다른 불일치성 검사 assert($a < $c); assert($c > $b); assert($a <= $b); assert($c >= $d); // 다음과 같은 코드는 값과 타입이 모두 일치하는 경우에만 참입니다. assert($c === $d); assert($a !== $d); assert(1 == '1'); assert(1 !== '1'); // 변수는 어떻게 사용하느냐 따라 다른 타입으로 변환될 수 있습니다. $integer = 1; echo $integer + $integer; // => 2 $string = '1'; echo $string + $string; // => 2 (문자열이 강제로 정수로 변환됩니다) $string = 'one'; echo $string + $string; // => 0 // + 연산자는 'one'이라는 문자열을 숫자로 형변환할 수 없기 때문에 0이 출력됩니다. // 한 변수를 다른 타입으로 처리하는 데 형변환을 사용할 수 있습니다. $boolean = (boolean) 1; // => true $zero = 0; $boolean = (boolean) $zero; // => false // 대다수의 타입을 형변환하는 데 사용하는 전용 함수도 있습니다. $integer = 5; $string = strval($integer); $var = null; // 널 타입 /******************************** * 제어 구조 */ if (true) { print 'I get printed'; } if (false) { print 'I don\'t'; } else { print 'I get printed'; } if (false) { print 'Does not get printed'; } elseif(true) { print 'Does'; } // 사항 연산자 print (false ? 'Does not get printed' : 'Does'); $x = 0; if ($x === '0') { print 'Does not print'; } elseif($x == '1') { print 'Does not print'; } else { print 'Does print'; } // 다음과 같은 문법은 템플릿에 유용합니다. ?> This is displayed if the test is truthy. This is displayed otherwise. 2, 'car' => 4]; // foreach 문은 배영를 순회할 수 있습니다. foreach ($wheels as $wheel_count) { echo $wheel_count; } // "24"를 출력 echo "\n"; // 키와 값을 동시에 순회할 수 있습니다. foreach ($wheels as $vehicle => $wheel_count) { echo "A $vehicle has $wheel_count wheels"; } echo "\n"; $i = 0; while ($i < 5) { if ($i === 3) { break; // while 문을 빠져나옴 } echo $i++; } // "012"를 출력 for ($i = 0; $i < 5; $i++) { if ($i === 3) { continue; // 이번 순회를 생략 } echo $i; } // "0124"를 출력 /******************************** * 함수 */ // "function"으로 함수를 정의합니다. function my_function () { return 'Hello'; } echo my_function(); // => "Hello" // 유효한 함수명은 문자나 밑줄로 시작하고, 이어서 // 임의 개수의 문자나 숫자, 밑줄이 옵니다. function add ($x, $y = 1) { // $y는 선택사항이고 기본값은 1입니다. $result = $x + $y; return $result; } echo add(4); // => 5 echo add(4, 2); // => 6 // 함수 밖에서는 $result에 접근할 수 없습니다. // print $result; // 이 코드를 실행하면 경고가 출력됩니다. // PHP 5.3부터는 익명 함수를 선언할 수 있습니다. $inc = function ($x) { return $x + 1; }; echo $inc(2); // => 3 function foo ($x, $y, $z) { echo "$x - $y - $z"; } // 함수에서는 함수를 반환할 수 있습니다. function bar ($x, $y) { // 'use'를 이용해 바깥 함수의 변수를 전달합니다. return function ($z) use ($x, $y) { foo($x, $y, $z); }; } $bar = bar('A', 'B'); $bar('C'); // "A - B - C"를 출력 // 문자열을 이용해 이름이 지정된 함수를 호출할 수 있습니다. $function_name = 'add'; echo $function_name(1, 2); // => 3 // 프로그램 방식으로 어느 함수를 실행할지 결정할 때 유용합니다. // 아니면 call_user_func(callable $callback [, $parameter [, ... ]]);를 사용해도 됩니다. /******************************** * 인클루드 */ instanceProp = $instanceProp; } // 메서드는 클래스 안의 함수로서 선언됩니다. public function myMethod() { print 'MyClass'; } final function youCannotOverrideMe() { } public static function myStaticMethod() { print 'I am static'; } } echo MyClass::MY_CONST; // 'value' 출력 echo MyClass::$staticVar; // 'static' 출력 MyClass::myStaticMethod(); // 'I am static' 출력 // new를 사용해 클래스를 인스턴스화합니다. $my_class = new MyClass('An instance property'); // 인자를 전달하지 않을 경우 괄호를 생략할 수 있습니다. // ->를 이용해 클래스 멤버에 접근합니다 echo $my_class->property; // => "public" echo $my_class->instanceProp; // => "An instance property" $my_class->myMethod(); // => "MyClass" // "extends"를 이용해 클래스를 확장합니다. class MyOtherClass extends MyClass { function printProtectedProperty() { echo $this->prot; } // 메서드 재정의 function myMethod() { parent::myMethod(); print ' > MyOtherClass'; } } $my_other_class = new MyOtherClass('Instance prop'); $my_other_class->printProtectedProperty(); // => "protected" 출력 $my_other_class->myMethod(); // "MyClass > MyOtherClass" 출력 final class YouCannotExtendMe { } // "마법 메서드(magic method)"로 설정자 메서드와 접근자 메서드를 만들 수 있습니다. class MyMapClass { private $property; public function __get($key) { return $this->$key; } public function __set($key, $value) { $this->$key = $value; } } $x = new MyMapClass(); echo $x->property; // __get() 메서드를 사용 $x->property = 'Something'; // __set() 메서드를 사용 // 클래스는 추상화하거나(abstract 키워드를 사용해) // 인터페이스를 구현할 수 있습니다(implments 키워드를 사용해). // 인터페이스는 interface 키워드로 선언합니다. interface InterfaceOne { public function doSomething(); } interface InterfaceTwo { public function doSomethingElse(); } // 인터페이스는 확장할 수 있습니다. interface InterfaceThree extends InterfaceTwo { public function doAnotherContract(); } abstract class MyAbstractClass implements InterfaceOne { public $x = 'doSomething'; } class MyConcreteClass extends MyAbstractClass implements InterfaceTwo { public function doSomething() { echo $x; } public function doSomethingElse() { echo 'doSomethingElse'; } } // 클래스에서는 하나 이상의 인터페이스를 구현할 수 있습니다. class SomeOtherClass implements InterfaceOne, InterfaceTwo { public function doSomething() { echo 'doSomething'; } public function doSomethingElse() { echo 'doSomethingElse'; } } /******************************** * 특성 */ // 특성(trait)은 PHP 5.4.0부터 사용 가능하며, "trait"으로 선언합니다. trait MyTrait { public function myTraitMethod() { print 'I have MyTrait'; } } class MyTraitfulClass { use MyTrait; } $cls = new MyTraitfulClass(); $cls->myTraitMethod(); // "I have MyTrait"을 출력 /******************************** * 네임스페이스 */ // 이 부분은 별도의 영역인데, 파일에서 처음으로 나타나는 문장은 // 네임스페이스 선언이어야 하기 때문입니다. 여기서는 그런 경우가 아니라고 가정합니다. 3 # 수학 연산은 예상하신 대로입니다. 1 + 1 #=> 2 8 - 1 #=> 7 10 * 2 #=> 20 35 / 5 #=> 7 # 나눗셈은 약간 까다롭습니다. 정수로 나눈 다음 결과값을 자동으로 내림합니다. 5 / 2 #=> 2 # 나눗셈 문제를 해결하려면 float에 대해 알아야 합니다. 2.0 # 이것이 float입니다. 11.0 / 4.0 #=> 2.75 훨씬 낫네요 # 괄호를 이용해 연산자 우선순위를 지정합니다. (1 + 3) * 2 #=> 8 # 불린(Boolean) 값은 기본형입니다. True False # not을 이용해 부정합니다. not True #=> False not False #=> True # 동일성 연산자는 ==입니다. 1 == 1 #=> True 2 == 1 #=> False # 불일치 연산자는 !=입니다. 1 != 1 #=> False 2 != 1 #=> True # 그밖의 비교 연산자는 다음과 같습니다. 1 < 10 #=> True 1 > 10 #=> False 2 <= 2 #=> True 2 >= 2 #=> True # 비교 연산을 연결할 수도 있습니다! 1 < 2 < 3 #=> True 2 < 3 < 2 #=> False # 문자열은 "나 '로 생성합니다. "This is a string." 'This is also a string.' # 문자열도 연결할 수 있습니다! "Hello " + "world!" #=> "Hello world!" # 문자열은 문자로 구성된 리스트로 간주할 수 있습니다. "This is a string"[0] #=> 'T' # %는 다음과 같이 문자열을 형식화하는 데 사용할 수 있습니다: "%s can be %s" % ("strings", "interpolated") # 문자열을 형식화하는 새로운 방법은 format 메서드를 이용하는 것입니다. # 이 메서드를 이용하는 방법이 더 선호됩니다. "{0} can be {1}".format("strings", "formatted") # 자릿수를 세기 싫다면 키워드를 이용해도 됩니다. "{name} wants to eat {food}".format(name="Bob", food="lasagna") # None은 객체입니다. None #=> None # 객체와 None을 비교할 때는 동일성 연산자인 `==`를 사용해서는 안 됩니다. # 대신 `is`를 사용하세요. "etc" is None #=> False None is None #=> True # 'is' 연산자는 객체의 식별자를 검사합니다. # 기본형 값을 다룰 때는 이 연산자가 그다지 유용하지 않지만 # 객체를 다룰 때는 매우 유용합니다. # None, 0, 빈 문자열/리스트는 모두 False로 평가됩니다. # 그밖의 다른 값은 모두 True입니다 0 == False #=> True "" == False #=> True #################################################### ## 2. 변수와 컬렉션 #################################################### # 뭔가를 출력하는 것은 상당히 쉽습니다. print "I'm Python. Nice to meet you!" # 변수에 값을 할당하기 전에 변수를 반드시 선언하지 않아도 됩니다. some_var = 5 # 명명관례는 '밑줄이_포함된_소문자'입니다. some_var #=> 5 # 미할당된 변수에 접근하면 예외가 발생합니다. # 예외 처리에 관해서는 '제어 흐름'을 참고하세요. some_other_var # 이름 오류가 발생 # 표현식으로도 사용할 수 있습니다. "yahoo!" if 3 > 2 else 2 #=> "yahoo!" # 리스트는 순차 항목을 저장합니다. li = [] # 미리 채워진 리스트로 시작할 수도 있습니다. other_li = [4, 5, 6] # append를 이용해 리스트 끝에 항목을 추가합니다. li.append(1) #li는 이제 [1]입니다. li.append(2) #li는 이제 [1, 2]입니다. li.append(4) #li는 이제 [1, 2, 4]입니다. li.append(3) #li는 이제 [1, 2, 4, 3]입니다. # pop을 이용해 끝에서부터 항목을 제거합니다. li.pop() #=> 3이 반환되고 li는 이제 [1, 2, 4]입니다. # 다시 넣어봅시다 li.append(3) # li는 이제 다시 [1, 2, 4, 3]가 됩니다. # 배열에서 했던 것처럼 리스트에도 접근할 수 있습니다. li[0] #=> 1 # 마지막 요소를 봅시다. li[-1] #=> 3 # 범위를 벗어나서 접근하면 IndexError가 발생합니다. li[4] # IndexError가 발생 # 슬라이스 문법을 통해 범위를 지정해서 값을 조회할 수 있습니다. # (이 문법을 통해 간편하게 범위를 지정할 수 있습니다.) li[1:3] #=> [2, 4] # 앞부분을 생략합니다. li[2:] #=> [4, 3] # 끝부분을 생략합니다. li[:3] #=> [1, 2, 4] # del로 임의의 요소를 제거할 수 있습니다. del li[2] # li is now [1, 2, 3] # 리스트를 추가할 수도 있습니다. li + other_li #=> [1, 2, 3, 4, 5, 6] - 참고: li와 other_li는 그대로 유지됩니다. # extend로 리스트를 연결합니다. li.extend(other_li) # 이제 li는 [1, 2, 3, 4, 5, 6]입니다. # in으로 리스트 안에서 특정 요소가 존재하는지 확인합니다. 1 in li #=> True # len으로 길이를 검사합니다. len(li) #=> 6 # 튜플은 리스트와 비슷하지만 불변성을 띱니다. tup = (1, 2, 3) tup[0] #=> 1 tup[0] = 3 # TypeError가 발생 # 튜플에 대해서도 리스트에서 할 수 있는 일들을 모두 할 수 있습니다. len(tup) #=> 3 tup + (4, 5, 6) #=> (1, 2, 3, 4, 5, 6) tup[:2] #=> (1, 2) 2 in tup #=> True # 튜플(또는 리스트)을 변수로 풀 수 있습니다. a, b, c = (1, 2, 3) # 이제 a는 1, b는 2, c는 3입니다 # 괄호를 빼면 기본적으로 튜플이 만들어집니다. d, e, f = 4, 5, 6 # 이제 두 값을 바꾸는 게 얼마나 쉬운지 확인해 보세요. e, d = d, e # 이제 d는 5이고 e는 4입니다. # 딕셔너리는 매핑을 저장합니다. empty_dict = {} # 다음은 값을 미리 채운 딕셔너리입니다. filled_dict = {"one": 1, "two": 2, "three": 3} # []를 이용해 값을 조회합니다. filled_dict["one"] #=> 1 # 모든 키를 리스트로 구합니다. filled_dict.keys() #=> ["three", "two", "one"] # 참고 - 딕셔너리 키의 순서는 보장되지 않습니다. # 따라서 결과가 이와 정확히 일치하지 않을 수도 있습니다. # 모든 값을 리스트로 구합니다. filled_dict.values() #=> [3, 2, 1] # 참고 - 키 순서와 관련해서 위에서 설명한 내용과 같습니다. # in으로 딕셔너리 안에 특정 키가 존재하는지 확인합니다. "one" in filled_dict #=> True 1 in filled_dict #=> False # 존재하지 않는 키를 조회하면 KeyError가 발생합니다. filled_dict["four"] # KeyError # get 메서드를 이용하면 KeyError가 발생하지 않습니다. filled_dict.get("one") #=> 1 filled_dict.get("four") #=> None # get 메서드는 값이 누락된 경우 기본 인자를 지원합니다. filled_dict.get("one", 4) #=> 1 filled_dict.get("four", 4) #=> 4 # setdefault 메서드는 딕셔너리에 새 키-값 쌍을 추가하는 안전한 방법입니다. filled_dict.setdefault("five", 5) #filled_dict["five"]는 5로 설정됩니다. filled_dict.setdefault("five", 6) #filled_dict["five"]는 여전히 5입니다. # 세트는 집합을 저장합니다. empty_set = set() # 다수의 값으로 세트를 초기화합니다. some_set = set([1,2,2,3,4]) # 이제 some_set는 set([1, 2, 3, 4])입니다. # 파이썬 2.7부터는 {}를 세트를 선언하는 데 사용할 수 있습니다. filled_set = {1, 2, 2, 3, 4} # => {1 2 3 4} # 세트에 항목을 추가합니다. filled_set.add(5) # 이제 filled_set는 {1, 2, 3, 4, 5}입니다. # &을 이용해 교집합을 만듭니다. other_set = {3, 4, 5, 6} filled_set & other_set #=> {3, 4, 5} # |를 이용해 합집합을 만듭니다. filled_set | other_set #=> {1, 2, 3, 4, 5, 6} # -를 이용해 차집합을 만듭니다. {1,2,3,4} - {2,3,5} #=> {1, 4} # in으로 세트 안에 특정 요소가 존재하는지 검사합니다. 2 in filled_set #=> True 10 in filled_set #=> False #################################################### ## 3. 제어 흐름 #################################################### # 변수를 만들어 봅시다. some_var = 5 # 다음은 if 문입니다. 파이썬에서는 들여쓰기가 대단히 중요합니다! # 다음 코드를 실행하면 "some_var is smaller than 10"가 출력됩니다. if some_var > 10: print "some_var is totally bigger than 10." elif some_var < 10: # elif 절은 선택사항입니다. print "some_var is smaller than 10." else: # 이 부분 역시 선택사항입니다. print "some_var is indeed 10." """ for 루프는 리스트를 순회합니다. 아래 코드는 다음과 같은 내용을 출력합니다: dog is a mammal cat is a mammal mouse is a mammal """ for animal in ["dog", "cat", "mouse"]: # %로 형식화된 문자열에 값을 채워넣을 수 있습니다. print "%s is a mammal" % animal """ `range(number)`는 숫자 리스트를 반환합니다. 이때 숫자 리스트의 범위는 0에서 지정한 숫자까지입니다. 아래 코드는 다음과 같은 내용을 출력합니다: 0 1 2 3 """ for i in range(4): print i """ while 루프는 조건이 더는 충족되지 않을 때까지 진행됩니다. prints: 0 1 2 3 """ x = 0 while x < 4: print x x += 1 # x = x + 1의 축약형 # try/except 블록을 이용한 예외 처리 # 파이썬 2.6 및 상위 버전에서 동작하는 코드 try: # raise를 이용해 오류를 발생시킵니다 raise IndexError("This is an index error") except IndexError as e: pass # pass는 단순 no-op 연산입니다. 보통 이곳에 복구 코드를 작성합니다. #################################################### ## 4. 함수 #################################################### # 새 함수를 만들 때 def를 사용합니다. def add(x, y): print "x is %s and y is %s" % (x, y) return x + y # return 문을 이용해 값을 반환합니다. # 매개변수를 전달하면서 함수를 호출 add(5, 6) #=> "x is 5 and y is 6"가 출력되고 11이 반환됨 # 함수를 호출하는 또 다른 방법은 키워드 인자를 지정하는 방법입니다. add(y=6, x=5) # 키워드 인자는 순서에 구애받지 않습니다. # 위치 기반 인자를 임의 개수만큼 받는 함수를 정의할 수 있습니다. def varargs(*args): return args varargs(1, 2, 3) #=> (1,2,3) # 키워드 인자를 임의 개수만큼 받는 함수 또한 정의할 수 있습니다. def keyword_args(**kwargs): return kwargs # 이 함수를 호출해서 어떤 일이 일어나는지 확인해 봅시다. keyword_args(big="foot", loch="ness") #=> {"big": "foot", "loch": "ness"} # 원한다면 한 번에 두 가지 종류의 인자를 모두 받는 함수를 정의할 수도 있습니다. def all_the_args(*args, **kwargs): print args print kwargs """ all_the_args(1, 2, a=3, b=4)를 실행하면 다음과 같은 내용이 출력됩니다: (1, 2) {"a": 3, "b": 4} """ # 함수를 호출할 때 varargs/kwargs와 반대되는 일을 할 수 있습니다! # *를 이용해 튜플을 확장하고 **를 이용해 kwargs를 확장합니다. args = (1, 2, 3, 4) kwargs = {"a": 3, "b": 4} all_the_args(*args) # foo(1, 2, 3, 4)와 같음 all_the_args(**kwargs) # foo(a=3, b=4)와 같음 all_the_args(*args, **kwargs) # foo(1, 2, 3, 4, a=3, b=4)와 같음 # 파이썬에는 일급 함수가 있습니다 def create_adder(x): def adder(y): return x + y return adder add_10 = create_adder(10) add_10(3) #=> 13 # 게다가 익명 함수도 있습니다. (lambda x: x > 2)(3) #=> True # 내장된 고차 함수(high order function)도 있습니다. map(add_10, [1,2,3]) #=> [11, 12, 13] filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7] # 맵과 필터에 리스트 조건 제시법(list comprehensions)을 사용할 수 있습니다. [add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13] [x for x in [3, 4, 5, 6, 7] if x > 5] #=> [6, 7] #################################################### ## 5. 클래스 #################################################### # 클래스를 하나 만들기 위해 특정 객체의 하위 클래스를 만들 수 있습니다. class Human(object): # 클래스 속성은 이 클래스의 모든 인스턴스에서 공유합니다. species = "H. sapiens" # 기본 초기화자 def __init__(self, name): # 인자를 인스턴스의 name 속성에 할당합니다. self.name = name # 모든 인스턴스 메서드에서는 self를 첫 번째 인자로 받습니다. def say(self, msg): return "%s: %s" % (self.name, msg) # 클래스 메서드는 모든 인스턴스에서 공유합니다. # 클래스 메서드는 호출하는 클래스를 첫 번째 인자로 호출됩니다. @classmethod def get_species(cls): return cls.species # 정적 메서드는 클래스나 인스턴스 참조 없이도 호출할 수 있습니다. @staticmethod def grunt(): return "*grunt*" # 클래스 인스턴스화 i = Human(name="Ian") print i.say("hi") # "Ian: hi"가 출력됨 j = Human("Joel") print j.say("hello") # "Joel: hello"가 출력됨 # 클래스 메서드를 호출 i.get_species() #=> "H. sapiens" # 공유 속성을 변경 Human.species = "H. neanderthalensis" i.get_species() #=> "H. neanderthalensis" j.get_species() #=> "H. neanderthalensis" # 정적 메서드를 호출 Human.grunt() #=> "*grunt*" #################################################### ## 6. 모듈 #################################################### # 다음과 같이 모듈을 임포트할 수 있습니다. import math print math.sqrt(16) #=> 4.0 # 모듈의 특정 함수를 호출할 수 있습니다. from math import ceil, floor print ceil(3.7) #=> 4.0 print floor(3.7) #=> 3.0 # 모듈의 모든 함수를 임포트할 수 있습니다. # Warning: this is not recommended from math import * # 모듈 이름을 축약해서 쓸 수 있습니다. import math as m math.sqrt(16) == m.sqrt(16) #=> True # 파이썬 모듈은 평범한 파이썬 파일에 불과합니다. # 직접 모듈을 작성해서 그것들을 임포트할 수 있습니다. # 모듈의 이름은 파일의 이름과 같습니다. # 다음과 같은 코드로 모듈을 구성하는 함수와 속성을 확인할 수 있습니다. import math dir(math) ``` ## 더 배울 준비가 되셨습니까? ### 무료 온라인 참고자료 * [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) * [Dive Into Python](http://www.diveintopython.net/) * [The Official Docs](http://docs.python.org/2.6/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) * [Python Module of the Week](http://pymotw.com/2/) ### 파이썬 관련 도서 * [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20) * [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20) * [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20) ================================================ FILE: ko/racket.md ================================================ --- contributors: - ["th3rac25", "https://github.com/voila"] - ["Eli Barzilay", "https://github.com/elibarzilay"] - ["Gustavo Schmidt", "https://github.com/gustavoschmidt"] - ["Duong H. Nguyen", "https://github.com/cmpitg"] translators: - ["KIM Taegyoon", "https://github.com/kimtg"] --- Racket 은 Lisp/Scheme 계열의 일반 목적의, 다중 패러다임 프로그래밍 언어이다. ```racket #lang racket ; 우리가 사용하는 언어를 정의한다. ;;; 주석 ;; 한 줄 주석은 세미콜론으로 시작한다. #| 블록 주석 은 여러 줄에 걸칠 수 있으며... #| 중첩될 수 있다! |# |# ;; S-expression 주석은 아래 식을 버리므로, ;; 디버깅할 때 식을 주석화할 때 유용하다. #; (이 식은 버려짐) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 1. 근본 자료형과 연산자 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 숫자 9999999999999999999999 ; 정수 #b111 ; 이진수 => 7 #o111 ; 팔진수 => 73 #x111 ; 16진수 => 273 3.14 ; 실수 6.02e+23 1/2 ; 분수 1+2i ; 복소수 ;; 함수 적용은 이렇게 쓴다: (f x y z ...) ;; 여기에서 f는 함수이고 x, y, z는 피연산자이다. ;; 글자 그대로의 데이터 리스트를 만들고 싶다면 평가를 막기 위해 '를 쓰시오. '(+ 1 2) ; => (+ 1 2) ;; 이제, 산술 연산 몇 개 (+ 1 1) ; => 2 (- 8 1) ; => 7 (* 10 2) ; => 20 (expt 2 3) ; => 8 (quotient 5 2) ; => 2 (remainder 5 2) ; => 1 (/ 35 5) ; => 7 (/ 1 3) ; => 1/3 (exact->inexact 1/3) ; => 0.3333333333333333 (+ 1+2i 2-3i) ; => 3-1i ;;; 불린 #t ; 참 #f ; 거짓 -- #f가 아닌 것은 참 (not #t) ; => #f (and 0 #f (error "doesn't get here")) ; => #f (or #f 0 (error "doesn't get here")) ; => 0 ;;; 문자 #\A ; => #\A #\λ ; => #\λ #\u03BB ; => #\λ ;;; 문자열은 고정 길이의 문자 배열이다. "Hello, world!" "Benjamin \"Bugsy\" Siegel" ; 백슬래시는 탈출 문자이다. "Foo\tbar\41\x21\u0021\a\r\n" ; C 탈출 문자, 유니코드 포함 "λx:(μα.α→α).xx" ; 유니코드 문자 포함 가능 ;; 문자열은 붙여질 수 있다! (string-append "Hello " "world!") ; => "Hello world!" ;; 문자열은 문자의 리스트처럼 취급될 수 있다. (string-ref "Apple" 0) ; => #\A ;; format은 문자열을 형식화하기 위해 사용된다: (format "~a can be ~a" "strings" "formatted") ;; 인쇄는 쉽다. (printf "I'm Racket. Nice to meet you!\n") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 2. 변수 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; define으로 변수를 만든다. ;; 변수명으로 다음 문자를 사용할 수 없다: ()[]{}",'`;#|\ (define some-var 5) some-var ; => 5 ;; 유니코드 문자도 사용 가능하다. (define ⊆ subset?) (⊆ (set 3 2) (set 1 2 3)) ; => #t ;; 앞에서 정의되지 않은 변수에 접근하면 예외가 발생한다. ; x ; => x: undefined ... ;; 지역 변수: `me'는 (let ...) 안에서만 "Bob"이다. (let ([me "Bob"]) "Alice" me) ; => "Bob" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 3. 구조체(Struct)와 모음(Collection) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 구조체 (struct dog (name breed age)) (define my-pet (dog "lassie" "collie" 5)) my-pet ; => # (dog? my-pet) ; => #t (dog-name my-pet) ; => "lassie" ;;; 쌍 (불변) ;; `cons'는 쌍을 만들고, `car'와 `cdr'는 첫번째와 ;; 두번째 원소를 추출한다. (cons 1 2) ; => '(1 . 2) (car (cons 1 2)) ; => 1 (cdr (cons 1 2)) ; => 2 ;;; 리스트 ;; 리스트는 연결-리스트 데이터 구조이며, `cons' 쌍으로 만들어지며 ;; `null' (또는 '()) 로 리스트의 끝을 표시한다. (cons 1 (cons 2 (cons 3 null))) ; => '(1 2 3) ;; `list'는 편리한 가변인자 리스트 생성자이다. (list 1 2 3) ; => '(1 2 3) ;; 글자 그대로의 리스트 값에는 인용부호를 쓴다. '(1 2 3) ; => '(1 2 3) ;; 리스트의 앞에 항목을 추가하기 위하여 `cons'를 사용한다. (cons 4 '(1 2 3)) ; => '(4 1 2 3) ;; 리스트들을 붙이기 위해 `append'를 사용한다. (append '(1 2) '(3 4)) ; => '(1 2 3 4) ;; 리스트는 매우 기본적인 자료형이기 때문에, 리스트에 대해 적용되는 많은 기능들이 있다. ;; 예를 들어: (map add1 '(1 2 3)) ; => '(2 3 4) (map + '(1 2 3) '(10 20 30)) ; => '(11 22 33) (filter even? '(1 2 3 4)) ; => '(2 4) (count even? '(1 2 3 4)) ; => 2 (take '(1 2 3 4) 2) ; => '(1 2) (drop '(1 2 3 4) 2) ; => '(3 4) ;;; 벡터 ;; 벡터는 고정 길이의 배열이다. #(1 2 3) ; => '#(1 2 3) ;; `vector-append'를 사용하여 벡터들을 붙인다. (vector-append #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) ;;; 집합 ;; 리스트로부터 집합 만들기 (list->set '(1 2 3 1 2 3 3 2 1 3 2 1)) ; => (set 1 2 3) ;; 원소를 추가하려면 `set-add'를 사용한다. ;; (함수적: 확장된 집합을 반환하며, 원래의 입력을 변경하지 않는다.) (set-add (set 1 2 3) 4) ; => (set 1 2 3 4) ;; 원소를 삭제하려면 `set-remove' (set-remove (set 1 2 3) 1) ; => (set 2 3) ;; 존재 여부를 조사하려면 `set-member?' (set-member? (set 1 2 3) 1) ; => #t (set-member? (set 1 2 3) 4) ; => #f ;;; 해시 ;; 불변의 해시 테이블을 만든다. (가변 예제는 아래에) (define m (hash 'a 1 'b 2 'c 3)) ;; 값 꺼내기 (hash-ref m 'a) ; => 1 ;; 없는 값을 꺼내는 것은 예외를 발생시킨다. ; (hash-ref m 'd) => no value found ;; 키가 없을 때 반환할 기본값을 지정할 수 있다. (hash-ref m 'd 0) ; => 0 ;; `hash-set'을 사용하여 불변의 해시 테이블을 확장 ;; (원래 것을 변경하지 않고 확장된 해시를 반환한다.) (define m2 (hash-set m 'd 4)) m2 ; => '#hash((b . 2) (a . 1) (d . 4) (c . 3)) ;; 이 해시들은 불변이라는 점을 기억하시오! m ; => '#hash((b . 2) (a . 1) (c . 3)) <-- no `d' ;; `hash-remove'로 키를 삭제 (이것도 함수적) (hash-remove m 'a) ; => '#hash((b . 2) (c . 3)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 3. 함수 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; `lambda'로 함수를 만든다. ;; 함수는 항상 마지막 식을 반환한다. (lambda () "Hello World") ; => # ;; 유니코드 `λ'도 사용 가능 (λ () "Hello World") ; => same function ;; 모든 함수를 호출할 때는 괄호를 쓴다, lambda 식도 포함하여. ((lambda () "Hello World")) ; => "Hello World" ((λ () "Hello World")) ; => "Hello World" ;; 변수에 함수를 할당 (define hello-world (lambda () "Hello World")) (hello-world) ; => "Hello World" ;; 문법적 설탕을 사용하여 함수 정의를 더 짧게할 수 있다: (define (hello-world2) "Hello World") ;; 위에서 ()는 함수의 인자 리스트이다. (define hello (lambda (name) (string-append "Hello " name))) (hello "Steve") ; => "Hello Steve" ;; ... 또는, 설탕 친 정의로: (define (hello2 name) (string-append "Hello " name)) ;; 가변인자 함수에는 `case-lambda'를 사용한다. (define hello3 (case-lambda [() "Hello World"] [(name) (string-append "Hello " name)])) (hello3 "Jake") ; => "Hello Jake" (hello3) ; => "Hello World" ;; ... 또는 선택적 인자에 기본값 지정 (define (hello4 [name "World"]) (string-append "Hello " name)) ;; 함수는 추가 인자를 리스트에 포장할 수 있다. (define (count-args . args) (format "You passed ~a args: ~a" (length args) args)) (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" ;; ... 설탕 안 친 `lambda' 형식으로는: (define count-args2 (lambda args (format "You passed ~a args: ~a" (length args) args))) ;; 일반 인자와 포장된 인자를 섞을 수 있다. (define (hello-count name . args) (format "Hello ~a, you passed ~a extra args" name (length args))) (hello-count "Finn" 1 2 3) ; => "Hello Finn, you passed 3 extra args" ;; ... 설탕 안 친 것: (define hello-count2 (lambda (name . args) (format "Hello ~a, you passed ~a extra args" name (length args)))) ;; 키워드 인자 (define (hello-k #:name [name "World"] #:greeting [g "Hello"] . args) (format "~a ~a, ~a extra args" g name (length args))) (hello-k) ; => "Hello World, 0 extra args" (hello-k 1 2 3) ; => "Hello World, 3 extra args" (hello-k #:greeting "Hi") ; => "Hi World, 0 extra args" (hello-k #:name "Finn" #:greeting "Hey") ; => "Hey Finn, 0 extra args" (hello-k 1 2 3 #:greeting "Hi" #:name "Finn" 4 5 6) ; => "Hi Finn, 6 extra args" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 4. 동등성 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 숫자에는 `='를 사용하시오. (= 3 3.0) ; => #t (= 2 1) ; => #f ;; 개체의 동등성에는 `eq?'를 사용하시오. (eq? 3 3) ; => #t (eq? 3 3.0) ; => #f (eq? (list 3) (list 3)) ; => #f ;; 모음에는 `equal?'을 사용하시오. (equal? (list 'a 'b) (list 'a 'b)) ; => #t (equal? (list 'a 'b) (list 'b 'a)) ; => #f ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 5. 흐름 제어하기 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 조건 (if #t ; 조사 식 "this is true" ; 그러면 식 "this is false") ; 아니면 식 ; => "this is true" ;; 조건에서는 #f가 아니면 참으로 취급된다. (member 'Groucho '(Harpo Groucho Zeppo)) ; => '(Groucho Zeppo) (if (member 'Groucho '(Harpo Groucho Zeppo)) 'yep 'nope) ; => 'yep ;; `cond'는 연속하여 조사하여 값을 선택한다. (cond [(> 2 2) (error "wrong!")] [(< 2 2) (error "wrong again!")] [else 'ok]) ; => 'ok ;;; 양식 맞춤 (define (fizzbuzz? n) (match (list (remainder n 3) (remainder n 5)) [(list 0 0) 'fizzbuzz] [(list 0 _) 'fizz] [(list _ 0) 'buzz] [_ #f])) (fizzbuzz? 15) ; => 'fizzbuzz (fizzbuzz? 37) ; => #f ;;; 반복 ;; 반복은 (꼬리-) 재귀로 한다. (define (loop i) (when (< i 10) (printf "i=~a\n" i) (loop (add1 i)))) (loop 5) ; => i=5, i=6, ... ;; 이름 있는 let으로도... (let loop ((i 0)) (when (< i 10) (printf "i=~a\n" i) (loop (add1 i)))) ; => i=0, i=1, ... ;; Racket은 매우 유연한 `for' 형식을 가지고 있다: (for ([i 10]) (printf "i=~a\n" i)) ; => i=0, i=1, ... (for ([i (in-range 5 10)]) (printf "i=~a\n" i)) ; => i=5, i=6, ... ;;; 다른 Sequence들을 순회하는 반복 ;; `for'는 여러 가지의 sequence를 순회할 수 있다: ;; 리스트, 벡터, 문자열, 집합, 해시 테이블 등... (for ([i (in-list '(l i s t))]) (displayln i)) (for ([i (in-vector #(v e c t o r))]) (displayln i)) (for ([i (in-string "string")]) (displayln i)) (for ([i (in-set (set 'x 'y 'z))]) (displayln i)) (for ([(k v) (in-hash (hash 'a 1 'b 2 'c 3 ))]) (printf "key:~a value:~a\n" k v)) ;;; 더 복잡한 반복 ;; 여러 sequence에 대한 병렬 순회 (가장 짧은 것 기준으로 중단) (for ([i 10] [j '(x y z)]) (printf "~a:~a\n" i j)) ; => 0:x 1:y 2:z ;; 중첩 반복 (for* ([i 2] [j '(x y z)]) (printf "~a:~a\n" i j)) ; => 0:x, 0:y, 0:z, 1:x, 1:y, 1:z ;; 조건 (for ([i 1000] #:when (> i 5) #:unless (odd? i) #:break (> i 10)) (printf "i=~a\n" i)) ; => i=6, i=8, i=10 ;;; 함축 ;; `for' 반복과 비슷하며, 결과만 수집한다. (for/list ([i '(1 2 3)]) (add1 i)) ; => '(2 3 4) (for/list ([i '(1 2 3)] #:when (even? i)) i) ; => '(2) (for/list ([i 10] [j '(x y z)]) (list i j)) ; => '((0 x) (1 y) (2 z)) (for/list ([i 1000] #:when (> i 5) #:unless (odd? i) #:break (> i 10)) i) ; => '(6 8 10) (for/hash ([i '(1 2 3)]) (values i (number->string i))) ; => '#hash((1 . "1") (2 . "2") (3 . "3")) ;; 반복의 값을 수집하는 여러 가지 방법이 있다: (for/sum ([i 10]) (* i i)) ; => 285 (for/product ([i (in-range 1 11)]) (* i i)) ; => 13168189440000 (for/and ([i 10] [j (in-range 10 20)]) (< i j)) ; => #t (for/or ([i 10] [j (in-range 0 20 2)]) (= i j)) ; => #t ;; 임의의 조합을 사용하려면 `for/fold'를 사용: (for/fold ([sum 0]) ([i '(1 2 3 4)]) (+ sum i)) ; => 10 ;; (이것은 명령형 반복문을 대체하기도 한다.) ;;; 예외 ;; 예외를 잡으려면 `with-handlers' 형식을 사용 (with-handlers ([exn:fail? (lambda (exn) 999)]) (+ 1 "2")) ; => 999 (with-handlers ([exn:break? (lambda (exn) "no time")]) (sleep 3) "phew") ; => "phew", but if you break it => "no time" ;; 예외나 다른 값을 던지려면 `raise'를 사용 (with-handlers ([number? ; catch numeric values raised identity]) ; return them as plain values (+ 1 (raise 2))) ; => 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 6. 변경 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 기존 변수에 새 값을 할당하려면 `set!'을 사용한다. (define n 5) (set! n (add1 n)) n ; => 6 ;; 명시적인 가변 값을 사용하려면 box 사용 (다른 언어의 포인터나 참조와 비슷함) (define n* (box 5)) (set-box! n* (add1 (unbox n*))) (unbox n*) ; => 6 ;; 많은 Racket 자료형은 불변이다 (쌍, 리스트 등). 그러나 어떤 것들은 ;; 가변과 불변형이 둘 다 있다. (string, vector, hash table 등) ;; `vector'나 `make-vector'로 가변 벡터를 생성한다. (define vec (vector 2 2 3 4)) (define wall (make-vector 100 'bottle-of-beer)) ;; 칸을 변경하려면 vector-set!을 사용한다. (vector-set! vec 0 1) (vector-set! wall 99 'down) vec ; => #(1 2 3 4) ;; 비어 있는 가변 해시 테이블을 만들고 조작한다. (define m3 (make-hash)) (hash-set! m3 'a 1) (hash-set! m3 'b 2) (hash-set! m3 'c 3) (hash-ref m3 'a) ; => 1 (hash-ref m3 'd 0) ; => 0 (hash-remove! m3 'a) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 7. 모듈 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 모듈은 코드를 여러 파일과 재사용 가능한 라이브러리로 조직하게 한다. ;; 여기서 우리는 서브-모듈을 사용한다. 이 글이 만드는 전체 모듈("lang" 줄 부터 시작)에 포함된 모듈이다. (module cake racket/base ; racket/base 기반의 `cake' 모듈 정의 (provide print-cake) ; 모듈이 노출(export)시키는 함수 (define (print-cake n) (show " ~a " n #\.) (show " .-~a-. " n #\|) (show " | ~a | " n #\space) (show "---~a---" n #\-)) (define (show fmt n ch) ; 내부 함수 (printf fmt (make-string n ch)) (newline))) ;; `require'를 사용하여 모듈에서 모든 `provide'된 이름을 사용한다. (require 'cake) ; '는 지역 지역 서브-모듈을 위한 것이다. (print-cake 3) ; (show "~a" 1 #\A) ; => 에러, `show'가 export되지 않았음 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 8. 클래스와 개체 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 클래스 fish%를 생성한다. (-%는 클래스 정의에 쓰이는 관용구) (define fish% (class object% (init size) ; 초기화 인자 (super-new) ; 상위 클래스 초기화 ;; 필드 (define current-size size) ;; 공용 메서드 (define/public (get-size) current-size) (define/public (grow amt) (set! current-size (+ amt current-size))) (define/public (eat other-fish) (grow (send other-fish get-size))))) ;; fish%의 인스턴스를 생성한다. (define charlie (new fish% [size 10])) ;; 개체의 메서드를 호출하기 위해 `send'를 사용한다. (send charlie get-size) ; => 10 (send charlie grow 6) (send charlie get-size) ; => 16 ;; `fish%'는 보통의 "일급" 값이며, mixin을 줄 수 있다. (define (add-color c%) (class c% (init color) (super-new) (define my-color color) (define/public (get-color) my-color))) (define colored-fish% (add-color fish%)) (define charlie2 (new colored-fish% [size 10] [color 'red])) (send charlie2 get-color) ;; 또는, 이름 없이: (send (new (add-color fish%) [size 10] [color 'red]) get-color) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 9. 매크로 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 매크로는 언어의 문법을 확장할 수 있게 한다. ;; while 반복문을 추가하자. (define-syntax-rule (while condition body ...) (let loop () (when condition body ... (loop)))) (let ([i 0]) (while (< i 10) (displayln i) (set! i (add1 i)))) ;; 매크로는 위생적이다. 즉, 기존 변수를 침범할 수 없다. (define-syntax-rule (swap! x y) ; -!는 변경의 관용구 (let ([tmp x]) (set! x y) (set! y tmp))) (define tmp 2) (define other 3) (swap! tmp other) (printf "tmp = ~a; other = ~a\n" tmp other) ;; `tmp` 변수는 이름 충돌을 피하기 위해 `tmp_1`로 이름이 변경된다. ;; (let ([tmp_1 tmp]) ;; (set! tmp other) ;; (set! other tmp_1)) ;; 하지만 그것들은 단지 코드 변형일 뿐이다. 예를 들어: (define-syntax-rule (bad-while condition body ...) (when condition body ... (bad-while condition body ...))) ;; 이 매크로는 엉터리다: 무한 코드를 생성하며, ;; 이것을 사용하려고 하면 컴파일러가 무한 반복에 빠진다. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 10. 계약(Contract) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 계약은 모듈에서 노출된 값에 대해 제약을 부여한다. (module bank-account racket (provide (contract-out [deposit (-> positive? any)] ; 값은 양수여야 함 [balance (-> positive?)])) (define amount 0) (define (deposit a) (set! amount (+ amount a))) (define (balance) amount) ) (require 'bank-account) (deposit 5) (balance) ; => 5 ;; 양수가 아닌 값을 예치하려고 하는 고객은 비난받는다. ;; (deposit -5) ; => deposit: contract violation ;; expected: positive? ;; given: -5 ;; more details.... ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 11. 입력과 출력 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Racket은 이 "port"라는 개념이 있다. 이것은 다른 언어의 ;; 파일 서술자 (file descriptor)와 매우 비슷하다. ;; "/tmp/tmp.txt"를 열고 "Hello World"를 기록한다. ;; 그 파일이 이미 있다면 에러를 발생시킨다. (define out-port (open-output-file "/tmp/tmp.txt")) (displayln "Hello World" out-port) (close-output-port out-port) ;; "/tmp/tmp.txt"에 붙이기 (define out-port (open-output-file "/tmp/tmp.txt" #:exists 'append)) (displayln "Hola mundo" out-port) (close-output-port out-port) ;; 파일에서 다시 읽기 (define in-port (open-input-file "/tmp/tmp.txt")) (displayln (read-line in-port)) ; => "Hello World" (displayln (read-line in-port)) ; => "Hola mundo" (close-input-port in-port) ;; 다르게, call-with-output-file을 사용하면, 명시적으로 파일을 닫지 않아도 된다. (call-with-output-file "/tmp/tmp.txt" #:exists 'update ; 내용을 다시 쓴다. (λ (out-port) (displayln "World Hello!" out-port))) ;; call-with-input-file은 입력에 대해 같은 방식으로 작동한다. (call-with-input-file "/tmp/tmp.txt" (λ (in-port) (displayln (read-line in-port)))) ``` ## 더 읽을거리 더 배우고 싶으면, [Getting Started with Racket](http://docs.racket-lang.org/getting-started/)도 보시오. ================================================ FILE: ko/vim.md ================================================ --- contributors: - ["RadhikaG", "https://github.com/RadhikaG"] translators: - ["Wooseop Kim", "https://github.com/linterpreteur"] - ["Yeongjae Jang", "https://github.com/Liberatedwinner"] --- [Vim](http://www.vim.org) (Vi IMproved)은 유닉스에서 인기 있는 vi 에디터의 클론입니다. Vim은 속도와 생산성을 위해 설계된 텍스트 에디터로, 대부분의 유닉스 기반 시스템에 내장되어 있습니다. 다양한 단축 키를 통해 파일 안에서 빠르게 이동하고 편집할 수 있습니다. ## Vim 조작의 기본 ``` vim # vim으로 열기 :help # (존재하는 경우에) 에 대한, 내장된 도움말 문서 열기 :q # vim 종료 :w # 현재 파일 저장 :wq # 파일 저장 후 종료 ZZ # 파일 저장 후 종료 :q! # 저장하지 않고 종료 # ! *강제로* :q를 실행하여, 저장 없이 종료 :x # 파일 저장 후 종료 (:wq의 축약) u # 동작 취소 CTRL+R # 되돌리기 h # 한 글자 왼쪽으로 이동 j # 한 줄 아래로 이동 k # 한 줄 위로 이동 l # 한 글자 오른쪽으로 이동 # 줄 안에서의 이동 0 # 줄 시작으로 이동 $ # 줄 끝으로 이동 ^ # 줄의 공백이 아닌 첫 문자로 이동 Ctrl+B # 한 화면 뒤로 이동 Ctrl+F # 한 화면 앞으로 이동 Ctrl+D # 반 화면 앞으로 이동 Ctrl+U # 반 화면 뒤로 이동 # 텍스트 검색 /word # 커서 뒤에 나타나는 해당 단어를 모두 하이라이트 ?word # 커서 앞에 나타나는 해당 단어를 모두 하이라이트 n # 해당 단어를 검색 후 다음으로 나타나는 위치로 이동 N # 이전에 나타나는 위치로 이동 :%s/foo/bar/g # 파일 모든 줄에 있는 'foo'를 'bar'로 치환 :s/foo/bar/g # 현재 줄에 있는 'foo'를 'bar'로 치환 :%s/foo/bar/gc # 사용자에게 확인을 요구하는, 모든 줄에 있는 'foo'를 'bar'로 치환 :%s/\n/\r/g # 한 종류의 개행 문자에서 다른 종류의 것으로 치환 (\n에서 \r로) # 문자로 이동 f # 로 건너뛰기 t # 의 바로 뒤로 건너뛰기 # 예를 들어, f< # <로 건너뛰기 t< # <의 바로 뒤로 건너뛰기 # 단어 단위로 이동 w # 한 단어 오른쪽으로 이동 b # 한 단어 왼쪽으로 이동 e # 현재 단어의 끝으로 이동 # 기타 이동 명령어 gg # 파일 맨 위로 이동 G # 파일 맨 아래로 이동 :NUM # 줄 수 NUM(숫자)로 가기 H # 화면 꼭대기로 이동 M # 화면 중간으로 이동 L # 화면 바닥으로 이동 ``` ## 도움말 문서 Vim은 `:help ` 명령을 통해 접근할 수 있는 도움말 문서를 내장하고 있습니다. 예를 들어, `:help navigation` 은 당신의 작업 공간을 탐색하는 방법에 대한 문서를 표시합니다! `:help`는 옵션 없이도 사용할 수 있습니다. 이는 기본 도움말 대화 상자를 표시합니다. 이 대화 상자는 Vim을 시작하는 것이 보다 용이하도록 도와줍니다. ## 모드 Vim은 **모드**의 개념에 기초를 두고 있습니다. - 명령어 모드 - vim은 이 모드로 시작됩니다. 이동과 명령어 입력에 사용합니다. - 삽입 모드 - 파일을 수정합니다. - 비주얼 모드 - 텍스트를 하이라이트하고 그 텍스트에 대한 작업을 합니다. - 실행 모드 - ':' 이후 명령어를 입력합니다. ``` i # 커서 위치 앞에서 삽입 모드로 변경 a # 커서 위치 뒤에서 삽입 모드로 변경 v # 비주얼 모드로 변경 : # 실행 모드로 변경 # 현재 모드를 벗어나 명령어 모드로 변경 # 복사와 붙여넣기 y # 선택한 객체 복사(Yank) yy # 현재 줄 복사 d # 선택한 객체 삭제 dd # 현재 줄 삭제 p # 커서 위치 뒤에 복사한 텍스트 붙여넣기 P # 커서 위치 앞에 복사한 텍스트 붙여넣기 x # 현재 커서 위치의 문자 삭제 ``` ## vim의 '문법' Vim의 명령어는 '서술어-수식어-목적어'로 생각할 수 있습니다. 서술어 - 취할 동작 수식어 - 동작을 취할 방식 목적어 - 동작을 취할 객체 '서술어', '수식어', '목적어'의 예시는 다음과 같습니다. ``` # '서술어' d # 지운다 c # 바꾼다 y # 복사한다 v # 선택한다 # '수식어' i # 안에 a # 근처에 NUM # (숫자) f # 찾아서 그곳에 t # 찾아서 그 앞에 / # 문자열을 커서 뒤로 찾아서 ? # 문자열을 커서 앞으로 찾아서 # '목적어' w # 단어를 s # 문장을 p # 문단을 b # 블록을 # 예시 '문장' (명령어) d2w # 단어 2개를 지운다 cis # 문장 안을 바꾼다 yip # 문단 안을 복사한다 ct< # 여는 괄호까지 바꾼다 # 현재 위치에서 다음 여는 괄호까지의 텍스트를 바꾼다 d$ # 줄 끝까지 지운다 ``` ## 몇 가지 트릭 ``` > # 선택한 영역 한 칸 들여쓰기 < # 선택한 영역 한 칸 내어쓰기 :earlier 15m # 15분 전의 상태로 되돌리기 :later 15m # 위의 명령어를 취소 ddp # 이어지는 줄과 위치 맞바꾸기 (dd 후 p) . # 이전 동작 반복 :w !sudo tee % # 현재 파일을 루트 권한으로 저장 :set syntax=c # 문법 강조를 'C'의 것으로 설정 :sort # 모든 줄을 정렬 :sort! # 모든 줄을 역순으로 정렬 :sort u # 모든 줄을 정렬하고, 중복되는 것을 삭제 ~ # 선택된 텍스트의 대/소문자 토글 u # 선택된 텍스트를 소문자로 바꾸기 U # 선택된 텍스트를 대문자로 바꾸기 # 텍스트 폴딩 zf # 선택된 텍스트 위치에서 폴딩 만들기 zo # 현재 폴딩 펴기 zc # 현재 폴딩 접기 zR # 모든 폴딩 펴기 zM # 모든 폴딩 접기 zi # 폴딩 접기/펴기 토글 zd # 접은 폴딩 삭제 ``` ## 매크로 매크로는 기본적으로 녹화할 수 있는 동작을 말합니다. 매크로를 녹화하기 시작하면, 끝날 때까지 **모든** 동작과 명령어가 녹화됩니다. 매크로를 호출하면 선택한 텍스트에 대해 정확히 같은 순서의 동작과 명령어가 실행됩니다. ``` qa # 'a'라는 이름의 매크로 녹화 시작 q # 녹화 중지 @a # 매크로 실행 ``` ### ~/.vimrc 설정 .vimrc 파일은 Vim이 시작할 때의 설정을 결정합니다. 다음은 ~/.vimrc 파일의 예시입니다. ```vim " ~/.vimrc 예시 " 2015.10 " vim이 iMprove 되려면 필요 set nocompatible " 자동 들여쓰기 등을 위해 파일 명으로부터 타입 결정 filetype indent plugin on " 신택스 하이라이팅 켜기 syntax on " 커맨드 라인 완성 향상 set wildmenu " 대문자를 썼을 때가 아니면 대소문자 구분하지 않고 검색 set ignorecase set smartcase " 줄넘김을 했을 때 파일에 따른 들여쓰기가 켜져 있지 않다면 " 현재 줄과 같은 들여쓰기를 유지 set autoindent " 좌측에 줄 번호 표시 set number " 들여쓰기 설정 (개인 기호에 따라 변경) " 탭 하나와 시각적으로 같을 스페이스 개수 set tabstop=4 " 편집할 때 탭 하나에 들어갈 스페이스 수 set softtabstop=4 " 들여쓰기 혹은 내어쓰기 작업(>>, <<)을 했을 때 움직일 스페이스 개수 set shiftwidth=4 " 탭을 스페이스로 변환 set expandtab " 들여쓰기와 정렬에 자동 탭 및 스페이스 사용 set smarttab ``` ### 참고 자료 [(영어) Vim 홈페이지](http://www.vim.org/index.php) `$ vimtutor` [(영어) vim 입문과 기초](https://danielmiessler.com/study/vim/) [(영어) 엄마가 말해주지 않은 Vim의 어두운 구석들 (Stack Overflow 게시물)](http://stackoverflow.com/questions/726894/what-are-the-dark-corners-of-vim-your-mom-never-told-you-about) [(영어) 아치 리눅스 위키](https://wiki.archlinux.org/index.php/Vim) ================================================ FILE: ko/xml.md ================================================ --- contributors: - ["João Farias", "https://github.com/JoaoGFarias"] - ["Rachel Stiyer", "https://github.com/rstiyer"] - ["Deepanshu Utkarsh", "https://github.com/duci9y"] translators: - ["Wooseop Kim", "https://github.com/linterpreteur"] --- XML은 데이터를 저장하고 전송하기 위해 설계된 마크업 언어입니다. 인간과 기계 모두가 읽을 수 있도록 만들어졌습니다. XML은 HTML과는 달리 데이터를 보여주는 방법이나 그 형식을 특정하지 않습니다. 단지 데이터를 담을 뿐입니다. 차이는 **내용**과 **마크업**에 있습니다. 내용은 무엇이든 될 수 있지만, 마크업은 정의되어 있습니다. ## 기초 정의 및 도입 XML 문서는 기본적으로 자신을 설명하는 *속성*을 가질 수 있으며 자식으로서 텍스트 혹은 다른 요소를 가질 수 있는 *요소*들로 이루어집니다. 모든 XML 문서는 반드시 루트 요소를 가져야 합니다. 루트 요소는 문서에 있는 모든 다른 요소들의 조상입니다. XML 파서는 매우 엄격하게 설계되어 있으므로 문서의 형식이 틀렸다면 파싱을 멈출 것입니다. 그러므로 모든 XML 문서는 [(영어) XML 문법 규칙](http://www.w3schools.com/xml/xml_syntax.asp)을 따른다고 보장할 수 있습니다. ```xml 내용 Text Text Text ``` ## XML 문서 XML이 유용한 것은 인간도 읽을 수 있다는 것입니다. 다음의 문서는 에릭 레이의 XML 배우기를 포함해 세 권의 책을 파는 서점을 정의한다는 것을 알 수 있습니다. XML 파서 없이도 이렇게 쉽습니다. ```xml 매일 이탈리아 요리 지아다 데 라우렌티스 2005 30.00 해리 포터 J K 롤링 2005 29.99 XML 배우기 에릭 레이 2003 39.95 ``` ## 적격성과 유효성 XML 문서는 문법적으로 정확할 경우 *적격*합니다. 하지만 문서 유형 정의(DTD)를 이용하여 문서에 제약을 더 추가할 수 있습니다. 한 문서의 요소와 속성이 DTD 안에 정의되어 있고 그 파일에 특정된 문법을 따른다면 *적격*할 뿐만 아니라 그 DTD에 대하여 *유효*하다고 말합니다. ```xml Everyday Italian Giada De Laurentiis 2005 30.00 ]> ]> Everyday Italian 30.00 ``` ## DTD 호환성과 XML 스키마 정의 DTD는 오래되었기 때문에 지원이 광범위합니다. 불행히도 네임스페이스와 같은 현대적 XML 기능은 DTD에서 지원하지 않습니다. XML 스키마 정의(XSD)가 XML 문서의 문법을 정의하기 위한 DTD의 대체재입니다. ## Resources * [(영어) Validate your XML](http://www.xmlvalidation.com) ## Further Reading * [(영어) XML 스키마 정의 튜토리얼](http://www.w3schools.com/xml/xml_schema.asp) * [(영어) DTD 튜토리얼](http://www.w3schools.com/xml/xml_dtd_intro.asp) * [(영어) XML 튜토리얼](http://www.w3schools.com/xml/default.asp) * [(영어) XPath 쿼리로 XML 파싱하기](http://www.w3schools.com/xml/xml_xpath.asp) ================================================ FILE: ko/yaml.md ================================================ --- contributors: - ["Leigh Brenecki", "https://github.com/adambrenecki"] - ["Suhas SG", "https://github.com/jargnar"] translators: - ["Wooseop Kim", "https://github.com/linterpreteur"] - ["Justin Yang", "https://github.com/justin-themedium"] --- YAML은 인간이 직접 쓰고 읽을 수 있도록 설계된 데이터 직렬화 언어입니다. YAML은 마치 파이썬처럼 개행과 들여쓰기에 문법적으로 의미를 준 JSON의 엄격한 수퍼셋입니다. 하지만 파이썬과는 달리 YAML은 탭 문자를 들여쓰기에 사용하지 않습니다. ```yaml --- # 문서 시작 # YAML의 주석은 이런 식입니다. ############ # 스칼라 형 # ############ # 문서 내내 이어질 루트 객체는 맵입니다. # 맵은 다른 언어의 딕셔너리, 해시, 혹은 객체에 해당합니다. 키: 값 다른_키: 다른 값이 여기 옵니다. 숫자_값: 100 과학적_표기법: 1e+12 # 숫자 1은 불리언이 아닌 값으로 처리됩니다. 불리언으로 처리하고 싶다면 # true를 사용하세요. 불리언: true 널_값: null 띄어서 쓴 키: 값 # 문자열에 따옴표를 칠 필요는 없습니다. 하지만 칠 수도 있습니다. 하지만: '따옴표에 담은 문자열' '키도 따옴표에 담을 수 있습니다.': "키에 ':'을 넣고 싶다면 유용합니다." 작은 따옴표: '는 ''하나''의 이스케이프 패턴을 갖습니다' 큰 따옴표: "는 많이 갖습니다. \", \0, \t, \u263A, \x0d\x0a == \r\n, 그리고 더." # UTF-8/16/32 문자는 인코딩되어야 합니다. 첨자 2: \u00B2 # 여러 줄의 문자열은 (|을 이용한) '리터럴 블락' 혹은 (>을 이용한) '접은 블락'으로 # 쓸 수 있습니다. 리터럴_블락: | 개행을 포함한 이 모든 덩어리가 '리터럴_블락' 키에 대응하는 값이 될 것입니다. 리터럴 값은 들여쓰기가 끝날 때까지 계속되며 들여쓰기는 문자열에 포함되지 않습니다. '들여쓰기를 더 한' 줄은 나머지 들여쓰기를 유지합니다. 이 줄은 띄어쓰기 4개만큼 들여쓰기 됩니다. 접는_방식: > 이 텍스트 덩어리가 전부 '접는_방식' 키의 값이 되지만, 이번에는 모든 개행 문자가 띄어쓰기 하나로 대체됩니다. 위와 같이 텅 빈 줄은 개행 문자로 바뀝니다. '더 들여쓴' 줄 역시 개행 문자를 유지합니다. 이 텍스트는 두 줄에 걸쳐 나타날 것입니다. ########## # 모임 형 # ########## # 중첩은 들여쓰기를 사용합니다. 2칸 띄어쓰기가 많이 쓰입니다(필수는 아닙니다). 중첩된_맵: 키: 값 다른_키: 다른 값 다른_중첩된_맵: 안녕: 안녕 # 맵은 반드시 문자열 키를 가지는 것은 아닙니다. 0.25: 실수형 키 # 키는 여러 줄에 걸친 객체와 같이 복합적일 수도 있습니다. # ?와 그 뒤의 띄어쓰기로 복합 키의 시작을 나타냅니다. ? | 여러 줄짜리 키 : 그리고 그 값 # YAML은 복합 키 문법으로 연속열 간의 매핑도 지원합니다. # 일부 파서는 지원하지 않을 수 있습니다. # 예시 ? - 맨체스터 유나이티드 - 레알 마드리드 : [2001-01-01, 2002-02-02] # 리스트 혹은 배열에 대응되는 연속열은 다음과 같습니다. # (들여쓰기처럼 '-'를 세는 것에 주의하세요) 연속열: - 하나 - 둘 - 0.5 # 연속열은 다른 형을 포함 가능 - 넷 - 키: 값 다른_키: 다른_값 - - 연속열 안의 - 또 다른 연속열 - - - 중첩된 연속열 지시자 - 접힘 가능 # YAML은 JSON의 수퍼셋이기 때문에, JSON식으로 맵과 연속열을 작성할 수도 # 있습니다. 제이슨_맵: {"키": "값"} 제이슨_열: [3, 2, 1, "발사"] ################# # 기타 YAML 기능 # ################# # YAML은 '앵커'라는 편리한 기능이 있습니다. 앵커를 이용하면 문서에서 # 손쉽게 내용을 복제할 수 있습니다. 이 키들은 같은 값을 갖습니다. 앵커된_내용: &앵커_이름 이 문자열은 두 키의 값으로 나타납니다. 다른_앵커: *앵커_이름 # 앵커는 속성을 복제하거나 상속할 수 있습니다. 기반: &기반 이름: 모두 이름이 같다 # 정규식 << 는 병합 키 언어-비종속 타입으로 불립니다. 이는 하나 # 이상 지정된 맵의 모든 키가 현재 맵 안으로 삽입됨을 나타냅니다. 멍멍: <<: *기반 나이: 10 야옹: <<: *기반 나이: 20 # 멍멍이와 야옹이도 '이름: 모두 이름이 같다'를 갖습니다. # 또한 YAML에는 명시적으로 형을 선언할 수 있는 태그가 있습니다. 명시적_문자열: !!str 0.5 # 파이썬의 복소수 형을 나타내는 다음 태그처럼, 일부 파서는 언어에 종속된 태그를 # 구현합니다. 파이썬_복소수: !!python/complex 1+2j # YAML 복합 키를 언어 종속 태그와 함께 사용할 수도 있습니다. ? !!python/tuple [5, 7] : 오십칠 # 파이썬에서의 {(5, 7): '오십칠'} 객체 ############### # 기타 YAML 형 # ############### # YAML이 이해할 수 있는 스칼라가 문자열과 수만 있는 것은 아닙니다. # ISO 형식 날짜와 시간 리터럴 또한 해석됩니다. 시간: 2001-12-15T02:59:43.1Z 띄어쓰기_한_시간: 2001-12-14 21:59:43.10 -5 날짜: 2002-12-14 # !!binary 태그는 문자열이 실제로는 base64로 인코딩된 # 이진수 객체(BLOB)라는 것을 나타냅니다. 이미지_파일: !!binary | R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= # YAML에는 다음과 같은 집합도 있습니다. 집합: ? 하나 ? 둘 ? 셋 # 집합은 단지 널 값을 갖는 맵입니다. 위는 다음과 같습니다. 집합2: 하나: null 둘: null 셋: null ... # 문서 끝 ``` ### 더 읽기 + [(영어) YAML 공식 사이트](https://yaml.org/) + [(영어) 온라인 YAML 검사기](http://www.yamllint.com/) ================================================ FILE: kotlin.md ================================================ --- name: Kotlin contributors: - ["S Webber", "https://github.com/s-webber"] filename: LearnKotlin.kt --- Kotlin is a statically typed programming language for the JVM, Android and the browser. It is 100% interoperable with Java. [Read more here.](https://kotlinlang.org/) ```kotlin // Single-line comments start with // /* Multi-line comments look like this. */ // The "package" keyword works in the same way as in Java. package com.learnxinyminutes.kotlin /* The entry point to a Kotlin program is a function named "main". The function is passed an array containing any command-line arguments. Since Kotlin 1.3 the "main" function can also be defined without any parameters. */ fun main(args: Array) { /* Declaring variables is done using either "var" or "val". "val" declarations cannot be reassigned, whereas "vars" can. */ val fooVal = 10 // we cannot later reassign fooVal to something else var fooVar = 10 fooVar = 20 // fooVar can be reassigned /* In most cases, Kotlin can determine what the type of a variable is, so we don't have to explicitly specify it every time. We can explicitly declare the type of a variable like so: */ val foo: Int = 7 /* Strings can be represented in a similar way as in Java. Escaping is done with a backslash. */ val fooString = "My String Is Here!" val barString = "Printing on a new line?\nNo Problem!" val bazString = "Do you want to add a tab?\tNo Problem!" println(fooString) println(barString) println(bazString) /* A raw string is delimited by a triple quote ("""). Raw strings can contain newlines and any other characters. */ val fooRawString = """ fun helloWorld(val name : String) { println("Hello, world!") } """ println(fooRawString) /* Strings can contain template expressions. A template expression starts with a dollar sign ($). */ val fooTemplateString = "$fooString has ${fooString.length} characters" println(fooTemplateString) // => My String Is Here! has 18 characters /* For a variable to hold null it must be explicitly specified as nullable. A variable can be specified as nullable by appending a ? to its type. We can access a nullable variable by using the ?. operator. We can use the ?: operator to specify an alternative value to use if a variable is null. */ var fooNullable: String? = "abc" println(fooNullable?.length) // => 3 println(fooNullable?.length ?: -1) // => 3 fooNullable = null println(fooNullable?.length) // => null println(fooNullable?.length ?: -1) // => -1 /* Functions can be declared using the "fun" keyword. Function arguments are specified in brackets after the function name. Function arguments can optionally have a default value. The function return type, if required, is specified after the arguments. */ fun hello(name: String = "world"): String { return "Hello, $name!" } println(hello("foo")) // => Hello, foo! println(hello(name = "bar")) // => Hello, bar! println(hello()) // => Hello, world! /* A function parameter may be marked with the "vararg" keyword to allow a variable number of arguments to be passed to the function. */ fun varargExample(vararg names: Int) { println("Argument has ${names.size} elements") } varargExample() // => Argument has 0 elements varargExample(1) // => Argument has 1 elements varargExample(1, 2, 3) // => Argument has 3 elements /* When a function consists of a single expression then the curly brackets can be omitted. The body is specified after the = symbol. */ fun odd(x: Int): Boolean = x % 2 == 1 println(odd(6)) // => false println(odd(7)) // => true // If the return type can be inferred then we don't need to specify it. fun even(x: Int) = x % 2 == 0 println(even(6)) // => true println(even(7)) // => false /* You can also use lambda functions, with the '->' operator separating the parameters from the function body. */ val fooLambda: (Int) -> Int = {n -> n + 1} println(fooLambda(1)) // => 2 // Functions can take functions as arguments and return functions. fun not(f: (Int) -> Boolean): (Int) -> Boolean { return {n -> !f.invoke(n)} } // Named functions can be specified as arguments using the :: operator. val notOdd = not(::odd) val notEven = not(::even) /* Lambda expressions can be specified as arguments. If it's the only argument parentheses can be omitted. */ val notZero = not {n -> n == 0} /* If a lambda has only one parameter then its declaration can be omitted (along with the ->). The name of the single parameter will be "it". */ val notPositive = not {it > 0} for (i in 0..4) { println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}") } // The "class" keyword is used to declare classes. class ExampleClass(val x: Int) { fun memberFunction(y: Int): Int { return x + y } infix fun infixMemberFunction(y: Int): Int { return x * y } } /* To create a new instance we call the constructor. Note that Kotlin does not have a "new" keyword. */ val fooExampleClass = ExampleClass(7) // Member functions can be called using dot notation. println(fooExampleClass.memberFunction(4)) // => 11 /* If a function has been marked with the "infix" keyword then it can be called using infix notation. */ println(fooExampleClass infixMemberFunction 4) // => 28 /* Data classes are a concise way to create classes that just hold data. The "hashCode"/"equals" and "toString" methods are automatically generated. */ data class DataClassExample (val x: Int, val y: Int, val z: Int) val fooData = DataClassExample(1, 2, 4) println(fooData) // => DataClassExample(x=1, y=2, z=4) // Data classes have a "copy" function. val fooCopy = fooData.copy(y = 100) println(fooCopy) // => DataClassExample(x=1, y=100, z=4) // Objects can be destructured into multiple variables. val (a, b, c) = fooCopy println("$a $b $c") // => 1 100 4 // destructuring in "for" loop for ((a, b, c) in listOf(fooData)) { println("$a $b $c") // => 1 2 4 } val mapData = mapOf("a" to 1, "b" to 2) // Map.Entry is destructurable as well for ((key, value) in mapData) { println("$key -> $value") } // The "with" function is similar to the JavaScript "with" statement. data class MutableDataClassExample (var x: Int, var y: Int, var z: Int) val fooMutableData = MutableDataClassExample(7, 4, 9) with (fooMutableData) { x -= 2 y += 2 z-- } println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8) /* We can create a list using the "listOf" function. The list will be immutable - elements cannot be added or removed. */ val fooList = listOf("a", "b", "c") println(fooList.size) // => 3 println(fooList.first()) // => a println(fooList.last()) // => c // Elements of a list can be accessed by their index. println(fooList[1]) // => b // A mutable list can be created using the "mutableListOf" function. val fooMutableList = mutableListOf("a", "b", "c") fooMutableList.add("d") println(fooMutableList.last()) // => d println(fooMutableList.size) // => 4 // We can create a set using the "setOf" function. val fooSet = setOf("a", "b", "c") println(fooSet.contains("a")) // => true println(fooSet.contains("z")) // => false // We can create a map using the "mapOf" function. val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9) // Map values can be accessed by their key. println(fooMap["a"]) // => 8 /* Sequences represent lazily-evaluated collections. We can create a sequence using the "generateSequence" function. */ val fooSequence = generateSequence(1, { it + 1 }) val x = fooSequence.take(10).toList() println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // An example of using a sequence to generate Fibonacci numbers: fun fibonacciSequence(): Sequence { var a = 0L var b = 1L fun next(): Long { val result = a + b a = b b = result return a } return generateSequence(::next) } val y = fibonacciSequence().take(10).toList() println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] // Kotlin provides higher-order functions for working with collections. val z = (1..9).map {it * 3} .filter {it < 20} .groupBy {it % 2 == 0} .mapKeys {if (it.key) "even" else "odd"} println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]} // A "for" loop can be used with anything that provides an iterator. for (c in "hello") { println(c) } // "while" loops work in the same way as other languages. var ctr = 0 while (ctr < 5) { println(ctr) ctr++ } do { println(ctr) ctr++ } while (ctr < 10) /* "if" can be used as an expression that returns a value. For this reason the ternary ?: operator is not needed in Kotlin. */ val num = 5 val message = if (num % 2 == 0) "even" else "odd" println("$num is $message") // => 5 is odd // "when" can be used as an alternative to "if-else if" chains. val i = 10 when { i < 7 -> println("first block") fooString.startsWith("hello") -> println("second block") else -> println("else block") } // "when" can be used with an argument. when (i) { 0, 21 -> println("0 or 21") in 1..20 -> println("in the range 1 to 20") else -> println("none of the above") } // "when" can be used as an expression that returns a value. var result = when (i) { 0, 21 -> "0 or 21" in 1..20 -> "in the range 1 to 20" else -> "none of the above" } println(result) /* We can check if an object is of a particular type by using the "is" operator. If an object passes a type check then it can be used as that type without explicitly casting it. */ fun smartCastExample(x: Any) : Boolean { if (x is Boolean) { // x is automatically cast to Boolean return x } else if (x is Int) { // x is automatically cast to Int return x > 0 } else if (x is String) { // x is automatically cast to String return x.isNotEmpty() } else { return false } } println(smartCastExample("Hello, world!")) // => true println(smartCastExample("")) // => false println(smartCastExample(5)) // => true println(smartCastExample(0)) // => false println(smartCastExample(true)) // => true // Smartcast also works with when block fun smartCastWhenExample(x: Any) = when (x) { is Boolean -> x is Int -> x > 0 is String -> x.isNotEmpty() else -> false } /* Extensions are a way to add new functionality to a class. This is similar to C# extension methods. */ fun String.remove(c: Char): String { return this.filter {it != c} } println("Hello, world!".remove('l')) // => Heo, word! } // Enum classes are similar to Java enum types. enum class EnumExample { A, B, C // Enum constants are separated with commas. } fun printEnum() = println(EnumExample.A) // => A // Since each enum is an instance of the enum class, they can be initialized as: enum class EnumExample(val value: Int) { A(value = 1), B(value = 2), C(value = 3) } fun printProperty() = println(EnumExample.A.value) // => 1 // Every enum has properties to obtain its name and ordinal(position) in the enum class declaration: fun printName() = println(EnumExample.A.name) // => A fun printPosition() = println(EnumExample.A.ordinal) // => 0 /* The "object" keyword can be used to create singleton objects. We cannot instantiate it but we can refer to its unique instance by its name. This is similar to Scala singleton objects. */ object ObjectExample { fun hello(): String { return "hello" } override fun toString(): String { return "Hello, it's me, ${ObjectExample::class.simpleName}" } } fun useSingletonObject() { println(ObjectExample.hello()) // => hello // In Kotlin, "Any" is the root of the class hierarchy, just like "Object" is in Java val someRef: Any = ObjectExample println(someRef) // => Hello, it's me, ObjectExample } /* The not-null assertion operator (!!) converts any value to a non-null type and throws an exception if the value is null. */ var b: String? = "abc" val l = b!!.length data class Counter(var value: Int) { // overload Counter += Int operator fun plusAssign(increment: Int) { this.value += increment } // overload Counter++ and ++Counter operator fun inc() = Counter(value + 1) // overload Counter + Counter operator fun plus(other: Counter) = Counter(this.value + other.value) // overload Counter * Counter operator fun times(other: Counter) = Counter(this.value * other.value) // overload Counter * Int operator fun times(value: Int) = Counter(this.value * value) // overload Counter in Counter operator fun contains(other: Counter) = other.value == this.value // overload Counter[Int] = Int operator fun set(index: Int, value: Int) { this.value = index + value } // overload Counter instance invocation operator fun invoke() = println("The value of the counter is $value") } /* You can also overload operators through extension methods */ // overload -Counter operator fun Counter.unaryMinus() = Counter(-this.value) fun operatorOverloadingDemo() { var counter1 = Counter(0) var counter2 = Counter(5) counter1 += 7 println(counter1) // => Counter(value=7) println(counter1 + counter2) // => Counter(value=12) println(counter1 * counter2) // => Counter(value=35) println(counter2 * 2) // => Counter(value=10) println(counter1 in Counter(5)) // => false println(counter1 in Counter(7)) // => true counter1[26] = 10 println(counter1) // => Counter(value=36) counter1() // => The value of the counter is 36 println(-counter2) // => Counter(value=-5) } ``` ### Further Reading * [Kotlin tutorials](https://kotlinlang.org/docs/tutorials/) * [Try Kotlin in your browser](https://play.kotlinlang.org/) * [A list of Kotlin resources](http://kotlin.link/) ================================================ FILE: lambda-calculus.md ================================================ --- category: Algorithms & Data Structures name: Lambda Calculus contributors: - ["Max Sun", "http://github.com/maxsun"] - ["Yan Hui Hang", "http://github.com/yanhh0"] --- # Lambda Calculus Lambda calculus (λ-calculus), originally created by [Alonzo Church](https://en.wikipedia.org/wiki/Alonzo_Church), is the world's smallest programming language. Despite not having numbers, strings, booleans, or any non-function datatype, lambda calculus can be used to represent any Turing Machine! Lambda calculus is composed of 3 elements: **variables**, **functions**, and **applications**. | Name | Syntax | Example | Explanation | |-------------|------------------------------------|-----------|-----------------------------------------------| | Variable | `` | `x` | a variable named "x" | | Function | `λ.` | `λx.x` | a function with parameter "x" and body "x" | | Application | `` | `(λx.x)a` | calling the function "λx.x" with argument "a" | The most basic function is the identity function: `λx.x` which is equivalent to `f(x) = x`. The first "x" is the function's argument, and the second is the body of the function. ## Free vs. Bound Variables: - In the function `λx.x`, "x" is called a bound variable because it is both in the body of the function and a parameter. - In `λx.y`, "y" is called a free variable because it is never declared before hand. ## Evaluation: Evaluation is done via [β-Reduction](https://en.wikipedia.org/wiki/Lambda_calculus#Beta_reduction), which is essentially lexically-scoped substitution. When evaluating the expression `(λx.x)a`, we replace all occurrences of "x" in the function's body with "a". - `(λx.x)a` evaluates to: `a` - `(λx.y)a` evaluates to: `y` You can even create higher-order functions: - `(λx.(λy.x))a` evaluates to: `λy.a` Although lambda calculus traditionally supports only single parameter functions, we can create multi-parameter functions using a technique called [currying](https://en.wikipedia.org/wiki/Currying). - `(λx.λy.λz.xyz)` is equivalent to `f(x, y, z) = ((x y) z)` Sometimes `λxy.` is used interchangeably with: `λx.λy.` ---- It's important to recognize that traditional **lambda calculus doesn't have numbers, characters, or any non-function datatype!** ## Boolean Logic: There is no "True" or "False" in lambda calculus. There isn't even a 1 or 0. Instead: `T` is represented by: `λx.λy.x` `F` is represented by: `λx.λy.y` First, we can define an "if" function `λbtf` that returns `t` if `b` is True and `f` if `b` is False `IF` is equivalent to: `λb.λt.λf.b t f` Using `IF`, we can define the basic boolean logic operators: `a AND b` is equivalent to: `λab.IF a b F` `a OR b` is equivalent to: `λab.IF a T b` `NOT a` is equivalent to: `λa.IF a F T` *Note: `IF a b c` is essentially saying: `IF((a b) c)`* ## Numbers: Although there are no numbers in lambda calculus, we can encode numbers using [Church numerals](https://en.wikipedia.org/wiki/Church_encoding). For any number n: n = λf.fn so: `0 = λf.λx.x` `1 = λf.λx.f x` `2 = λf.λx.f(f x)` `3 = λf.λx.f(f(f x))` To increment a Church numeral, we use the successor function `S(n) = n + 1` which is: `S = λn.λf.λx.f((n f) x)` Using successor, we can define add: `ADD = λab.(a S)b` **Challenge:** try defining your own multiplication function! ## Get even smaller: SKI, SK and Iota ### SKI Combinator Calculus Let S, K, I be the following functions: `I x = x` `K x y = x` `S x y z = x z (y z)` We can convert an expression in the lambda calculus to an expression in the SKI combinator calculus: 1. `λx.x = I` 2. `λx.c = Kc` provided that `x` does not occur free in `c` 3. `λx.(y z) = S (λx.y) (λx.z)` Take the church number 2 for example: `2 = λf.λx.f(f x)` For the inner part `λx.f(f x)`: ``` λx.f(f x) = S (λx.f) (λx.(f x)) (case 3) = S (K f) (S (λx.f) (λx.x)) (case 2, 3) = S (K f) (S (K f) I) (case 2, 1) ``` So: ``` 2 = λf.λx.f(f x) = λf.(S (K f) (S (K f) I)) = λf.((S (K f)) (S (K f) I)) = S (λf.(S (K f))) (λf.(S (K f) I)) (case 3) ``` For the first argument `λf.(S (K f))`: ``` λf.(S (K f)) = S (λf.S) (λf.(K f)) (case 3) = S (K S) (S (λf.K) (λf.f)) (case 2, 3) = S (K S) (S (K K) I) (case 2, 3) ``` For the second argument `λf.(S (K f) I)`: ``` λf.(S (K f) I) = λf.((S (K f)) I) = S (λf.(S (K f))) (λf.I) (case 3) = S (S (λf.S) (λf.(K f))) (K I) (case 2, 3) = S (S (K S) (S (λf.K) (λf.f))) (K I) (case 1, 3) = S (S (K S) (S (K K) I)) (K I) (case 1, 2) ``` Merging them up: ``` 2 = S (λf.(S (K f))) (λf.(S (K f) I)) = S (S (K S) (S (K K) I)) (S (S (K S) (S (K K) I)) (K I)) ``` Expanding this, we would end up with the same expression for the church number 2 again. ### SK Combinator Calculus The SKI combinator calculus can still be reduced further. We can remove the I combinator by noting that `I = SKK`. We can substitute all `I`'s with `SKK`. ### Iota Combinator The SK combinator calculus is still not minimal. Defining: ``` ι = λf.((f S) K) ``` We have: ``` I = ιι K = ι(ιI) = ι(ι(ιι)) S = ι(K) = ι(ι(ι(ιι))) ``` ## For more advanced reading: 1. [A Tutorial Introduction to the Lambda Calculus](http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf) 2. [Cornell CS 312 Recitation 26: The Lambda Calculus](http://www.cs.cornell.edu/courses/cs3110/2008fa/recitations/rec26.html) 3. [Wikipedia - Lambda Calculus](https://en.wikipedia.org/wiki/Lambda_calculus) 4. [Wikipedia - SKI combinator calculus](https://en.wikipedia.org/wiki/SKI_combinator_calculus) 5. [Wikipedia - Iota and Jot](https://en.wikipedia.org/wiki/Iota_and_Jot) ================================================ FILE: latex.md ================================================ --- name: LaTeX contributors: - ["Chaitanya Krishna Ande", "http://icymist.github.io"] - ["Colton Kohnke", "https://github.com/voltnor"] - ["Sricharan Chiruvolu", "http://sricharan.xyz"] - ["Ramanan Balakrishnan", "https://github.com/ramananbalakrishnan"] - ["Svetlana Golubeva", "https://attillax.github.io/"] - ["Oliver Kopp", "http://orcid.org/0000-0001-6962-4290"] filename: learn-latex.tex --- ```tex % All comment lines start with % % There are no multi-line comments % LaTeX is NOT a "What You See Is What You Get" word processing software like % MS Word, or OpenOffice Writer % Every LaTeX command starts with a backslash (\) % LaTeX documents start with a defining the type of document it's compiling % Other document types include book, report, presentations, etc. % The options for the document appear in the [] brackets. In this case % it specifies we want to use 12pt font. \documentclass[12pt]{article} % Next we define the packages the document uses. % If you want to include graphics, colored text, or % source code from another language file into your document, % you need to enhance the capabilities of LaTeX. This is done by adding packages. % I'm going to include the float and caption packages for figures % and hyperref package for hyperlinks \usepackage{caption} \usepackage{float} \usepackage{hyperref} % We can define some other document properties too! \author{Chaitanya Krishna Ande, Colton Kohnke, Sricharan Chiruvolu \& \\ Svetlana Golubeva} \date{\today} \title{Learn \LaTeX{} in Y Minutes!} % Now we're ready to begin the document % Everything before this line is called "The Preamble" \begin{document} % if we set the author, date, title fields, we can have LaTeX % create a title page for us. \maketitle % If we have sections, we can create table of contents. We have to compile our % document twice to make it appear in right order. % It is a good practice to separate the table of contents form the body of the % document. To do so we use \newpage command \newpage \tableofcontents \newpage % Most research papers have abstract, you can use the predefined commands for this. % This should appear in its logical order, therefore, after the top matter, % but before the main sections of the body. % This command is available in the document classes article and report. \begin{abstract} \LaTeX{} documentation written as \LaTeX! How novel and totally not my idea! \end{abstract} % Section commands are intuitive. % All the titles of the sections are added automatically to the table of contents. \section{Introduction} Hello, my name is Colton and together we're going to explore \LaTeX! \section{Another section} This is the text for another section. I think it needs a subsection. \subsection{This is a subsection} % Subsections are also intuitive. I think we need another one. \subsubsection{Pythagoras} Much better now. \label{subsec:pythagoras} % By using the asterisk we can suppress LaTeX's inbuilt numbering. % This works for other LaTeX commands as well. \section*{This is an unnumbered section} However not all sections have to be numbered! \section{Some Text notes} %\section{Spacing} % Need to add more information about space intervals \LaTeX{} is generally pretty good about placing text where it should go. If a line \\ needs \\ to \\ break \\ you add \textbackslash\textbackslash{} to the source code. Separate paragraphs by empty lines. You need to add a tilde after abbreviations (if not followed by a comma) for a non-breaking space, because otherwise the spacing after the dot is too large: E.g., i.e., etc.~are such abbreviations. \section{Lists} Lists are one of the easiest things to create in \LaTeX! I need to go shopping tomorrow, so let's make a grocery list. \begin{enumerate} % This creates an "enumerate" environment. % \item tells the enumerate to increment \item Salad. \item 27 watermelon. \item A single jackrabbit. % we can even override the item number by using [] \item[how many?] Medium sized squirt guns. Not a list item, but still part of the enumerate. \end{enumerate} % All environments must have an end. \section{Math} One of the primary uses for \LaTeX{} is to produce academic articles or technical papers. Usually in the realm of math and science. As such, we need to be able to add special symbols to our paper! Math has many symbols, far beyond what you can find on a keyboard; Set and relation symbols, arrows, operators, and Greek letters to name a few. Sets and relations play a vital role in many mathematical research papers. Here's how you state all x that belong to X, $\forall x \in X$. % Notice how I needed to add $ signs before and after the symbols. This is % because when writing, we are in text-mode. % However, the math symbols only exist in math-mode. % We can enter math-mode from text mode with the $ signs. % The opposite also holds true. Variable can also be rendered in math-mode. % We can also enter math mode with \[\] \[a^2 + b^2 = c^2 \] My favorite Greek letter is $\xi$. I also like $\beta$, $\gamma$ and $\sigma$. I haven't found a Greek letter yet that \LaTeX{} doesn't know about! Operators are essential parts of a mathematical document: trigonometric functions ($\sin$, $\cos$, $\tan$), logarithms and exponentials ($\log$, $\exp$), limits ($\lim$), etc.~have pre-defined LaTeX commands. Let's write an equation to see how it's done: $\cos(2\theta) = \cos^{2}(\theta) - \sin^{2}(\theta)$ Fractions (Numerator-denominators) can be written in these forms: % 10 / 7 $$ ^{10}/_{7} $$ % Relatively complex fractions can be written as % \frac{numerator}{denominator} $$ \frac{n!}{k!(n - k)!} $$ We can also insert equations in an ``equation environment''. % Display math with the equation 'environment' \begin{equation} % enters math-mode c^2 = a^2 + b^2. \label{eq:pythagoras} % for referencing \end{equation} % all \begin statements must have an end statement We can then reference our new equation! Eqn.~\ref{eq:pythagoras} is also known as the Pythagoras Theorem which is also the subject of Sec.~\ref{subsec:pythagoras}. A lot of things can be labeled: figures, equations, sections, etc. Summations and Integrals are written with sum and int commands: % Some LaTeX compilers will complain if there are blank lines % In an equation environment. \begin{equation} \sum_{i=0}^{5} f_{i} \end{equation} \begin{equation} \int_{0}^{\infty} \mathrm{e}^{-x} \mathrm{d}x \end{equation} \section{Figures} Let's insert a figure. Figure placement can get a little tricky. Basic options are [t] for top, [b] for bottom, [h] for here (approximately). I definitely have to lookup the placement options each time. % See https://en.wikibooks.org/wiki/LaTeX/Floats,_Figures_and_Captions for more details \begin{figure}[H] % H here denoted the placement option. \centering % centers the figure on the page % Inserts a figure scaled to 0.8 the width of the page. %\includegraphics[width=0.8\linewidth]{right-triangle.png} % Commented out for compilation purposes. Please use your imagination. \caption{Right triangle with sides $a$, $b$, $c$} \label{fig:right-triangle} \end{figure} \subsection{Table} We can also insert Tables in the same way as figures. \begin{table}[H] \caption{Caption for the Table.} % the {} arguments below describe how each row of the table is drawn. % The basics are simple: one letter for each column, to control alignment: % basic options are: c, l, r and p for centered, left, right and paragraph % optionally, you can add a | for a vertical line % See https://en.wikibooks.org/wiki/LaTeX/Tables for more details \begin{tabular}{c|cc} % here it means "centered | vertical line, centered centered" Number & First Name & Last Name \\ % Column rows are separated by & \hline % a horizontal line 1 & Biggus & Dickus \\ 2 & Monty & Python \end{tabular} % it will approximately be displayed like this % Number | First Name Last Name % -------|--------------------------- % because of \hline % 1 | Biggus Dickus % 2 | Monty Python \end{table} \section{Getting \LaTeX{} to not compile something (i.e.~Source Code)} Let's say we want to include some code into our \LaTeX{} document, we would then need \LaTeX{} to not try and interpret that text and instead just print it to the document. We do this with a verbatim environment. % There are other packages that exist (i.e. minty, lstlisting, etc.) % but verbatim is the bare-bones basic one. \begin{verbatim} print("Hello World!") a%b; % look! We can use % signs in verbatim. random = 4; #decided by fair random dice roll, https://www.xkcd.com/221/ See https://www.explainxkcd.com/wiki/index.php/221:_Random_Number \end{verbatim} \section{Compiling} By now you're probably wondering how to compile this fabulous document and look at the glorious glory that is a \LaTeX{} pdf. (Yes, this document actually does compile). Getting to the final document using \LaTeX{} consists of the following steps: \begin{enumerate} \item Write the document in plain text (the ``source code''). \item Compile source code to produce a pdf. The compilation step looks like this (in Linux): \\ \begin{verbatim} > pdflatex learn-latex.tex \end{verbatim} \end{enumerate} A number of \LaTeX{} editors combine both Step 1 and Step 2 in the same piece of software. So, you get to see Step 1, but not Step 2 completely. Step 2 is still happening behind the scenes\footnote{In cases, where you use references (like Eqn.~\ref{eq:pythagoras}), you may need to run Step 2 multiple times, to generate an intermediary *.aux file.}. % Also, this is how you add footnotes to your document! % with a simple \footnote{...} command. They are numbered ¹, ², ... by default. You write all your formatting information in plain text in Step 1. The compilation part in Step 2 takes care of producing the document in the format you defined in Step 1. \section{Hyperlinks} We can also insert hyperlinks in our document. To do so we need to include the package hyperref into preamble with the command: \begin{verbatim} \usepackage{hyperref} \end{verbatim} There exists two main types of links: visible URL \\ \url{https://learnxinyminutes.com/latex/}, or \href{https://learnxinyminutes.com/latex/}{shadowed by text} % You can not add extra-spaces or special symbols into shadowing text since it % will cause mistakes during the compilation This package also produces list of thumbnails in the output PDF document and active links in the table of contents. \section{Writing in ASCII or other encodings} By default, historically LaTeX accepts inputs which are pure ASCII (128), but not extended ASCII, meaning without accents (à, è etc.) and non-Latin symbols. It is easy to insert accents and basic Latin symbols, with backslash shortcuts Like \,c, \'e, \`A, \ae and \oe etc. % for ç, é, À, etc % See https://en.wikibooks.org/wiki/LaTeX/Special_Characters#Escaped_codes for more To write directly in UTF-8, when compiling with pdflatex, use \begin{verbatim} \usepackage[utf8]{inputenc} \end{verbatim} The selected font has to support the glyphs used for your document, you have to add \begin{verbatim} \usepackage[T1]{fontenc} \end{verbatim} Since LuaTeX and XeLaTeX were designed with built-in support for UTF-8, making life easier for writing in non-Latin alphabets. \section{End} That's all for now! % Most often, you would want to have a references section in your document. % The easiest way to set this up would be by using the bibliography section \begin{thebibliography}{1} % similar to other lists, the \bibitem command can be used to list items % each entry can then be cited directly in the body of the text \bibitem{latexwiki} The amazing \LaTeX{} wikibook: \emph{https://en.wikibooks.org/wiki/LaTeX} \bibitem{latextutorial} An actual tutorial: \emph{http://www.latex-tutorial.com} \end{thebibliography} % end the document \end{document} ``` ## More on LaTeX * The amazing LaTeX Wikibook: [https://en.wikibooks.org/wiki/LaTeX](https://en.wikibooks.org/wiki/LaTeX) * An actual tutorial: [http://www.latex-tutorial.com/](http://www.latex-tutorial.com/) * A quick guide for learning LaTeX: [Learn LaTeX in 30 minutes](https://www.overleaf.com/learn/latex/Learn_LaTeX_in_30_minutes) * An interactive platform to learn LaTeX (installationfree) [learnlatex.org/](https://www.learnlatex.org/) * Stack Exchange's question and answer site about TeX, LaTeX, ConTeXt, etc. [tex.stackexchange.com](https://tex.stackexchange.com/) ================================================ FILE: lbstanza.md ================================================ --- name: LB Stanza filename: learn-stanza.stanza contributors: - ["Mike Hilgendorf", "https://github.com/m-hilgendorf"] --- LB Stanza (or Stanza for short) is a new optionally-typed general purpose programming language from the University of California, Berkeley. Stanza was designed to help programmers tackle the complexity of architecting large programs and significantly increase the productivity of application programmers across the entire software development life cycle. ``` ; this is a comment ;
This is a block comment ; block comments can be nested with optional tags. ; ; defpackage learn-stanza-in-y: import core import collections ;============================================================================== ; The basics, things you'd find in most programming languages ;============================================================================== ; Variables can be mutable (var) or immutable (val) val immutable = "this string can't be changed" var mutable = "this one can be" mutable = "like this" ; The basic data types (annotations are optional) val an-int: Int = 12345 val a-long: Long = 12345L val a-float: Float = 1.2345f val a-double: Double = 3.14159 val a-string: String = "this is a string" val a-multiline-string = \ this is a "raw" string literal \ ; Print a formatted string with println and "..." % [...] println("this is a formatted string %_ %_" % [mutable, immutable]) ; Stanza is optionally typed, and has a ? (any) type. var anything:? = 0 anything = 3.14159 anything = "a string" ; Stanza has basic collections like Tuples, Arrays, Vectors and HashTables val tuple: Tuple = [mutable, immutable] val array = Array(3) array[0] = "string" array[1] = 1 array[2] = 1.23455 ; array[3] = "out-of-bounds" ; arrays are bounds-checked val vector = Vector() vector[0] = "string" vector[1] = 1 vector[2] = 3.14159 val hash-table = HashTable() hash-table["0"] = 0 hash-table["1"] = 1 hash-table["2"] = 1 ;============================================================================== ; Functions ;============================================================================== ; Functions are declared with the `defn` keyword defn my-function (arg:?) : ; note the space between identifier and arg list println("called my-function with %_" % [arg]) my-function("arg") ; note the lack of a space to call the function ; Functions can be declared inside another function and capture variables from ; the surrounding environment. defn outer (arg): defn inner (): println("outer had arg: %_" % [arg]) inner() outer("something") ; functions are "first-class" in stanza, meaning you can assign variables ; to functions and pass functions as arguments to other functions. val a-function = outer defn do-n-times (arg, func, n:Int): for i in 0 to n do : func(arg) do-n-times("argument", a-function, 3) ; sometimes you want to define a function inline, or use an anonymous function. ; for this you can use the syntax: ; fn (args): ; ... do-n-times("hello", fn (arg): println(arg), 2) ; there is a shorthand for writing anonymous functions do-n-times("hello", { println(_) }, 2) ; the short hand works for multiple arguments as well. val multi-lambda = { println(_ + 2 * _) } multi-lambda(1, 2) ;============================================================================== ; User defined types ;============================================================================== ; Structs are declared with the `defstruct` keyword defstruct MyStruct: field ; constructors are derived automatically val my-struct = MyStruct("field:value") ; fields are accessed using function-call syntax println(field(my-struct)) ; Stanza supports subtyping with a "multimethod" system based on method ; overloading. deftype MyType defmulti a-method (m:MyType) defstruct Foo <: MyType defstruct Bar <: MyType defmethod a-method (a-foo: Foo): println("called a-method on a Foo") defmethod a-method (a-foo: Bar): println("called a-method on a Bar") ;============================================================================== ; The Type System ;============================================================================== ; True and Falseare types with a single value. val a-true: True = true val a-false: False = false ; You can declare a union type, or a value that is one of a set of types val a-boolean: True|False = true val another-boolean: True|False = false ; You can pattern match on types match(a-boolean): (t:True): println("is true") (f:False): println("is false") ; You can match against a single possible type match(a-boolean:True): println("is still true") else: println("is not true") ; You can compose program logic around the type of a variable if anything is Float : println("anything is a float") else if anything is-not String : println("anything is not an int") else : println("I don't know what anything is") ;============================================================================== ; Control Flow ;============================================================================== ; stanza has the standard basic control flow val condition = [false, false] if condition[0] : ; do something false else if condition[1] : ; do another thing false else : ; whatever else false ; there is also a switch statement, which can be used to pattern match ; on values (as opposed to types) switch(anything): "this": false "that": false "the-other-thing": false else: false ; for and while loops are supported while condition[0]: println("do stuff") for i in 0 to 10 do: vector[i] = i ; stanza also supports named labels which can function as break or return ; statements defn another-fn (): label return: label break: while true: if condition[0] is False: break(false) return(false) ; For a comprehensive guide on Stanza's advanced control flow, check out ; this page: http://lbstanza.org/chapter9.html from Stanza-by-Example ;============================================================================== ; Sequences ;============================================================================== ; for "loops" are sugar for a more powerful syntax. val xs = [1, 2, 3] val ys = ['a', 'b', 'c'] val zs = ["foo", "bar", "baz"] for (x in xs, y in ys, z in zs) do : println("x:%_, y:%_, z:%_" % [x, y, z]) ;xs, ys, and zs are all "Seqable" meaning they are Seq types (sequences). ; the `do` identifier is a special function that just applies the body of ; the for loop to each element of the sequence. ; ; A common sequence task is concatenating sequences. This is accomplished ; using the `seq-cat` function. This is analogous to "flattening" iterateors val concat = to-tuple $ for sequence in [xs, ys, zs] seq-cat: sequence ; we can also use a variation to interleave the elements of multiple sequences val interleaved = to-tuple $ for (x in xs, y in ys, z in zs) seq-cat : [x, y, z] println("[%,] [%,]" % [concat, interleaved]) ; Another common task is mapping a sequence to another, for example multiplying ; all the elements of a list of numbers by a constant. To do this we use `seq`. var numbers = [1.0, 2.0, 3.0, 4.0] numbers = to-tuple $ for n in numbers seq : 2.0 * n println("%," % [numbers]) if find({_ == 2.0}, numbers) is-not False : println("found it!") ; or maybe we just want to know if there's something in a sequence var is-there = for n in numbers any? : n == 2.0 ; since this is "syntactic sugar" we can write it explicitly using an ; anonymous function is-there = any?({_ == 2.0}, numbers) ; a detailed reference of the sequence library and various adaptors can ; be found here: http://lbstanza.org/reference.html#anchor439 ========================================================================= ; Documentation ;========================================================================= ; ; Top level statements can be prefixed with the "doc" field which takes ; a string value and is used to autogenerate documentation for the package. doc: \ # Document Strings ``` val you-can = "include code snippets, too" ``` To render documentation as markdown (compatible with mdbook) ```bash stanza doc source.stanza -o docs ``` \ defn docfn () : false ``` ================================================ FILE: ldpl.md ================================================ --- name: LDPL filename: learnLDPL.ldpl contributors: - ["Martín del Río", "https://github.com/lartu"] - ["John Paul Wohlscheid", "https://github.com/JohnBlood"] --- **LDPL** is a powerful, C++ transpiled, open-source programming language designed from the ground up to be excessively expressive, readable, fast and easy to learn. It mimics plain English, in the likeness of older programming languages like COBOL, with the desire that it can be understood by anybody. It's very portable and runs on a plethora of different architectures and operating systems and it even supports UTF-8 out of the box. [Read more here.](https://github.com/lartu/ldpl) ```coffeescript # This is a single line comment in LDPL. # LDPL doesn't have multi-line comments. # LDPL is a case-insensitive language: dIsPlaY and DISPLAY are the same # statement, and foo and FOO name the same variable. # An LDPL source file is divided in two sections, the DATA section and # the PROCEDURE section. DATA: # Within the DATA section, variables are declared. myNumber is number # Defines a real number. myString is text # Defines a string. myList is number list # Defines a list of numbers. myMap is number map # Defines a map of numbers. # LDPL understands four data types: two scalar types (NUMBER, TEXT) # and two container types (LISTs and MAPs). # LISTs can be TEXT LISTs or NUMBER LISTs, while MAPs can be # TEXT MAPs and NUMBER MAPs. You can also chain many containers # to create larger data types: textListList is text list list myMulticontainer is number list list map # Defines a map of lists of lists of numbers. PROCEDURE: # Within the PROCEDURE section, your code is written. store -19.2 in myNumber # Use the STORE statement to assign values store "Hi there" in myString # to variables. push 890 to myList # Use PUSH - TO to append values to lists. push 100 to myList push 500 to myList store 45 in myMap:"someIndex" # Use the : operator to index containers. push list to textListList # Push an empty list into a list of lists. push "LDPL is nice!" to textListList:0 #Push text to the pushed list. display "Hello World!" # Use the DISPLAY statement to print values. # The display statement can receive multiple values separated by spaces. display crlf "How are you today?" myNumber myString crlf # CRLF is the standard line break value in LDPL. display textListList:0:0 " Isn't it?" crlf # IF statements in LDPL are extremely verbose: if myNumber is equal to -19.2 and myList:0 is less than 900 then display "Yes!" crlf else if myMap:"someIndex" is not equal to 45 then display "This is an else if!" crlf else display "Else!" crlf end if # Valid LDPL comparison operators are # - IS EQUAL TO # - IS NOT EQUAL TO # - IS LESS THAN # - IS GREATER THAN # - IS LESS THAN OR EQUAL TO # - IS GREATER THAN OR EQUAL TO if "Hi there!" is not equal to "Bye bye!" then display "Yep, those weren't equal." crlf end if # LDPL normally doesn't understand inline expressions, so you # cannot do stuff like: # if myNumber - 9 * 2 is equal to 10 then # LDPL will set your computer on fire and burst your screen if you do so. # WHILE loops follow the same rules store 0 in myNumber while myNumber is less than 10 do display "Loop number " myNumber "..." crlf in myNumber solve myNumber + 1 # You can do math like this. repeat # You can use 'break' and 'continue' inside loops just like any other language. # LDPL also has FOR loops and FOR EACH loops for myNumber from 0 to 100 step 2 do display myNumber crlf repeat for each myNumber in myList do display myNumber repeat display "Enter your name: " accept myString # Use ACCEPT to let the user input values. display "Hi there, " myString crlf display "How old are you?: " accept myNumber if myNumber is greater than 200 then display "Woah, you are so old!" crlf end if wait 1000 milliseconds # Pause the program for a whole second. # Let's do some math store 1.2 in myNumber in myNumber solve myNumber * (10 / 7.2) # Operators are separated by spaces. floor myNumber display myNumber crlf get random in myNumber # get a random number between 0 and 1 # and store it in myNumber # Functions in LDPL are called sub-procedures. Sub-procedures, like source # files, are divided in sections. The sections found in sub-procedures are # the PARAMETERS section, the LOCAL DATA section and the PROCEDURE section. # All sections except the PROCEDURE section can be skipped if they aren't # used. If no PARAMETERS nor LOCAL DATA sections are used, the PROCEDURE # keyword may be omitted. sub myFunction parameters: a is number # LDPL is pass by reference b is number result is number # Thus you can return values through a parameter. local data: c is number procedure: get random in c in result solve a + b * c end sub sub sayHello display "Hi there!" crlf return display "This won't be displayed :(" end sub call myFunction with 1 2 myNumber display myNumber crlf call sayHello call sayBye # sub-procedures may be called before they are declared sub sayBye display "Bye!" end sub # One of the greatest features of LDPL is the ability to create your # own statements. create statement "say hi" executing sayHello say hi create statement "random add $ and $ in $" executing myFunction random add 1 and 2 in myNumber display myNumber crlf exit ``` ## Further Reading * [LDPL Docs](https://docs.ldpl-lang.org) ================================================ FILE: lean4.md ================================================ --- name: "Lean 4" filename: learnlean4.lean contributors: - ["Balagopal Komarath", "https://bkomarath.rbgo.in/"] - ["Ferinko", "https://github.com/Ferinko"] --- [Lean 4](https://lean-lang.org/) is a dependently typed functional programming language and an interactive theorem prover. ```lean4 /- An enumerated data type. -/ inductive Grade where | A : Grade | B : Grade | F : Grade deriving Repr /- Functions. -/ def grade (m : Nat) : Grade := if 80 <= m then Grade.A else if 60 <= m then Grade.B else Grade.F def highMarks := 80 + 9 def lowMarks := 25 + 25 #eval grade highMarks #eval grade lowMarks #check (0 : Nat) /- #check (0 : Grade) -/ /- This is an error. -/ /- Types themselves are values. -/ #check (Nat : Type) /- Mathematical propositions are values in Lean. `Prop` is the type of propositions. Here are some simple propositions. -/ #check 0 = 1 #check 1 = 1 #check 2^9 - 2^8 = 2^8 /- Notice Lean displays `0 = 1 : Prop` to say: The statement "0 = 1" is a proposition. We want to distinguish true propositions and false propositions. We do this via proofs. Each proposition is a type. `0 = 1` is a type, `1 = 1` is another type. A proposition is true iff there is a value of that type. How do we construct a value of type `1 = 1`? We use a constructor that is defined for that type. `Eq.refl a` constructs a value of type `a = a`. (reflexivity) Using this we can prove `1 = 1` as follows. -/ theorem one_eq_one : 1 = 1 := Eq.refl 1 /- But there is no way to prove (construct a value of type) `0 = 1`. The following will fail. As will `Eq.refl 1` -/ /- theorem zero_eq_one : 0 = 1 := Eq.refl 0 -/ /- Let us prove an inequality involving variables. The `calc` primitive allows us to prove equalities using stepwise calculations. Each step has to be justified by a proof. -/ theorem plus_squared (a b : Nat) : (a+b)^2 = a^2 + 2*a*b + b^2 := calc (a+b)^2 = (a+b)*(a+b) := Nat.pow_two _ _ = (a+b)*a + (a+b)*b := Nat.mul_add _ _ _ _ = a*a + b*a + (a*b + b*b) := by repeat rw [Nat.add_mul] _ = a*a + b*a + a*b + b*b := by rw [← Nat.add_assoc] _ = a*a + a*b + a*b + b*b := by rw [Nat.mul_comm b _] _ = a^2 + a*b + a*b + b*b := by rw [← Nat.pow_two _] _ = a^2 + a*b + a*b + b^2 := by rw [← Nat.pow_two _] _ = a^2 + (a*b + a*b) + b^2 := by rw [Nat.add_assoc (a^_)] _ = a^2 + 2*(a*b) + b^2 := by rw [← Nat.two_mul _] _ = a^2 + 2*a*b + b^2 := by rw [Nat.mul_assoc _ _ _] /- Underscores can be used when there is no ambiguity in what is to be matched. For example, in the first step, we want to apply `Nat.pow_two (a+b)`. But, `(a+b)` is the only pattern here to apply `Nat.pow_two`. So we can omit it. -/ /- Let us now prove more "realistic" theorems. Those involving logical connectives. First, we define even and odd numbers. -/ def Even (n : Nat) := ∃ k, n = 2*k def Odd (n : Nat) := ∃ k, n = 2*k + 1 /- To prove an existential, we can provide specific values if we know them. -/ theorem zero_even : Even 0 := have h : 0 = 2 * 0 := Eq.symm (Nat.mul_zero 2) Exists.intro 0 h /- `Exists.intro v h` proves `∃ x, p x` by substituting `x` by `v` and using the proof `h` for `p v`. -/ /- Now, we will see how to use hypothesis that are existentials to prove conclusions that are existentials. The curly braces around parameters `n` and `m` indicate that they are implicit. Here, Lean will infer them from `hn` and `hm`. -/ theorem even_mul_even_is_even' {n m : Nat} (hn : Even n) (hm : Even m) : Even (n*m) := Exists.elim hn (fun k1 hk1 => Exists.elim hm (fun k2 hk2 => Exists.intro (k1 * ( 2 * k2)) ( calc n*m = (2 * k1) * (2 * k2) := by rw [hk1, hk2] _ = 2 * (k1 * (2 * k2)) := by rw [Nat.mul_assoc] ) ) ) /- Most proofs are written using *tactics*. These are commands to Lean that guide it to construct proofs by itself. The same theorem, proved using tactics. -/ theorem even_mul_even_is_even {n m : Nat} (hn : Even n) (hm : Even m) : Even (n*m) := by have ⟨k1, hk1⟩ := hn have ⟨k2, hk2⟩ := hm apply Exists.intro $ k1 * (2 * k2) calc n*m = (2 * k1) * (2 * k2) := by rw [hk1, hk2] _ = 2 * (k1 * (2 * k2)) := by rw [Nat.mul_assoc] /- Let us work with implications. -/ theorem succ_of_even_is_odd' {n : Nat} : Even n → Odd (n+1) := fun hn => have ⟨k, hk⟩ := hn Exists.intro k ( calc n + 1 = 2 * k + 1 := by rw [hk] ) /- To prove an implication `p → q`, you have to write a function that takes a proof of `p` and construct a proof of `q`. Here, `pn` is proof of `Even n := ∃ k, n = 2 *k`. Eliminating the existential gets us `k` and a proof `hk` of `n = 2 * k`. Now, we have to introduce the existential `∃ k, n + 1 = 2 * k + 1`. This `k` is the same as `k` for `n`. And, the equation is proved by a simple calculation that substitutes `2 * k` for `n`, which is allowed by `hk`. -/ /- Same theorem, now using tactics. -/ theorem succ_of_even_is_odd {n : Nat} : Even n → Odd (n+1) := by intro hn have ⟨k, hk⟩ := hn apply Exists.intro k rw [hk] /- The following theorem can be proved similarly. We will use this theorem later. A `sorry` proves any theorem. It should not be used in real proofs. -/ theorem succ_of_odd_is_even {n : Nat} : Odd n → Even (n+1) := sorry /- We can use theorems by applying them. -/ example : Odd 1 := by apply succ_of_even_is_odd exact zero_even /- The two new tactics are: - `apply p` where `p` is an implication `q → r` and `r` is the goal rewrites the goal to `q`. More generally, `apply t` will unify the current goal with the conclusion of `t` and generate goals for each hypothesis of `t`. - `exact h` solves the goal by stating that the goal is the same as `h`. -/ /- Let us see examples of disjunctions. -/ example : Even 0 ∨ Odd 0 := Or.inl zero_even example : Even 0 ∨ Odd 1 := Or.inl zero_even example : Odd 1 ∨ Even 0 := Or.inr zero_even /- Here, we always know from `p ∨ q` which of `p` and/or `q` is correct. So we can introduce a proof of the correct side. -/ /- Let us see a more "standard" disjunction. Here, from the hypothesis that `n : Nat`, we cannot determine whether `n` is even or odd. So we cannot construct `Or` directly. But, for any specific `n`, we will know which one to construct. This is exactly what induction allows us to do. We introduce the `induction` tactic. The inductive hypothesis is a disjunction. When disjunctions appear at the hypothesis, we use *proof by exhaustive cases*. This is done using the `cases` tactic. -/ theorem even_or_odd {n : Nat} : Even n ∨ Odd n := by induction n case zero => left ; exact zero_even case succ n ihn => cases ihn with | inl h => right ; apply (succ_of_even_is_odd h) | inr h => left ; apply (succ_of_odd_is_even h) /- `induction` is not just for natural numbers. It is for any type, since all types in Lean are inductive. -/ /- We now state Collatz conjecture. The proof is left as an exercise to the reader. -/ def collatz_next (n : Nat) : Nat := if n % 2 = 0 then n / 2 else 3 * n + 1 def iter (k : Nat) (f : Nat → Nat) := match k with | Nat.zero => fun x => x | Nat.succ k' => fun x => f (iter k' f x) theorem collatz : ∀ n, n > 0 → ∃ k, iter k collatz_next n = 1 := sorry /- Now, some "corner cases" in logic. -/ /- The proposition `True` is something that can be trivially proved. `True.intro` is a constructor for proving `True`. Notice that it needs no inputs. -/ theorem obvious : True := True.intro /- On the other hand, there is no constructor for `False`. We have to use `sorry`. -/ theorem impossible : False := sorry /- Any `False` in the hypothesis allows us to conclude anything. Written in term style, we use the eliminator `False.elim`. It takes a proof of `False`, here `h`, and concludes whatever is the goal. -/ theorem nonsense (h : False) : 0 = 1 := False.elim h /- The `contradiction` tactic uses any `False` in the hypothesis to conclude the goal. -/ theorem more_nonsense (h : False) : 1 = 2 := by contradiction /- To illustrate constructive vs classical logic, we now prove the contrapositive theorem. The forward direction does not require classical logic. -/ theorem contrapositive_forward' (p q : Prop) : (p → q) → (¬q → ¬p) := fun pq => fun hqf => fun hp => hqf (pq hp) /- Use the definition `¬q := q → False`. Notice that we have to construct `p → False` given `p → q` and `q → False`. This is just function composition. -/ /- The above proof, using tactics. -/ theorem contrapositive_forward (p q : Prop) : (p → q) → (¬q → ¬p) := by intro hpq intro intro hp specialize hpq hp contradiction /- The reverse requires classical logic. Here, we are required to construct a `q` given values of following types: - `(q → False) → (p → False)`. - `p`. This is impossible without using the law of excluded middle. -/ theorem contrapositive_reverse' (p q : Prop) : (¬q → ¬p) → (p → q) := fun hnqnp => Classical.byCases (fun hq => fun _ => hq) (fun hnq => fun hp => absurd hp (hnqnp hnq)) /- Law of excluded middle tells us that we will have a `q` or a `q → False`. In the first case, it is trivial to construct a `q`, we already have it. In the second case, we give the `q → False` to obtain a `p → False`. Then, we use the fact (in constructive logic) that given `p` and `p → False`, we can construct `False`. Once, we have `False`, we can construct anything, and specifically `q`. -/ /- Same proof, using tactics. -/ theorem contrapositive_reverse (p q : Prop) : (¬q → ¬p) → (p → q) := by intro hnqnp intro hp have emq := Classical.em q cases emq case inl _ => assumption case inr h => specialize hnqnp h ; contradiction /- To illustrate how we can define an work with axiomatic systems. Here is a definition of Groups and some proofs directly translated from "Topics in Algebra" by Herstein, Second edition. -/ /- A `section` introduces a namespace. -/ section GroupTheory /- To define abstract objects like groups, we may use `class`. -/ class Group (G : Type u) where op : G → G → G assoc : ∀ a b c : G, op (op a b) c = op a (op b c) e : G identity: ∀ a : G, op a e = a ∧ op e a = a inverse: ∀ a : G, ∃ b : G, op a b = e ∧ op b a = e /- Let us introduce some notation to make this convenient. -/ open Group infixl:70 " * " => op /- `G` will always stand for a group and variables `a b c` will be elements of that group in this `section`. -/ variable [Group G] {a b c : G} def is_identity (e' : G) := ∀ a : G, (a * e' = a ∧ e' * a = a) /- We prove that the identity element is unique. -/ theorem identity_element_unique : ∀ e' : G, is_identity e' → e' = e := by intro e' intro h specialize h e have ⟨h1, _⟩ := h have h' := identity e' have ⟨_, h2⟩ := h' exact Eq.trans (Eq.symm h2) h1 /- Note that we used the `identity` axiom. -/ /- Left cancellation. We have to use both `identity` and `inverse` axioms from `Group`. -/ theorem left_cancellation : ∀ x y : G, a * x = a * y → x = y := by have h1 := inverse a have ⟨ai, a_inv⟩ := h1 have ⟨_, h2⟩ := a_inv intro x y intro h3 calc x = (e : G) * x := Eq.symm (identity x).right _ = ai * a * x := by rw [h2] _ = ai * (a * x) := by rw [assoc] _ = ai * (a * y) := by rw [h3] _ = ai * a * y := by rw [← assoc] _ = (e : G) * y := by rw [h2] _ = y := (identity y).right end GroupTheory /- Variables `G`, `a`, `b`, `c` are now not in scope. -/ /- Let us see a mutually recursive definition. The game of Nim with two heaps. -/ abbrev between (lower what upper : Nat) : Prop := lower ≤ what ∧ what ≤ upper mutual def Alice : Nat → Nat → Prop | n1, n2 => ∃ k, (between 1 k n1 ∧ (between 1 k n1 → Bob (n1-k) n2)) ∨ (between 1 k n2 ∧ (between 1 k n2 → Bob n1 (n2-k))) def Bob : Nat → Nat → Prop | n1, n2 => ∀ k, (between 1 k n1 → Alice (n1-k) n2) ∧ (between 1 k n2 → Alice n1 (n2-k)) end example : Bob 0 0 := by intro k induction k case zero => constructor intro ; contradiction intro ; contradiction case succ => constructor intro a ; have := a.right ; contradiction intro a ; have := a.right ; contradiction /- We have to convince Lean of termination when a function is defined using just a `def`. Here's a simple primality checking algorithm that tests all candidate divisors. -/ def prime' (n : Nat) : Bool := if h : n < 2 then false else @go 2 n (by omega) where go (d : Nat) (n : Nat) {_ : n ≥ d} : Bool := if h : n = d then /- `h` needed for `omega` below. -/ true else if n % d = 0 then false else @go (Nat.succ d) n (by omega) termination_by (n - d) /- We have to specify that the recursive function `go` terminates because `n-k` decreases in each recursive call. This needs the hypothesis `n > k` at the recursive call site. But the function itself can only assume that `n ≥ k`. We label the test `n ≤ k` by `h` so that the falsification of this proposition can be used by `omega` later to conclude that `n > k`. The tactic `omega` can solve simple equalities and inequalities. -/ /- You can also instruct Lean to not check for totality by prefixing `partial` to `def`. -/ /- Or, we can rewrite the function to test the divisors from largest to smallest. In this case, Lean easily verifies that the function is total. -/ def prime (n : Nat) : Bool := if n < 2 then true else go (n-1) n where go d n := if d < 2 then true else if n % d = 0 then false else go (d-1) n /- Now, to Lean, it is obvious that `go` will terminate because `d` decreases in each recursive call. -/ #eval prime 57 #eval prime 97 ``` For further learning, see: * [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/) * [Theorem Proving in Lean 4](https://lean-lang.org/theorem_proving_in_lean4/) * [Lean 4 Manual](https://lean-lang.org/lean4/doc/) ================================================ FILE: less.md ================================================ --- name: Less filename: learnless.less contributors: - ["Saravanan Ganesh", "http://srrvnn.me"] --- Less is a CSS pre-processor, that adds features such as variables, nesting, mixins and more. Less (and other preprocessors, such as [Sass](http://sass-lang.com/)) help developers to write maintainable and DRY (Don't Repeat Yourself) code. ```less //Single line comments are removed when Less is compiled to CSS. /*Multi line comments are preserved. */ /* Variables ==============================*/ /* You can store a CSS value (such as a color) in a variable. Use the '@' symbol to create a variable. */ @primary-color: #a3a4ff; @secondary-color: #51527f; @body-font: 'Roboto', sans-serif; /* You can use the variables throughout your stylesheet. Now if you want to change a color, you only have to make the change once.*/ body { background-color: @primary-color; color: @secondary-color; font-family: @body-font; } /* This would compile to: */ body { background-color: #a3a4ff; color: #51527F; font-family: 'Roboto', sans-serif; } /* This is much more maintainable than having to change the color each time it appears throughout your stylesheet. */ /* Mixins ==============================*/ /* If you find you are writing the same code for more than one element, you might want to reuse that easily.*/ .center { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; } /* You can use the mixin by simply adding the selector as a style */ div { .center; background-color: @primary-color; } /* Which would compile to: */ .center { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; } div { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; background-color: #a3a4ff; } /* You can omit the mixin code from being compiled by adding parenthesis after the selector */ .center() { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; } div { .center; background-color: @primary-color; } /* Which would compile to: */ div { display: block; margin-left: auto; margin-right: auto; left: 0; right: 0; background-color: #a3a4ff; } /* Nesting ==============================*/ /* Less allows you to nest selectors within selectors */ ul { list-style-type: none; margin-top: 2em; li { background-color: #f00; } } /* '&' will be replaced by the parent selector. */ /* You can also nest pseudo-classes. */ /* Keep in mind that over-nesting will make your code less maintainable. Best practices recommend going no more than 3 levels deep when nesting. For example: */ ul { list-style-type: none; margin-top: 2em; li { background-color: red; &:hover { background-color: blue; } a { color: white; } } } /* Compiles to: */ ul { list-style-type: none; margin-top: 2em; } ul li { background-color: red; } ul li:hover { background-color: blue; } ul li a { color: white; } /* Functions ==============================*/ /* Less provides functions that can be used to accomplish a variety of tasks. Consider the following: */ /* Functions can be invoked by using their name and passing in the required arguments. */ body { width: round(10.25px); } .header { background-color: lighten(#000, 0.5); } .footer { background-color: fadeout(#000, 0.25) } /* Compiles to: */ body { width: 10px; } .header { background-color: #010101; } .footer { background-color: rgba(0, 0, 0, 0.75); } /* You may also define your own functions. Functions are very similar to mixins. When trying to choose between a function or a mixin, remember that mixins are best for generating CSS while functions are better for logic that might be used throughout your Less code. The examples in the 'Math Operators' section are ideal candidates for becoming a reusable function. */ /* This function calculates the average of two numbers: */ .average(@x, @y) { @average-result: ((@x + @y) / 2); } div { .average(16px, 50px); // "call" the mixin padding: @average-result; // use its "return" value } /* Compiles to: */ div { padding: 33px; } /*Extend (Inheritance) ==============================*/ /*Extend is a way to share the properties of one selector with another. */ .display { height: 50px; } .display-success { &:extend(.display); border-color: #22df56; } /* Compiles to: */ .display, .display-success { height: 50px; } .display-success { border-color: #22df56; } /* Extending a CSS statement is preferable to creating a mixin because of the way it groups together the classes that all share the same base styling. If this was done with a mixin, the properties would be duplicated for each statement that called the mixin. While it won't affect your workflow, it will add unnecessary bloat to the files created by the Less compiler. */ /*Partials and Imports ==============================*/ /* Less allows you to create partial files. This can help keep your Less code modularized. Partial files conventionally begin with an '_', e.g. _reset.less. and are imported into a main less file that gets compiled into CSS */ /* Consider the following CSS which we'll put in a file called _reset.less */ html, body, ul, ol { margin: 0; padding: 0; } /* Less offers @import which can be used to import partials into a file. This differs from the traditional CSS @import statement which makes another HTTP request to fetch the imported file. Less takes the imported file and combines it with the compiled code. */ @import 'reset'; body { font-size: 16px; font-family: Helvetica, Arial, Sans-serif; } /* Compiles to: */ html, body, ul, ol { margin: 0; padding: 0; } body { font-size: 16px; font-family: Helvetica, Arial, Sans-serif; } /* Math Operations ==============================*/ /* Less provides the following operators: +, -, *, /, and %. These can be useful for calculating values directly in your Less files instead of using values that you've already calculated by hand. Below is an example of a setting up a simple two column design. */ @content-area: 960px; @main-content: 600px; @sidebar-content: 300px; @main-size: @main-content / @content-area * 100%; @sidebar-size: @sidebar-content / @content-area * 100%; @gutter: 100% - (@main-size + @sidebar-size); body { width: 100%; } .main-content { width: @main-size; } .sidebar { width: @sidebar-size; } .gutter { width: @gutter; } /* Compiles to: */ body { width: 100%; } .main-content { width: 62.5%; } .sidebar { width: 31.25%; } .gutter { width: 6.25%; } ``` ## Practice Less If you want to play with Less in your browser, check out: * [Codepen](http://codepen.io/) * [LESS2CSS](http://lesscss.org/less-preview/) ## Compatibility Less can be used in any project as long as you have a program to compile it into CSS. You'll want to verify that the CSS you're using is compatible with your target browsers. [QuirksMode CSS](http://www.quirksmode.org/css/) and [CanIUse](http://caniuse.com) are great resources for checking compatibility. ## Further reading * [Official Documentation](http://lesscss.org/features/) * [Less CSS - Beginner's Guide](http://www.hongkiat.com/blog/less-basic/) ================================================ FILE: lfe.md ================================================ --- name: "Lisp Flavoured Erlang (LFE)" filename: lispflavourederlang.lfe contributors: - ["Pratik Karki", "https://github.com/prertik"] --- Lisp Flavoured Erlang (LFE) is a functional, concurrent, general-purpose programming language and Lisp dialect (Lisp-2) built on top of Core Erlang and the Erlang Virtual Machine (BEAM). LFE can be obtained from [LFE](https://github.com/rvirding/lfe). The classic starting point is the [LFE docs](http://docs.lfe.io). ```lisp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 0. Syntax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; General form. ;; Lisp is comprised of two syntaxes, the ATOM and the S-expression. ;; `forms` are known as grouped S-expressions. 8 ; an atom; it evaluates to itself :ERLANG ;Atom; evaluates to the symbol :ERLANG. t ; another atom which denotes true. (* 2 21) ; an S- expression '(8 :foo t) ;another one ;;; Comments ;; Single line comments start with a semicolon; use two for normal ;; comments, three for section comments, and four fo file-level ;; comments. ;; Block Comment #| comment text |# ;;; Environment ;; LFE is the de-facto standard. ;; Libraries can be used directly from the Erlang ecosystem. Rebar3 is the build tool. ;; LFE is usually developed with a text editor(preferably Emacs) and a REPL ;; (Read Evaluate Print Loop) running at the same time. The REPL ;; allows for interactive exploration of the program as it is "live" ;; in the system. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 1. Literals and Special Syntactic Rules ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Integers 1234 -123 ; Regular decimal notation #b0 #b10101 ; Binary notation #0 #10101 ; Binary notation (alternative form) #o377 #o-111 ; Octal notation #d123456789 #d+123 ; Explicitly decimal notation #xc0ffe 0x-01 ; Hexadecimal notation #2r1010 #8r377 ;Notation with explicit base (up to 36) #\a #$ #\ä #\🐭 ;Character notation (the value is the Unicode code point of the character) #\x1f42d; ;Character notation with the value in hexadecimal ;;; Floating point numbers 1.0 +2.0 -1.5 1.0e10 1.111e-10 ;;; Strings "any text between double quotes where \" and other special characters like \n can be escaped". ; List String "Cat: \x1f639;" ; writing unicode in string for regular font ending with semicolon. #"This is a binary string \n with some \"escaped\" and quoted (\x1f639;) characters" ; Binary strings are just strings but function different in the VM. ; Other ways of writing it are: #B("a"), #"a", and #B(97). ;;; Character escaping \b ; => Backspace \t ; => Tab \n ; => Newline \v ; => Vertical tab \f ; => Form Feed \r ; => Carriage Return \e ; => Escape \s ; => Space \d ; => Delete ;;; Binaries ;; It is used to create binaries with any contents. #B((#"a" binary) (#"b" binary)) ; #"ab" (Evaluated form) ;;; Lists are: () or (foo bar baz) ;;; Tuples are written in: #(value1 value2 ...). Empty tuple #() is also valid. ;;; Maps are written as: #M(key1 value1 key2 value2 ...). Empty map #M() is also valid. ;;; Symbols: Things that cannot be parsed. Eg: foo, Foo, foo-bar, :foo | foo | ; explicit construction of symbol by wrapping vertical bars. ;;; Evaluation ;; #.(... some expression ...). E.g. '#.(+ 1 1) will evaluate the (+ 1 1) while it ;; reads the expression and then be effectively '2. ;; List comprehension in LFE REPL lfe> (list-comp ((<- x '(0 1 2 3))) (trunc (math:pow 3 x))) (1 3 9 27) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 2. Core forms ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; These forms are the same as those found in Common Lisp and Scheme. (quote e) (cons head tail) (car e) (cdr e) (list e ... ) (tuple e ... ) (binary seg ... ) (map key val ...), (map-get m k), (map-set m k v ...), (map-update m k v ...) (lambda (arg ...) ...) (match-lambda ((arg ... ) {{(when e ...)}} ...) ; Matches clauses ... ) (let ((pat {{(when e ...)}} e) ...) ... ) (let-function ((name lambda|match-lambda) ; Only define local ... ) ; functions ... ) (letrec-function ((name lambda|match-lambda) ; Only define local ... ) ; functions ... ) (let-macro ((name lambda-match-lambda) ; Only define local ...) ; macros ...) (progn ... ) (if test true-expr {{false-expr}}) (case e (pat {{(when e ...)}} ...) ... )) (receive (pat {{(when e ...)}} ... ) ... (after timeout ... )) (catch ... ) (try e {{(case ((pat {{(when e ...)}} ... ) ... ))}} {{(catch ; Next must be tuple of length 3! (((tuple type value ignore) {{(when e ...)}} ... ) ... )}} {{(after ... )}}) (funcall func arg ... ) (call mod func arg ... ) - Call to Erlang Mod:Func(Arg, ... ) (define-module name declaration ... ) (extend-module declaration ... ) - Define/extend module and declarations. (define-function name lambda|match-lambda) (define-macro name lambda|match-lambda) - Define functions/macros at top-level. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 3. Macros ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Macros are part of the language and allow you to create abstractions ;; on top of the core language and standard library that move you closer ;; toward being able to directly express the things you want to express. ;; Top-level function (defun name (arg ...) ...) ;; Adding comments in functions (defun name "Toplevel function with pattern-matching arguments" ((argpat ...) ...) ...) ;; Top-level macro (defmacro name (arg ...) ...) (defmacro name arg ...) ;; Top-level macro with pattern matching arguments (defmacro name ((argpat ...) ...) ...) ;; Top-level macro using Scheme inspired syntax-rules format (defsyntax name (pat exp) ...) ;;; Local macros in macro or syntax-rule format (macrolet ((name (arg ... ) ... ) ... ) ... ) (syntaxlet ((name (pat exp) ...) ...) ...) ;; Like CLISP (prog1 ...) (prog2 ...) ;; Erlang LFE module (defmodule name ...) ;; Erlang LFE record (defrecord name ...) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 4. Patterns and Guards ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Using patterns in LFE compared to that of Erlang ;; Erlang ;; LFE ;; {ok, X} (tuple 'ok x) ;; error 'error ;; {yes, [X|Xs]} (tuple 'yes (cons x xs)) ;; <<34,F/float>> (binary 34 (f float)) ;; [P|Ps]=All (= (cons p ps) all) _ ; => is don't care while pattern matching (= pattern1 pattern2) ; => easier, better version of pattern matching ;; Guards ;; Whenever pattern occurs (let, case, receive, lc, etc) it can be followed by an optional ;; guard which has the form (when test ...). (progn gtest ...) ;; => Sequence of guard tests (if gexpr gexpr gexpr) (type-test e) (guard-bif ...) ;; => Guard BIFs, arithmetic, boolean and comparison operators ;;; REPL lfe>(set (tuple len status msg) #(8 ok "Trillian")) #(8 ok "Trillian") lfe>msg "Trillian" ;;; Program illustrating use of Guards (defun right-number? ((x) (when (orelse (== x 42) (== x 276709))) 'true) ((_) 'false)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 5. Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; A simple function using if. (defun max (x y) "The max function." (if (>= x y) x y)) ;; Same function using more clause (defun max "The max function." ((x y) (when (>= x y)) x) ((x y) y)) ;; Same function using similar style but using local functions defined by flet or fletrec (defun foo (x y) "The max function." (flet ((m (a b) "Local comment." (if (>= a b) a b))) (m x y))) ;; LFE being Lisp-2 has separate namespaces for variables and functions ;; Both variables and function/macros are lexically scoped. ;; Variables are bound by lambda, match-lambda and let. ;; Functions are bound by top-level defun, flet and fletrec. ;; Macros are bound by top-level defmacro/defsyntax and by macrolet/syntaxlet. ;; (funcall func arg ...) like CL to call lambdas/match-lambdas ;; (funs) bound to variables are used. ;; separate bindings and special for apply. apply _F (...), apply _F/3 ( a1, a2, a3 ) ;; Cons'ing in function heads (defun sum (l) (sum l 0)) (defun sum (('() total) total) (((cons h t) total) (sum t (+ h total)))) ;; ``cons`` literal instead of constructor form (defun sum (l) (sum l 0)) (defun sum (('() total) total) ((`(,h . ,t) total) (sum t (+ h total)))) ;; Matching records in function heads (defun handle_info (('ping (= (match-state remote-pid 'undefined) state)) (gen_server:cast (self) 'ping) `#(noreply ,state)) (('ping state) `#(noreply ,state))) ;; Receiving Messages (defun universal-server () (receive ((tuple 'become func) (funcall func)))) ;; another way for receiving messages (defun universal-server () (receive (`#(become ,func) (funcall func)))) ;; Composing a complete function for specific tasks (defun compose (f g) (lambda (x) (funcall f (funcall g x)))) (defun check () (let* ((sin-asin (compose #'sin/1 #'asin/1)) (expected (sin (asin 0.5))) (compose-result (funcall sin-asin 0.5))) (io:format "Expected answer: ~p~n" (list expected)) (io:format "Answer with compose: ~p~n" (list compose-result)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 6. Concurrency ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Message passing as done by Erlang's light-weight "processes". (defmodule messenger-back (export (print-result 0) (send-message 2))) (defun print-result () (receive ((tuple pid msg) (io:format "Received message: '~s'~n" (list msg)) (io:format "Sending message to process ~p ...~n" (list pid)) (! pid (tuple msg)) (print-result)))) (defun send-message (calling-pid msg) (let ((spawned-pid (spawn 'messenger-back 'print-result ()))) (! spawned-pid (tuple calling-pid msg)))) ;; Multiple simultaneous HTTP Requests: (defun parse-args (flag) "Given one or more command-line arguments, extract the passed values. For example, if the following was passed via the command line: $ erl -my-flag my-value-1 -my-flag my-value-2 One could then extract it in an LFE program by calling this function: (let ((args (parse-args 'my-flag))) ... ) In this example, the value assigned to the arg variable would be a list containing the values my-value-1 and my-value-2." (let ((`#(ok ,data) (init:get_argument flag))) (lists:merge data))) (defun get-pages () "With no argument, assume 'url parameter was passed via command line." (let ((urls (parse-args 'url))) (get-pages urls))) (defun get-pages (urls) "Start inets and make (potentially many) HTTP requests." (inets:start) (plists:map (lambda (x) (get-page x)) urls)) (defun get-page (url) "Make a single HTTP request." (let* ((method 'get) (headers '()) (request-data `#(,url ,headers)) (http-options ()) (request-options '(#(sync false)))) (httpc:request method request-data http-options request-options) (receive (`#(http #(,request-id #(error ,reason))) (io:format "Error: ~p~n" `(,reason))) (`#(http #(,request-id ,result)) (io:format "Result: ~p~n" `(,result)))))) ``` ## Further Reading * [LFE DOCS](http://docs.lfe.io) * [LFE GitBook](https://lfe.gitbooks.io/reference-guide/index.html) * [LFE Wiki](https://en.wikipedia.org/wiki/LFE_(programming_language)) ## Extra Info * [LFE PDF](http://www.erlang-factory.com/upload/presentations/61/Robertvirding-LispFlavouredErlang.pdf) * [LFE mail](https://groups.google.com/d/msg/lisp-flavoured-erlang/XA5HeLbQQDk/TUHabZCHXB0J) ================================================ FILE: linker.md ================================================ --- category: tool name: Linker script contributors: - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"] translators: - ["Anuj Shah", "https://github.com/ShahAnuj2610"] filename: learn.ld --- **Position counter** - the linker has a special variable "`.`" (dot) always contains the current output position. `ADDR (section)` - returns the absolute address of the specified section. However this section must be defined before using the ADDR function. `ALIGN (exp)` - returns the value of the position counter aligned to the border following the exp expression. `SIZEOF (section)` - returns the size of the section in bytes. `FILL (param)` - defines the fill pattern for the current section. All other unspecified regions within the section are filled with the value indicated in function argument. `KEEP (param)` - used to mark param as fatal. `ENTRY (func)` - defines the function that will be the entry point into the program. ```bash # Determine the entry point to the program ENTRY(Reset_Handler) # Define a variable that contains the address of the top of the stack _estack = 0x20020000; # Define a variable that contains a heap size value _Min_Heap_Size = 0x200; # Define a variable that contains the value of the stack size _Min_Stack_Size = 0x400; # Description of the memory card available for this processor # MEMORY # { # MEMORY_DOMAIN_NAME (access rights) : ORIGIN = START_ADDRESS, LENGTH = SIZE # } # In our example, the controller contains three memory areas: # RAM - starts with the address 0x20000000 and takes 128 KB; # CCMRAM - starts with the address 0x10000000 and occupies 64 KB; # FLASH - starts with the address 0x8000000; takes 1024 Kb; # Moreover, RAM memory access for reading, writing and execution. # CCMRAM memory is read-write only. # FLASH memory is available for reading and execution. MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K } # We describe output sections SECTIONS { # The first section contains a table of interrupt vectors .isr_vector : { # Align the current position to the border of 4 bytes. . = ALIGN(4); # There is an option --gc-sections, which allows you to collect garbage from unused # input sections. And if there are sections that the garbage collector should not touch, # you need to specify them as an argument to the KEEP () function (analogue of the keyword # volatile). # The entry (* (. Isr_vector)) means the .isr_vector sections in all object files. Because # appeal to the section in general terms looks like this: (FILE_NAME (SECTION_NAME)) KEEP(*(.isr_vector)) # Align the current position to the border of 4 bytes. . = ALIGN(4); # The expression "> MEMORY AREA" indicates which area of memory will be placed # this section. In our section, the .isr_vector section will be located in FLASH memory. } >FLASH # TOTAL: The .isr_vector section that contains the table of interrupt vectors is aligned # on the border of 4 bytes, marked as inaccessible to the garbage collector and placed at the beginning # FLASH microcontroller memory. # The second section contains the program code. .text : { # Align the current position to the border of 4 bytes. . = ALIGN(4); # We indicate that in this section the .text areas of all # object files *(.text) *(.text*) # Protect the .init and .fini sections from the garbage collector KEEP (*(.init)) KEEP (*(.fini)) # Align the current position to the border of 4 bytes. . = ALIGN(4); # The variable _etext is defined, which stores the address of the end of the .text section and which # may be available in the source code of the program through the announcement # volaile unsigned int extern _etext; _etext = .; } >FLASH # TOTAL: The .text section that contains the program code is aligned on the border of 4 bytes, # includes: all sections with program code in all object files and protected # from the garbage collector of the .init and .fini sections in all object files, located in FLASH # microcontroller memory immediately after the table of vectors. # The text, .init, and .fini sections. are located in memory in the order in which they # declared in the script. # The third section contains constant data. .rodata : { # Align the current position to the border of 4 bytes. . = ALIGN(4); # We indicate that in this section areas .rodata will be stored # object files *(.rodata) *(.rodata*) # Align the current position to the border of 4 bytes. . = ALIGN(4); } >FLASH # Save the absolute address of the .data section in the _sidata variable _sidata = LOADADDR(.data); # The fourth section contains initialized variables. .data : { # Align the current position to the border of 4 bytes. . = ALIGN(4); # Save the address of the current position (beginning of the section) in the variable _sdata _sdata = .; # We indicate that in this section the .data areas of all # object files *(.data) *(.data*) # Align the current position to the border of 4 bytes. . = ALIGN(4); # Save the address of the current position (end of section) in the variable _sdata _edata = .; # AT function indicates that this sector is stored in one memory area # (in our case, FLASH), and it will be executed from another area of memory (in our case, RAM). # There are two types of addresses: # * VMA (Virtual memory address) - this is the run-time address at which the compiler expects # see data. # * LMA (Load memory address) is the address at which the linker stores data. #Startup must code to copy the .data section from the LMA addresses to the VMA addresses. } >RAM AT> FLASH # The fifth section contains zero-initialized variables. .bss : { # Save the address of the current position (beginning of the section) in the variable _sbss and __bss_start__ _sbss = .; __bss_start__ = _sbss; # We indicate that in this section the .bss areas of all # object files *(.bss) *(.bss*) # Align the current position to the border of 4 bytes. . = ALIGN(4); # Save the address of the current position (beginning of the section) in the variable _ebss and __bss_end__ _ebss = .; __bss_end__ = _ebss; } >RAM # The sixth section contains a bunch and a stack. It is located at the very end of RAM. ._user_heap_stack : { . = ALIGN(4); PROVIDE ( end = . ); PROVIDE ( _end = . ); . = . + _Min_Heap_Size; . = . + _Min_Stack_Size; . = ALIGN(4); } >RAM } ``` ================================================ FILE: lint/encoding.sh ================================================ #!/bin/bash check_encoding() { file="$1" encoding=$(file -b --mime-encoding "$file") # Check if the encoding is neither UTF-8 nor US-ASCII if [[ "$encoding" != "utf-8" && "$encoding" != "us-ascii" ]]; then # Print the file path and encoding echo "Error: $file has encoding $encoding, which is not utf-8 or us-ascii" return 1 fi # Check for UTF-8 BOM if [[ "$encoding" == "utf-8" ]]; then if head -c 3 "$file" | cmp -s <(echo -ne '\xEF\xBB\xBF'); then echo "Error: $file contains a UTF-8 BOM" return 1 fi fi return 0 } export -f check_encoding # Default to current directory if no argument is given directory="${1:-.}" find "$directory" -type f -name "*.md" -print0 | xargs -0 -P 8 -I {} bash -c 'check_encoding "$@"' _ {} ================================================ FILE: lint/frontmatter.py ================================================ #!/usr/bin/env python3 import re from pathlib import Path import yaml import yamllint.config import yamllint.linter def extract_yaml_frontmatter(file_path): """Extracts YAML front matter from a Markdown file.""" with open(file_path, "r", encoding="utf-8") as file: content = file.read() matches = re.match(r"^(---\s*\n.*?\n)---\n", content, re.DOTALL) if matches: return matches.group(1) return None yaml_config = yamllint.config.YamlLintConfig( """{ extends: default, rules: { commas: disable, trailing-spaces: disable, indentation: disable, line-length: disable, empty-lines: disable } }""" ) def lint_yaml(yaml_content): """Lints YAML content using yamllint by sending it to stdin.""" problems = [] for p in yamllint.linter.run(yaml_content, yaml_config): problems.append(f"{p.line}:{p.column} {p.desc} ({p.rule})") return "\n".join(problems) def validate_yaml_keys(yaml_content, allowed_keys): """Validates that the YAML content contains only the specified keys.""" try: data = yaml.safe_load(yaml_content) if not data: return "Empty YAML front matter." extra_keys = set(data.keys()) - set(allowed_keys) if extra_keys: return f"Invalid keys found: {', '.join(extra_keys)}" for key, value_type in allowed_keys.items(): if key in data: if not isinstance(data[key], value_type): return f"Invalid type for key '{key}': expected {value_type.__name__}, got {type(data[key]).__name__}" if isinstance(data[key], list): for item in data[key]: if not isinstance(item, list): return f"Invalid type for item in key '{key}': expected list, got {type(item).__name__}" elif not item: return f"Invalid item in key '{key}': found empty list" elif not isinstance(item[0], str): return f"Invalid type for item[0] in key '{key}': expected str, got {type(item[0]).__name__}" elif len(item) == 2 and not isinstance(item[1], str): return f"Invalid type for item[1] in key '{key}': expected str, got {type(item[1]).__name__}" elif len(item) > 2: return f"Invalid length for item in key '{key}': expected 1 or 2, got {len(item)}" except yaml.YAMLError as e: return f"Error parsing YAML: {e}" return "" def process_files(path): """Processes either a single file or all Markdown files in a directory.""" if path.is_dir(): pathlist = path.rglob("*.md") else: pathlist = [path] has_error = False allowed_keys = { "name": str, "where_x_eq_name": str, "category": str, "filename": str, "contributors": list, "translators": list, } for path in pathlist: yaml_content = extract_yaml_frontmatter(path) if yaml_content: lint_result = lint_yaml(yaml_content) key_validation = validate_yaml_keys(yaml_content, allowed_keys) if lint_result or key_validation: if has_error: # don't prepend newline to first error print() print(path) if lint_result: print(lint_result) if key_validation: print(key_validation) has_error = True return has_error def main(path_input): """Determines if the input is a directory or a file and processes accordingly.""" path = Path(path_input) if not path.exists(): print(f"Error: {path_input} does not exist.") return 1 return process_files(path) if __name__ == "__main__": import sys path_input = sys.argv[1] if len(sys.argv) > 1 else "." has_error = main(path_input) sys.exit(1 if has_error else 0) ================================================ FILE: lint/requirements.txt ================================================ yamllint pyyaml ================================================ FILE: livescript.md ================================================ --- name: LiveScript filename: learnLivescript.ls contributors: - ["Christina Whyte", "http://github.com/kurisuwhyte/"] --- LiveScript is a functional compile-to-JavaScript language which shares most of the underlying semantics with its host language. Nice additions come with currying, function composition, pattern matching and lots of other goodies heavily borrowed from languages like Haskell, F# and Scala. LiveScript is a fork of [Coco](https://github.com/satyr/coco), which is itself a fork of [CoffeeScript](https://coffeescript.org/). ```livescript # Just like its CoffeeScript cousin, LiveScript uses number symbols for # single-line comments. /* Multi-line comments are written C-style. Use them if you want comments to be preserved in the JavaScript output. */ # As far as syntax goes, LiveScript uses indentation to delimit blocks, # rather than curly braces, and whitespace to apply functions, rather # than parenthesis. ######################################################################## ## 1. Basic values ######################################################################## # Lack of value is defined by the keyword `void` instead of `undefined` void # same as `undefined` but safer (can't be overridden) # No valid value is represented by Null. null # The most basic actual value is the logical type: true false # And it has a plethora of aliases that mean the same thing: on; off yes; no # Then you get numbers. These are double-precision floats like in JS. 10 0.4 # Note that the leading `0` is required # For readability, you may use underscores and letter suffixes in a # number, and these will be ignored by the compiler. 12_344km # Strings are immutable sequences of characters, like in JS: "Christina" # apostrophes are okay too! """Multi-line strings are okay too.""" # Sometimes you want to encode a keyword, the backslash notation makes # this easy: \keyword # => 'keyword' # Arrays are ordered collections of values. fruits = * \apple * \orange * \pear # They can be expressed more concisely with square brackets: fruits = [ \apple, \orange, \pear ] # You also get a convenient way to create a list of strings, using # white space to delimit the items. fruits = <[ apple orange pear ]> # You can retrieve an item by their 0-based index: fruits[0] # => "apple" # Objects are a collection of unordered key/value pairs, and a few other # things (more on that later). person = name: "Christina" likes: * "kittens" * "and other cute stuff" # Again, you can express them concisely with curly brackets: person = {name: "Christina", likes: ["kittens", "and other cute stuff"]} # You can retrieve an item by their key: person.name # => "Christina" person["name"] # => "Christina" # Regular expressions use the same syntax as JavaScript: trailing-space = /\s$/ # dashed-words become dashedWords # Except you can do multi-line expressions too! # (comments and whitespace just gets ignored) funRE = // function\s+(.+) # name \s* \((.*)\) \s* # arguments { (.*) } # body // ######################################################################## ## 2. Basic operations ######################################################################## # Arithmetic operators are the same as JavaScript's: 1 + 2 # => 3 2 - 1 # => 1 2 * 3 # => 6 4 / 2 # => 2 3 % 2 # => 1 # Comparisons are mostly the same too, except that `==` is the same as # JS's `===`, where JS's `==` in LiveScript is `~=`, and `===` enables # object and array comparisons, and also stricter comparisons: 2 == 2 # => true 2 == "2" # => false 2 ~= "2" # => true 2 === "2" # => false [1,2,3] == [1,2,3] # => false [1,2,3] === [1,2,3] # => true +0 == -0 # => true +0 === -0 # => false # Other relational operators include <, <=, > and >= # Logical values can be combined through the logical operators `or`, # `and` and `not` true and false # => false false or true # => true not false # => true # Collections also get some nice additional operators [1, 2] ++ [3, 4] # => [1, 2, 3, 4] 'a' in <[ a b c ]> # => true 'name' of { name: 'Chris' } # => true ######################################################################## ## 3. Functions ######################################################################## # Since LiveScript is functional, you'd expect functions to get a nice # treatment. In LiveScript it's even more apparent that functions are # first class: add = (left, right) -> left + right add 1, 2 # => 3 # Functions which take no arguments are called with a bang! two = -> 2 two! # LiveScript uses function scope, just like JavaScript, and has proper # closures too. Unlike JavaScript, the `=` works as a declaration # operator, and will always declare the variable on the left hand side. # The `:=` operator is available to *reuse* a name from the parent # scope. # You can destructure arguments of a function to quickly get to # interesting values inside a complex data structure: tail = ([head, ...rest]) -> rest tail [1, 2, 3] # => [2, 3] # You can also transform the arguments using binary or unary # operators. Default arguments are also possible. foo = (a = 1, b = 2) -> a + b foo! # => 3 # You could use it to clone a particular argument to avoid side-effects, # for example: copy = (^^target, source) -> for k,v of source => target[k] = v target a = { a: 1 } copy a, { b: 2 } # => { a: 1, b: 2 } a # => { a: 1 } # A function may be curried by using a long arrow rather than a short # one: add = (left, right) --> left + right add1 = add 1 add1 2 # => 3 # Functions get an implicit `it` argument, even if you don't declare # any. identity = -> it identity 1 # => 1 # Operators are not functions in LiveScript, but you can easily turn # them into one! Enter the operator sectioning: divide-by-two = (/ 2) [2, 4, 8, 16].map(divide-by-two) .reduce (+) # Not only of function application lives LiveScript, as in any good # functional language you get facilities for composing them: double-minus-one = (- 1) . (* 2) # Other than the usual `f . g` mathematical formulae, you get the `>>` # and `<<` operators, that describe how the flow of values through the # functions. double-minus-one = (* 2) >> (- 1) double-minus-one = (- 1) << (* 2) # And talking about flow of value, LiveScript gets the `|>` and `<|` # operators that apply a value to a function: map = (f, xs) --> xs.map f [1 2 3] |> map (* 2) # => [2 4 6] # You can also choose where you want the value to be placed, just mark # the place with an underscore (_): reduce = (f, xs, initial) --> xs.reduce f, initial [1 2 3] |> reduce (+), _, 0 # => 6 # The underscore is also used in regular partial application, which you # can use for any function: div = (left, right) -> left / right div-by-two = div _, 2 div-by-two 4 # => 2 # Last, but not least, LiveScript has back-calls, which might help # with some callback-based code (though you should try more functional # approaches, like Promises): readFile = (name, f) -> f name a <- readFile 'foo' b <- readFile 'bar' console.log a + b # Same as: readFile 'foo', (a) -> readFile 'bar', (b) -> console.log a + b ######################################################################## ## 4. Patterns, guards and control-flow ######################################################################## # You can branch computations with the `if...else` expression: x = if n > 0 then \positive else \negative # Instead of `then`, you can use `=>` x = if n > 0 => \positive else \negative # Complex conditions are better-off expressed with the `switch` # expression, though: y = {} x = switch | (typeof y) is \number => \number | (typeof y) is \string => \string | 'length' of y => \array | otherwise => \object # `otherwise` and `_` always matches. # Function bodies, declarations and assignments get a free `switch`, so # you don't need to type it again: take = (n, [x, ...xs]) --> | n == 0 => [] | _ => [x] ++ take (n - 1), xs ######################################################################## ## 5. Comprehensions ######################################################################## # While the functional helpers for dealing with lists and objects are # right there in the JavaScript's standard library (and complemented on # the prelude-ls, which is a "standard library" for LiveScript), # comprehensions will usually allow you to do this stuff faster and with # a nice syntax: oneToTwenty = [1 to 20] evens = [x for x in oneToTwenty when x % 2 == 0] # `when` and `unless` can be used as filters in the comprehension. # Object comprehension works in the same way, except that it gives you # back an object rather than an Array: copy = { [k, v] for k, v of source } ######################################################################## ## 4. OOP ######################################################################## # While LiveScript is a functional language in most aspects, it also has # some niceties for imperative and object oriented programming. One of # them is class syntax and some class sugar inherited from CoffeeScript: class Animal (@name, kind) -> @kind = kind action: (what) -> "*#{@name} (a #{@kind}) #{what}*" class Cat extends Animal (@name) -> super @name, 'cat' purr: -> @action 'purrs' kitten = new Cat 'Mei' kitten.purr! # => "*Mei (a cat) purrs*" # Besides the classical single-inheritance pattern, you can also provide # as many mixins as you would like for a class. Mixins are just plain # objects: Huggable = hug: -> @action 'is hugged' class SnugglyCat extends Cat implements Huggable kitten = new SnugglyCat 'Purr' kitten.hug! # => "*Mei (a cat) is hugged*" ``` ## Further reading There's just so much more to LiveScript, but this should be enough to get you started writing little functional things in it. The [official website](http://livescript.net/) has a lot of information on the language, and a nice online compiler for you to try stuff out! You may also want to grab yourself some [prelude.ls](http://gkz.github.io/prelude-ls/), and check out the `#livescript` channel on the Freenode network. ================================================ FILE: logtalk.md ================================================ --- name: Logtalk filename: learnlogtalk.lgt contributors: - ["Paulo Moura", "http://github.com/pmoura"] --- Logtalk is an object-oriented logic programming language that extends and leverages Prolog with modern code encapsulation and code reuse mechanisms without compromising its declarative programming features. Logtalk is implemented in highly portable code and can use most modern and standards compliant Prolog implementations as a back-end compiler. To keep its size reasonable, this tutorial necessarily assumes that the reader have a working knowledge of Prolog and is biased towards describing Logtalk object-oriented features. # Syntax Logtalk uses standard Prolog syntax with the addition of a few operators and directives for a smooth learning curve and wide portability. One important consequence is that Prolog code can be easily encapsulated in objects with little or no changes. Moreover, Logtalk can transparently interpret most Prolog modules as Logtalk objects. The main operators are: * `::/2` - sending a message to an object * `::/1` - sending a message to _self_ (i.e. to the object that received the message being processed) * `^^/1` - _super_ call (of an inherited or imported predicate) Some of the most important entity and predicate directives will be introduced in the next sections. # Entities and roles Logtalk provides _objects_, _protocols_, and _categories_ as first-class entities. Relations between entities define _patterns of code reuse_ and the _roles_ played by the entities. For example, when an object _instantiates_ another object, the first object plays the role of an instance and the second object plays the role of a class. An _extends_ relation between two objects implies that both objects play the role of prototypes, with one of them extending the other, its parent prototype. # Defining an object An object encapsulates predicate declarations and definitions. Objects can be created dynamically but are usually static and defined in source files. A single source file can contain any number of entity definitions. A simple object, defining a list member public predicate: ```logtalk :- object(list). :- public(member/2). member(Head, [Head| _]). member(Head, [_| Tail]) :- member(Head, Tail). :- end_object. ``` # Compiling and loading source files Assuming that the code above for the `list` object is saved in a `list.lgt` file, it can be compiled and loaded using the `logtalk_load/1` built-in predicate or its abbreviation, `{}/1`, with the file path as argument (the extension can be omitted): ```logtalk ?- {list}. yes ``` In general, entities may have dependencies on entities defined in other source files (e.g. library entities). To load a file and all its dependencies, the advised solution is to define a _loader_ file that loads all the necessary files for an application. A loader file is simply a source file, typically named `loader.lgt`, that makes calls to the `logtalk_load/1-2` built-in predicates, usually from an `initialization/1` directive for portability and standards compliance. Loader files are provided for all libraries, tools, and examples. # Sending a message to an object The `::/2` infix operator is used to send a message to an object. As in Prolog, we can backtrack for alternative solutions: ```logtalk ?- list::member(X, [1,2,3]). X = 1 ; X = 2 ; X = 3 yes ``` Encapsulation is enforced. A predicate can be declared _public_, _protected_, or _private_. It can also be _local_ when there is no scope directive for it. For example: ```logtalk :- object(scopes). :- private(bar/0). bar. local. :- end_object. ``` Assuming the object is saved in a `scopes.lgt` file: ```logtalk ?- {scopes}. yes ?- catch(scopes::bar, Error, true). Error = error( permission_error(access, private_predicate, bar/0), logtalk(scopes::bar, user) ) yes ?- catch(scopes::local, Error, true). Error = error( existence_error(predicate_declaration, local/0), logtalk(scopes::local, user) ) yes ``` When the predicate in a message is unknown for the object (the role it plays determines the lookup procedures), we also get an error. For example: ```logtalk ?- catch(scopes::unknown, Error, true). Error = error( existence_error(predicate_declaration, unknown/0), logtalk(scopes::unknown, user) ) yes ``` A subtle point is that predicate scope directives specify predicate _calling_ semantics, not _definition_ semantics. For example, if an object playing the role of a class declares a predicate private, the predicate can be defined in subclasses and instances *but* can only be called in its instances _from_ the class. # Defining and implementing a protocol Protocols contain predicate declarations that can be implemented by any number of objects and categories: ```logtalk :- protocol(listp). :- public(member/2). :- end_protocol. :- object(list, implements(listp)). member(Head, [Head| _]). member(Head, [_| Tail]) :- member(Head, Tail). :- end_object. ``` The scope of the protocol predicates can be restricted using protected or private implementation. For example: ```logtalk :- object(stack, implements(private::listp)). :- end_object. ``` In fact, all entity relations (in an entity opening directive) can be qualified as public (the default), protected, or private. # Prototypes An object without an _instantiation_ or _specialization_ relation with another object plays the role of a prototype. A prototype can _extend_ another object, its parent prototype. ```logtalk % clyde, our prototypical elephant :- object(clyde). :- public(color/1). color(grey). :- public(number_of_legs/1). number_of_legs(4). :- end_object. % fred, another elephant, is like clyde, except that he's white :- object(fred, extends(clyde)). color(white). :- end_object. ``` When answering a message sent to an object playing the role of a prototype, we validate the message and look for an answer first in the prototype itself and, if not found, we delegate to the prototype parents if any: ```logtalk ?- fred::number_of_legs(N). N = 4 yes ?- fred::color(C). C = white yes ``` A message is valid if the corresponding predicate is declared (and the sender is within scope) but it will fail, rather then throwing an error, if the predicate is not defined. This is called the _closed-world assumption_. For example, consider the following object, saved in a `foo.lgt` file: ```logtalk :- object(foo). :- public(bar/0). :- end_object. ``` Loading the file and trying to call the `bar/0` predicate fails as expected. Note that this is different from calling an _unknown_ predicate, which results in an error: ```logtalk ?- {foo}. yes ?- foo::bar. no ?- catch(foo::baz, Error, true). Error = error( existence_error(predicate_declaration, baz/0), logtalk(foo::baz, user) ) yes ``` # Classes and instances In order to define objects playing the role of classes and/or instances, an object must have at least an instantiation or a specialization relation with another object. Objects playing the role of meta-classes can be used when we need to see a class also as an instance. We use the following example to also illustrate how to dynamically create new objects at runtime: ```logtalk % a simple, generic, metaclass defining a new/2 predicate for its instances :- object(metaclass, instantiates(metaclass)). :- public(new/2). new(Instance, Clauses) :- self(Class), create_object(Instance, [instantiates(Class)], [], Clauses). :- end_object. % a simple class defining age/1 and name/1 predicate for its instances :- object(person, instantiates(metaclass)). :- public([ age/1, name/1 ]). % a default value for age/1 age(42). :- end_object. % a static instance of the class person :- object(john, instantiates(person)). name(john). age(12). :- end_object. ``` When answering a message sent to an object playing the role of an instance, we validate the message by starting in its class and going up to its class superclasses if necessary. Assuming that the message is valid, then we look for an answer starting in the instance itself: ```logtalk ?- person::new(Instance, [name(paulo)]). Instance = o1 yes ?- o1::name(Name). Name = paulo yes ?- o1::age(Age). Age = 42 yes ?- john::age(Age). Age = 12 yes ``` # Categories A category is a fine grained unit of code reuse, used to encapsulate a _cohesive_ set of predicate declarations and definitions, implementing a _single_ functionality, that can be imported into any object. A category can thus be seen as the dual concept of a protocol. In the following example, we define categories representing car engines and then import them into car objects: ```logtalk % a protocol describing engine characteristics :- protocol(carenginep). :- public([ reference/1, capacity/1, cylinders/1, horsepower_rpm/2, bore_stroke/2, fuel/1 ]). :- end_protocol. % a typical engine defined as a category :- category(classic, implements(carenginep)). reference('M180.940'). capacity(2195). cylinders(6). horsepower_rpm(94, 4800). bore_stroke(80, 72.8). fuel(gasoline). :- end_category. % a souped up version of the previous engine :- category(sport, extends(classic)). reference('M180.941'). horsepower_rpm(HP, RPM) :- ^^horsepower_rpm(ClassicHP, ClassicRPM), % "super" call HP is truncate(ClassicHP*1.23), RPM is truncate(ClassicRPM*0.762). :- end_category. % with engines (and other components), we may start "assembling" some cars :- object(sedan, imports(classic)). :- end_object. :- object(coupe, imports(sport)). :- end_object. ``` Categories are independently compiled and thus allow importing objects to be updated by simple updating the imported categories without requiring object recompilation. Categories also provide _runtime transparency_. I.e. the category protocol adds to the protocol of the objects importing the category: ```logtalk ?- sedan::current_predicate(Predicate). Predicate = reference/1 ; Predicate = capacity/1 ; Predicate = cylinders/1 ; Predicate = horsepower_rpm/2 ; Predicate = bore_stroke/2 ; Predicate = fuel/1 yes ``` # Hot patching Categories can be also be used for hot-patching objects. A category can add new predicates to an object and/or replace object predicate definitions. For example, consider the following object: ```logtalk :- object(buggy). :- public(p/0). p :- write(foo). :- end_object. ``` Assume that the object prints the wrong string when sent the message `p/0`: ```logtalk ?- {buggy}. yes ?- buggy::p. foo yes ``` If the object source code is not available and we need to fix an application running the object code, we can simply define a category that fixes the buggy predicate: ```logtalk :- category(patch, complements(buggy)). % fixed p/0 def p :- write(bar). :- end_category. ``` After compiling and loading the category into the running application we will now get: ```logtalk ?- set_logtalk_flag(complements, allow). yes ?- {patch}. yes ?- buggy::p. bar yes ``` As hot-patching forcefully breaks encapsulation, the `complements` compiler flag can be set (globally or on a per-object basis) to allow, restrict, or prevent it. # Parametric objects and categories Objects and categories can be parameterized by using as identifier a compound term instead of an atom. Object and category parameters are _logical variables_ shared with all encapsulated predicates. An example with geometric circles: ```logtalk :- object(circle(_Radius, _Color)). :- public([ area/1, perimeter/1 ]). area(Area) :- parameter(1, Radius), Area is pi*Radius*Radius. perimeter(Perimeter) :- parameter(1, Radius), Perimeter is 2*pi*Radius. :- end_object. ``` Parametric objects are used just as any other object, usually providing values for the parameters when sending a message: ```logtalk ?- circle(1.23, blue)::area(Area). Area = 4.75291 yes ``` Parametric objects also provide a simple way of associating a set of predicates with a plain Prolog predicate. Prolog facts can be interpreted as _parametric object proxies_ when they have the same functor and arity as the identifiers of parametric objects. Handy syntax is provided to for working with proxies. For example, assuming the following clauses for a `circle/2` predicate: ```logtalk circle(1.23, blue). circle(3.71, yellow). circle(0.39, green). circle(5.74, black). circle(8.32, cyan). ``` With these clauses loaded, we can easily compute for example a list with the areas of all the circles: ```logtalk ?- findall(Area, {circle(_, _)}::area(Area), Areas). Areas = [4.75291, 43.2412, 0.477836, 103.508, 217.468] yes ``` The `{Goal}::Message` construct proves `Goal`, possibly instantiating any variables in it, and sends `Message` to the resulting term. # Events and monitors Logtalk supports _event-driven programming_ by allowing defining events and monitors for those events. An event is simply the sending of a message to an object. Interpreting message sending as an atomic activity, a _before_ event and an _after_ event are recognized. Event monitors define event handler predicates, `before/3` and `after/3`, and can query, register, and delete a system-wide event registry that associates events with monitors. For example, a simple tracer for any message being sent using the `::/2` control construct can be defined as: ```logtalk :- object(tracer, implements(monitoring)). % built-in protocol for event handlers :- initialization(define_events(_, _, _, _, tracer)). before(Object, Message, Sender) :- write('call: '), writeq(Object), write(' <-- '), writeq(Message), write(' from '), writeq(Sender), nl. after(Object, Message, Sender) :- write('exit: '), writeq(Object), write(' <-- '), writeq(Message), write(' from '), writeq(Sender), nl. :- end_object. ``` Assuming that the `tracer` object and the `list` object defined earlier are compiled and loaded, we can observe the event handlers in action by sending a message: ```logtalk ?- set_logtalk_flag(events, allow). yes ?- list::member(X, [1,2,3]). call: list <-- member(X, [1,2,3]) from user exit: list <-- member(1, [1,2,3]) from user X = 1 ; exit: list <-- member(2, [1,2,3]) from user X = 2 ; exit: list <-- member(3, [1,2,3]) from user X = 3 yes ``` Events can be set and deleted dynamically at runtime by calling the `define_events/5` and `abolish_events/5` built-in predicates. Event-driven programming can be seen as a form of _computational reflection_. But note that events are only generated when using the `::/2` message-sending control construct. # Lambda expressions Logtalk supports lambda expressions. Lambda parameters are represented using a list with the `(>>)/2` infix operator connecting them to the lambda. Some simple examples using library `meta`: ```logtalk ?- {meta(loader)}. yes ?- meta::map([X,Y]>>(Y is 2*X), [1,2,3], Ys). Ys = [2,4,6] yes ``` Currying is also supported: ```logtalk ?- meta::map([X]>>([Y]>>(Y is 2*X)), [1,2,3], Ys). Ys = [2,4,6] yes ``` Lambda free variables can be expressed using the extended syntax `{Free1, ...}/[Parameter1, ...]>>Lambda`. # Macros Terms and goals in source files can be _expanded_ at compile time by specifying a _hook object_ that defines term-expansion and goal-expansion rules. For example, consider the following simple object, saved in a `source.lgt` file: ```logtalk :- object(source). :- public(bar/1). bar(X) :- foo(X). foo(a). foo(b). foo(c). :- end_object. ``` Assume the following hook object, saved in a `my_macros.lgt` file, that expands clauses and calls to the `foo/1` local predicate: ```logtalk :- object(my_macros, implements(expanding)). % built-in protocol for expanding predicates term_expansion(foo(Char), baz(Code)) :- char_code(Char, Code). % standard built-in predicate goal_expansion(foo(X), baz(X)). :- end_object. ``` After loading the macros file, we can then expand our source file with it using the `hook` compiler flag: ```logtalk ?- logtalk_load(my_macros), logtalk_load(source, [hook(my_macros)]). yes ?- source::bar(X). X = 97 ; X = 98 ; X = 99 true ``` The Logtalk library provides support for combining hook objects using different workflows (for example, defining a pipeline of expansions). # Further information Visit the [Logtalk website](http://logtalk.org) for more information. ================================================ FILE: lolcode.md ================================================ --- name: LOLCODE filename: learnLOLCODE.lol contributors: - ["abactel", "https://github.com/abactel"] --- LOLCODE is an esoteric programming language designed to resemble the speech of [lolcats](https://upload.wikimedia.org/wikipedia/commons/a/ab/Lolcat_in_folder.jpg?1493656347257). ``` BTW This is an inline comment BTW All code must begin with `HAI ` and end with `KTHXBYE` HAI 1.3 CAN HAS STDIO? BTW Importing standard headers OBTW ========================================================================== ================================= BASICS ================================= ========================================================================== TLDR BTW Displaying text: VISIBLE "HELLO WORLD" BTW Declaring variables: I HAS A MESSAGE ITZ "CATZ ARE GOOD" VISIBLE MESSAGE OBTW (This is a codeblock.) Variables are dynamically typed so you don't need to declare their type. A variable's type matches its content. These are the types: TLDR I HAS A STRING ITZ "DOGZ ARE GOOOD" BTW type is YARN I HAS A INTEGER ITZ 42 BTW type is NUMBR I HAS A FLOAT ITZ 3.1415 BTW type is NUMBAR I HAS A BOOLEAN ITZ WIN BTW type is TROOF I HAS A UNTYPED BTW type is NOOB BTW Accepting user input: I HAS A AGE GIMMEH AGE BTW The variable is stored as a YARN. To convert it into NUMBR: AGE IS NOW A NUMBR OBTW ========================================================================== ================================== MATH ================================== ========================================================================== TLDR BTW LOLCODE uses polish notation style math. BTW Basic mathematical notation: SUM OF 21 AN 33 BTW 21 + 33 DIFF OF 90 AN 10 BTW 90 - 10 PRODUKT OF 12 AN 13 BTW 12 * 13 QUOSHUNT OF 32 AN 43 BTW 32 / 43 MOD OF 43 AN 64 BTW 43 modulo 64 BIGGR OF 23 AN 53 BTW max(23, 53) SMALLR OF 53 AN 45 BTW min(53, 45) BTW Binary notation: BOTH OF WIN AN WIN BTW and: WIN if x=WIN, y=WIN EITHER OF FAIL AN WIN BTW or: FAIL if x=FAIL, y=FAIL WON OF WIN AN FAIL BTW xor: FAIL if x=y NOT FAIL BTW unary negation: WIN if x=FAIL ALL OF WIN AN WIN MKAY BTW infinite arity AND ANY OF WIN AN FAIL MKAY BTW infinite arity OR BTW Comparison: BOTH SAEM "CAT" AN "DOG" BTW WIN if x == y DIFFRINT 732 AN 184 BTW WIN if x != y BOTH SAEM 12 AN BIGGR OF 12 AN 4 BTW x >= y BOTH SAEM 43 AN SMALLR OF 43 AN 56 BTW x <= y DIFFRINT 64 AN SMALLR OF 64 AN 2 BTW x > y DIFFRINT 75 AN BIGGR OF 75 AN 643 BTW x < y OBTW ========================================================================== ============================== FLOW CONTROL ============================== ========================================================================== TLDR BTW If/then statement: I HAS A ANIMAL GIMMEH ANIMAL BOTH SAEM ANIMAL AN "CAT", O RLY? YA RLY VISIBLE "YOU HAV A CAT" MEBBE BOTH SAEM ANIMAL AN "MAUS" VISIBLE "NOM NOM NOM. I EATED IT." NO WAI VISIBLE "AHHH IS A WOOF WOOF" OIC BTW Case statement: I HAS A COLOR GIMMEH COLOR COLOR, WTF? OMG "R" VISIBLE "RED FISH" GTFO OMG "Y" VISIBLE "YELLOW FISH" BTW Since there is no `GTFO` the next statements will also be tested OMG "G" OMG "B" VISIBLE "FISH HAS A FLAVOR" GTFO OMGWTF VISIBLE "FISH IS TRANSPARENT OHNO WAT" OIC BTW For loop: I HAS A TEMPERATURE GIMMEH TEMPERATURE TEMPERATURE IS NOW A NUMBR IM IN YR LOOP UPPIN YR ITERATOR TIL BOTH SAEM ITERATOR AN TEMPERATURE VISIBLE ITERATOR IM OUTTA YR LOOP BTW While loop: IM IN YR LOOP NERFIN YR ITERATOR WILE DIFFRINT ITERATOR AN -10 VISIBLE ITERATOR IM OUTTA YR LOOP OBTW ========================================================================= ================================ Strings ================================ ========================================================================= TLDR BTW Linebreaks: VISIBLE "FIRST LINE :) SECOND LINE" BTW Tabs: VISIBLE ":>SPACES ARE SUPERIOR" BTW Bell (goes beep): VISIBLE "NXT CUSTOMER PLS :o" BTW Literal double quote: VISIBLE "HE SAID :"I LIKE CAKE:"" BTW Literal colon: VISIBLE "WHERE I LIVE:: CYBERSPACE" OBTW ========================================================================= =============================== FUNCTIONS =============================== ========================================================================= TLDR BTW Declaring a new function: HOW IZ I SELECTMOVE YR MOVE BTW `MOVE` is an argument BOTH SAEM MOVE AN "ROCK", O RLY? YA RLY VISIBLE "YOU HAV A ROCK" NO WAI VISIBLE "OH NO IS A SNIP-SNIP" OIC GTFO BTW This returns NOOB IF U SAY SO BTW Declaring a function and returning a value: HOW IZ I IZYELLOW FOUND YR "YELLOW" IF U SAY SO BTW Calling a function: I IZ IZYELLOW MKAY KTHXBYE ``` ## Further reading: - [LCI compiler](https://github.com/justinmeza/lci) - [Official spec](https://github.com/justinmeza/lolcode-spec/blob/master/v1.2/lolcode-spec-v1.2.md) ================================================ FILE: lt/json.md ================================================ --- contributors: - ["Zygimantus", "https://github.com/zygimantus"] --- JSON („džeisonas“) yra itin paprastas duomenų mainų formatas, todėl tai bus pati lengviausia „Learn X in Y Minutes“ pamoka. JSON savo gryniausioje formoje neturi jokių komentarų, tačiau dauguma analizatorių priimtų C stiliaus komentarus (`//`, `/* */`). Kai kurie analizatoriai taip pat toleruoja gale esantį kablelį, pvz., kablelis po kiekvieno masyvo paskutinio elemento arba po paskutinio objekto lauko, tačiau jų reikėtų vengti dėl geresnio suderinamumo. JSON reikšmė privalo būti skaičius, eilutė, masyvas, objektas arba viena reikšmė iš šių: true, false, null. Palaikančios naršyklės yra: Firefox 3.5+, Internet Explorer 8.0+, Chrome 1.0+, Opera 10.0+, and Safari 4.0+. Failo plėtinys JSON failams yra „.json“, o MIME tipas yra „application/json“. Dauguma programavimo kalbų palaiko JSON duomenų serializaciją (kodavimą) ir deserializaciją (dekodavimą) į natyviasias duomenų struktūras. JavaScript turi visišką JSON teksto kaip duomenų manipuliavimo palaikymą. Daugiau informacijos galima rasti [json.org](http://www.json.org/) JSON yra pastatytas iš dviejų struktūrų: * Vardų/reikšmių porų rinkinys. Daugomoje kalbų, tai yra realizuojama kaip objektas, įrašas, struktūra, žodynas, hash lentelė, sąrašas su raktais arba asociatyvusis masyvas. * Rūšiuotas reikšmių sąrašas. Daugumoje kalbų, toks sąrašas yra realizuojama kaip masyvas, vektorius, sąrašas arba seka. Objektas su įvairiomis vardo/reikšmės poromis. ```json { "raktas": "reikšmė", "raktai": "privalo visada būti uždaryti dvigubomis kabutėmis", "skaičiai": 0, "eilutės": "Labas, pasauli. Visas unikodas yra leidžiamas, kartu su \"vengimu\".", "turi logiką?": true, "niekas": null, "didelis skaičius": 1.2e+100, "objektai": { "komentaras": "Dauguma tavo struktūrų ateis iš objektų.", "masyvas": [0, 1, 2, 3, "Masyvas gali turėti bet ką savyje.", 5], "kitas objektas": { "komentaras": "Šie dalykai gali būti įdedami naudingai." } }, "kvailumas": [ { "kalio šaltiniai": ["bananai"] }, [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, "neo"], [0, 0, 0, 1] ] ], "alternativus stilius": { "komentaras": "tik pažiūrėk!" , "kablelio padėti": "nesvarbi - kol jis prieš kitą raktą, tada teisingas" , "kitas komentaras": "kaip gražu" } } ``` Paprastas reikšmių masyvas pats savaime yra galiojantis JSON. ```json [1, 2, 3, "tekstas", true] ``` Objektai taip pat gali būti masyvų dalis. ```json [{"vardas": "Jonas", "amžius": 25}, {"vardas": "Eglė", "amžius": 29}, {"vardas": "Petras", "amžius": 31}] ``` ================================================ FILE: lt/tmux.md ================================================ --- contributors: - ["mdln", "https://github.com/mdln"] translators: - ["Zygimantus", "https://github.com/zygimantus"] --- [tmux](http://tmux.sourceforge.net) yra terminalo daugintuvas: jis leidžia vienu metu sukurti, turėti ir valdyti kelis terminalus viename ekrane. tmux gali būti atjungtas nuo ekrano ir veikti fone, o vėliau gali būti vėl prijungtas. ``` tmux [komanda] # Vykdyti komandą # 'tmux' be komandų sukurs naują sesiją new # Sukurti naują sesiją -s "Session" # Sukurti pavadintą sesiją -n "Window" # Sukurti pavadintą langą -c "/dir" # Pradėti nurodytoje direktorijoje attach # Priskirti paskutinę/prienamą sesiją -t "#" # Priskirti nurodytą sesiją -d # Atjungti sesiją nuo kitų langų ls # Aktyvių sesijų sąrašas -a # Visų aktyvių sesijų sąrašas lsw # Langų sąrašas -a # Visų langų sąrašas -s # Visų langų sesijoje sąrašas lsp # Skydelių sąrašas -a # Visų skydelių sąrašas -s # Visų skydelių sesijoje sąrašas -t # Visų skydelių taikinyje sąrašas kill-window # Užbaigti dabartinį langą -t "#" # Užbaigti nurodytą langą -a # Užbaigti visus langus -a -t "#" # Užbaigti visus langus, bet ne taikinį kill-session # Užbaigti dabartinę sesiją -t "#" # Užbaigti nurodytą sesiją -a # Užbaigti visas sesijas -a -t "#" # Užbaigti visas sesijas, bet ne taikinį ``` ### Klavišai Priskirta tmux sesija yra valdoma klavišų kompinacijomis. ``` ---------------------------------------------------------------------- (C-b) = Ctrl + b # Kombinacija reikalinga norint naudoti klavišus (M-1) = Meta + 1 -or- Alt + 1 ---------------------------------------------------------------------- ? # Rodo visų klavišų kombinacijų sąrašą : # Įjungiama tmux komandinė eilutė r # Priverstinai perpiešiamas prijungtas klientas c # Sukurti naują langą ! # Iškelia esamą skydelį iš lango. % # Perskelia esamą skydelį į du, kairįjį ir dešinį " # Perskelia esamą skydelį į du, viršutinį ir apatinį n # Pakeičia į kitą langą p # Pakeičia į buvusį langą { # Apkeičia dabartinį skydėlį su buvusiu } # Apkeičia dabartinį skydėlį su sekančiu s # Pasirinkti naują sesiją prijungtam klientui interaktyviai w # Pasirinkti dabartinį langą interaktyviai 0 to 9 # Pasirinkti langą nuo 0 iki 9 d # Atjungti dabartinį klientą D # Pasirinkti klientą, kurį atjungti & # Užbaigti dabartinį langą x # Užbaigti dabartinį skydelį Up, Down # Pakeisti į skydelį viršuje, apačioje, kairėje arba dešinėje Left, Right M-1 to M-5 # Rikiuoti skydelius: # 1) even-horizontal # 2) even-vertical # 3) main-horizontal # 4) main-vertical # 5) tiled C-Up, C-Down # Keisti esamo skydelio dydį vienos ląstelės žingsniu C-Left, C-Right M-Up, M-Down # Keisti esamo skydelio dydį penkių ląstelių žingsniu M-Left, M-Right ``` ### Configuring ~/.tmux.conf tmux.conf gali būti nustatytas automatiškai paleidimo metu, panašiai kaip ir .vimrc arba init.el. ``` # Pavyzdys tmux.conf # 2014.10 ### General ########################################################################### # Enable UTF-8 setw -g utf8 on set-option -g status-utf8 on # Scrollback/History limit set -g history-limit 2048 # Index Start set -g base-index 1 # Mouse set-option -g mouse-select-pane on # Force reload of config file unbind r bind r source-file ~/.tmux.conf ### Keybinds ########################################################################### # Unbind C-b as the default prefix unbind C-b # Set new default prefix set-option -g prefix ` # Return to previous window when prefix is pressed twice bind C-a last-window bind ` last-window # Allow swapping C-a and ` using F11/F12 bind F11 set-option -g prefix C-a bind F12 set-option -g prefix ` # Keybind preference setw -g mode-keys vi set-option -g status-keys vi # Moving between panes with vim movement keys bind h select-pane -L bind j select-pane -D bind k select-pane -U bind l select-pane -R # Window Cycle/Swap bind e previous-window bind f next-window bind E swap-window -t -1 bind F swap-window -t +1 # Easy split pane commands bind = split-window -h bind - split-window -v unbind '"' unbind % # Activate inner-most session (when nesting tmux) to send commands bind a send-prefix ### Theme ########################################################################### # Statusbar Color Palatte set-option -g status-justify left set-option -g status-bg black set-option -g status-fg white set-option -g status-left-length 40 set-option -g status-right-length 80 # Pane Border Color Palette set-option -g pane-active-border-fg green set-option -g pane-active-border-bg black set-option -g pane-border-fg white set-option -g pane-border-bg black # Message Color Palette set-option -g message-fg black set-option -g message-bg green # Window Status Color Palette setw -g window-status-bg black setw -g window-status-current-fg green setw -g window-status-bell-attr default setw -g window-status-bell-fg red setw -g window-status-content-attr default setw -g window-status-content-fg yellow setw -g window-status-activity-attr default setw -g window-status-activity-fg yellow ### UI ########################################################################### # Notification setw -g monitor-activity on set -g visual-activity on set-option -g bell-action any set-option -g visual-bell off # Automatically set window titles set-option -g set-titles on set-option -g set-titles-string '#H:#S.#I.#P #W #T' # window number,program name,active (or not) # Statusbar Adjustments set -g status-left "#[fg=red] #H#[fg=green]:#[fg=white]#S#[fg=green] |#[default]" # Show performance counters in statusbar # Requires https://github.com/thewtex/tmux-mem-cpu-load/ set -g status-interval 4 set -g status-right "#[fg=green] | #[fg=white]#(tmux-mem-cpu-load)#[fg=green] | #[fg=cyan]%H:%M #[default]" ``` ### Šaltiniai [Tmux | Home](http://tmux.sourceforge.net) [Tmux Manual page](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/tmux.1?query=tmux) [Gentoo Wiki](http://wiki.gentoo.org/wiki/Tmux) [Archlinux Wiki](https://wiki.archlinux.org/index.php/Tmux) [Display CPU/MEM % in statusbar](https://stackoverflow.com/questions/11558907/is-there-a-better-way-to-display-cpu-usage-in-tmux) [tmuxinator - Manage complex tmux sessions](https://github.com/tmuxinator/tmuxinator) ================================================ FILE: lua.md ================================================ --- name: Lua contributors: - ["Tyler Neylon", "http://tylerneylon.com/"] filename: learnlua.lua --- ```lua -- Two dashes start a one-line comment. --[[ Adding two ['s and ]'s makes it a multi-line comment. --]] ---------------------------------------------------- -- 1. Variables and flow control. ---------------------------------------------------- num = 42 -- Numbers can be integer or floating point. s = 'walternate' -- Immutable strings like Python. t = "double-quotes are also fine" u = [[ Double brackets start and end multi-line strings.]] t = nil -- Undefines t; Lua has garbage collection. -- Blocks are denoted with keywords like do/end: while num < 50 do num = num + 1 -- No ++ or += type operators. end -- If clauses: if num > 40 then print('over 40') elseif s ~= 'walternate' then -- ~= is not equals. -- Equality check is == like Python; ok for strs. io.write('not over 40\n') -- Defaults to stdout. else -- Variables are global by default. thisIsGlobal = 5 -- Camel case is common. -- How to make a variable local: local line = io.read() -- Reads next stdin line. -- String concatenation uses the .. operator: print('Winter is coming, ' .. line) end -- Undefined variables return nil. -- This is not an error: foo = anUnknownVariable -- Now foo = nil. aBoolValue = false -- Only nil and false are falsy; 0 and '' are true! if not aBoolValue then print('it was false') end -- 'or' and 'and' are short-circuited. -- This is similar to the a?b:c operator in C/js: ans = aBoolValue and 'yes' or 'no' --> 'no' karlSum = 0 for i = 1, 100 do -- The range includes both ends. karlSum = karlSum + i end -- Use "100, 1, -1" as the range to count down: fredSum = 0 for j = 100, 1, -1 do fredSum = fredSum + j end -- In general, the range is begin, end[, step]. -- Another loop construct: repeat print('the way of the future') num = num - 1 until num == 0 ---------------------------------------------------- -- 2. Functions. ---------------------------------------------------- function fib(n) if n < 2 then return 1 end return fib(n - 2) + fib(n - 1) end -- Closures and anonymous functions are ok: function adder(x) -- The returned function is created when adder is -- called, and remembers the value of x: return function (y) return x + y end end a1 = adder(9) a2 = adder(36) print(a1(16)) --> 25 print(a2(64)) --> 100 -- Returns, func calls, and assignments all work -- with lists that may be mismatched in length. -- Unmatched receivers are nil; -- unmatched senders are discarded. x, y, z = 1, 2, 3, 4 -- Now x = 1, y = 2, z = 3, and 4 is thrown away. function bar(a, b, c) print(a, b, c) return 4, 8, 15, 16, 23, 42 end x, y = bar('zaphod') --> prints "zaphod nil nil" -- Now x = 4, y = 8, values 15...42 are discarded. -- Functions are first-class, may be local/global. -- These are the same: function f(x) return x * x end f = function (x) return x * x end -- And so are these: local function g(x) return math.sin(x) end local g; g = function (x) return math.sin(x) end -- the 'local g' decl makes g-self-references ok. -- Trig funcs work in radians, by the way. -- Calls with one string param don't need parens: print 'hello' -- Works fine. ---------------------------------------------------- -- 3. Tables. ---------------------------------------------------- -- Tables = Lua's only compound data structure; -- they are associative arrays. -- Similar to php arrays or js objects, they are -- hash-lookup dicts that can also be used as lists. -- Using tables as dictionaries / maps: -- Dict literals have string keys by default: t = {key1 = 'value1', key2 = false} -- String keys can use js-like dot notation: print(t.key1) -- Prints 'value1'. t.newKey = {} -- Adds a new key/value pair. t.key2 = nil -- Removes key2 from the table. -- Literal notation for any (non-nil) value as key: u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} print(u[6.28]) -- prints "tau" -- Key matching is basically by value for numbers -- and strings, but by identity for tables. a = u['@!#'] -- Now a = 'qbert'. b = u[{}] -- We might expect 1729, but it's nil: -- b = nil since the lookup fails. It fails -- because the key we used is not the same object -- as the one used to store the original value. So -- strings & numbers are more portable keys. -- A one-table-param function call needs no parens: function h(x) print(x.key1) end h{key1 = 'Sonmi~451'} -- Prints 'Sonmi~451'. for key, val in pairs(u) do -- Table iteration. print(key, val) end -- _G is a special table of all globals. print(_G['_G'] == _G) -- Prints 'true'. -- Using tables as lists / arrays: -- List literals implicitly set up int keys: v = {'value1', 'value2', 1.21, 'gigawatts'} for i = 1, #v do -- #v is the size of v for lists. print(v[i]) -- Indices start at 1 !! SO CRAZY! end -- A 'list' is not a real type. v is just a table -- with consecutive integer keys, treated as a list. ---------------------------------------------------- -- 3.1 Metatables and metamethods. ---------------------------------------------------- -- A table can have a metatable that gives the table -- operator-overloadish behavior. Later we'll see -- how metatables support js-prototype behavior. f1 = {a = 1, b = 2} -- Represents the fraction a/b. f2 = {a = 2, b = 3} -- This would fail: -- s = f1 + f2 metafraction = {} function metafraction.__add(f1, f2) sum = {} sum.b = f1.b * f2.b sum.a = f1.a * f2.b + f2.a * f1.b return sum end setmetatable(f1, metafraction) setmetatable(f2, metafraction) s = f1 + f2 -- call __add(f1, f2) on f1's metatable -- f1, f2 have no key for their metatable, unlike -- prototypes in js, so you must retrieve it as in -- getmetatable(f1). The metatable is a normal table -- with keys that Lua knows about, like __add. -- But the next line fails since s has no metatable: -- t = s + s -- Class-like patterns given below would fix this. -- An __index on a metatable overloads dot lookups: defaultFavs = {animal = 'gru', food = 'donuts'} myFavs = {food = 'pizza'} setmetatable(myFavs, {__index = defaultFavs}) eatenBy = myFavs.animal -- works! thanks, metatable -- Direct table lookups that fail will retry using -- the metatable's __index value, and this recurses. -- An __index value can also be a function(tbl, key) -- for more customized lookups. -- The values of __index, __add, etc. are called -- metamethods. Here are some commonly used ones: -- __add(a, b) for a + b -- __sub(a, b) for a - b -- __mul(a, b) for a * b -- __div(a, b) for a / b -- __mod(a, b) for a % b -- __pow(a, b) for a ^ b -- __unm(a) for -a -- __concat(a, b) for a .. b -- __len(a) for #a -- __eq(a, b) for a == b -- __lt(a, b) for a < b -- __le(a, b) for a <= b -- __index(a, b) for a.b -- __newindex(a, b, c) for a.b = c -- __call(a, ...) for a(...) ---------------------------------------------------- -- 3.2 Class-like tables and inheritance. ---------------------------------------------------- -- Classes aren't built in; there are different ways -- to make them using tables and metatables. -- Explanation for this example is below it. Dog = {} -- 1. function Dog:new() -- 2. newObj = {sound = 'woof'} -- 3. self.__index = self -- 4. return setmetatable(newObj, self) -- 5. end function Dog:makeSound() -- 6. print('I say ' .. self.sound) end mrDog = Dog:new() -- 7. mrDog:makeSound() -- 'I say woof' -- 8. -- 1. Dog acts like a class; it's really a table. -- 2. function tablename:fn(...) is the same as -- function tablename.fn(self, ...) -- The : just adds a first arg called self. -- Read 7 & 8 below for how self gets its value. -- 3. newObj will be an instance of class Dog. -- 4. self = the class being instantiated. Often -- self = Dog, but inheritance can change it. -- newObj gets self's functions when we set both -- newObj's metatable and self's __index to self. -- 5. Reminder: setmetatable returns its first arg. -- 6. The : works as in 2, but this time we expect -- self to be an instance instead of a class. -- 7. Same as Dog.new(Dog), so self = Dog in new(). -- 8. Same as mrDog.makeSound(mrDog); self = mrDog. ---------------------------------------------------- -- Inheritance example: LoudDog = Dog:new() -- 1. function LoudDog:makeSound() s = self.sound .. ' ' -- 2. print(s .. s .. s) end seymour = LoudDog:new() -- 3. seymour:makeSound() -- 'woof woof woof' -- 4. -- 1. LoudDog gets Dog's methods and variables. -- 2. self has a 'sound' key from new(), see 3. -- 3. Same as LoudDog.new(LoudDog), and converted to -- Dog.new(LoudDog) as LoudDog has no 'new' key, -- but does have __index = Dog on its metatable. -- Result: seymour's metatable is LoudDog, and -- LoudDog.__index = LoudDog. So seymour.key will -- = seymour.key, LoudDog.key, Dog.key, whichever -- table is the first with the given key. -- 4. The 'makeSound' key is found in LoudDog; this -- is the same as LoudDog.makeSound(seymour). -- If needed, a subclass's new() is like the base's: function LoudDog:new() newObj = {} -- set up newObj self.__index = self return setmetatable(newObj, self) end ---------------------------------------------------- -- 4. Modules. ---------------------------------------------------- --[[ I'm commenting out this section so the rest of -- this script remains runnable. ``` ```lua -- Suppose the file mod.lua looks like this: local M = {} local function sayMyName() print('Hrunkner') end function M.sayHello() print('Why hello there') sayMyName() end return M -- Another file can use mod.lua's functionality: local mod = require('mod') -- Run the file mod.lua. -- require is the standard way to include modules. -- require acts like: (if not cached; see below) local mod = (function () end)() -- It's like mod.lua is a function body, so that -- locals inside mod.lua are invisible outside it. -- This works because mod here = M in mod.lua: mod.sayHello() -- Prints: Why hello there Hrunkner -- This is wrong; sayMyName only exists in mod.lua: mod.sayMyName() -- error -- require's return values are cached so a file is -- run at most once, even when require'd many times. -- Suppose mod2.lua contains "print('Hi!')". local a = require('mod2') -- Prints Hi! local b = require('mod2') -- Doesn't print; a=b. -- dofile is like require without caching: dofile('mod2.lua') --> Hi! dofile('mod2.lua') --> Hi! (runs it again) -- loadfile loads a lua file but doesn't run it yet. f = loadfile('mod2.lua') -- Call f() to run it. -- load is loadfile for strings. -- (loadstring is deprecated, use load instead) g = load('print(343)') -- Returns a function. g() -- Prints out 343; nothing printed before now. --]] ``` ## Community If you need support join the official Lua [mailing list](https://www.lua.org/lua-l.html), [IRC channel](http://lua-users.org/wiki/IrcChannel), or [forum](https://luaforum.com). ## References I was excited to learn Lua so I could make games with the [LÖVE game engine](http://love2d.org/). That's the why. I started with [BlackBulletIV's Lua for programmers](https://ebens.me/posts/lua-for-programmers-part-1/). Next I read the official [Programming in Lua](http://www.lua.org/pil/contents.html) book. That's the how. It might be helpful to check out the [Lua short reference](http://lua-users.org/wiki/LuaShortReference) on lua-users.org. The main topics not covered are standard libraries: * [`string` library](http://lua-users.org/wiki/StringLibraryTutorial) * [`table` library](http://lua-users.org/wiki/TableLibraryTutorial) * [`math` library](http://lua-users.org/wiki/MathLibraryTutorial) * [`io` library](http://lua-users.org/wiki/IoLibraryTutorial) * [`os` library](http://lua-users.org/wiki/OsLibraryTutorial) By the way, the entire file is valid Lua; save it as learn.lua and run it with "`lua learn.lua`" ! This was first written for tylerneylon.com, and is also available as a [GitHub gist](https://gist.github.com/tylerneylon/5853042). Have fun with Lua! ================================================ FILE: m.md ================================================ --- name: M (MUMPS) contributors: - ["Fred Turkington", "http://z3ugma.github.io"] filename: LEARNM.m --- M, or MUMPS (Massachusetts General Hospital Utility Multi-Programming System) is a procedural language with a built-in NoSQL database. Or, it’s a database with an integrated language optimized for accessing and manipulating that database. A key feature of M is that accessing local variables in memory and persistent storage use the same basic syntax, so there's no separate query language to remember. This makes it fast to program with, especially for beginners. M's syntax was designed to be concise in an era where computer memory was expensive and limited. This concise style means that a lot more fits on one screen without scrolling. The M database is a hierarchical key-value store designed for high-throughput transaction processing. The database is organized into tree structures called "globals", (for global variables) which are sparse data structures with parallels to modern formats like JSON. Originally designed in 1966 for the healthcare applications, M continues to be used widely by healthcare systems and financial institutions for high-throughput real-time applications. ### Example Here's an example M program using expanded syntax to calculate the Fibonacci series: ``` fib ; compute the first few Fibonacci terms new i,a,b,sum set (a,b)=1 ; Initial conditions for i=1:1 do quit:sum>1000 . set sum=a+b . write !,sum . set a=b,b=sum ``` ### Comments Comments in M need at least one space before the comment marker of semicolon. Comments that start with at least two semicolons (;;) are guaranteed to be accessible within a running program. ``` ; Comments start with a semicolon (;) ``` ### Data Types M has one data type (String) and three interpretations of that string.: ``` ; Strings - Characters enclosed in double quotes. ; "" is the null string. Use "" within a string for " ; Examples: "hello", "Scrooge said, ""Bah, Humbug!""" ; ; Numbers - no commas, leading and trailing 0 removed. ; Scientific notation with 'E'. (not 'e') ; Numbers with at least with IEEE 754 double-precision values (guaranteed 15 digits of precision) ; Examples: 20 (stored as 20) , 1e3 (stored as 1000), 0500.20 (stored as 500.2), ; the US National Debt AT sometime on 12-OCT-2020 retrieved from http://www.usdebt.org is 27041423576201.15) ; (required to be stored as at least 27041422576201.10 but most implementations store as 27041432576201.15) ; ; Truthvalues - String interpreted as 0 is used for false and any string interpreted as non-zero (such as 1) for true. ``` ### Commands Commands are case insensitive, and have full form, and a shortened abbreviation, often the first letter. Commands have zero or more arguments,depending on the command. This page includes programs written in this terse syntax. M is whitespace-aware. Spaces are treated as a delimiter between commands and arguments. Each command is separated from its arguments by 1 space. Commands with zero arguments are followed by 2 spaces. (technically these are called argumentless commands) #### Common Commands from all National and International Standards of M #### Write (abbreviated as W) Print data to the current device. ``` WRITE !,"hello world" ``` Output Formatting characters: The ! character is syntax for a new line. The # character is syntax for a new page. The sequence of the ? character and then a numeric expression is syntax for output of spaces until the number'th column is printed. Multiple statements can be provided as additional arguments before the space separators to the next command: ``` w !,"foo bar"," ","baz" ``` #### Read (abbreviated as R) Retrieve input from the user ``` READ var r !,"Wherefore art thou Romeo? ",why ``` As with all M commands, multiple arguments can be passed to a read command. Constants like quoted strings, numbers, and formatting characters are output directly. Values for both global variables and local variables are retrieved from the user. The terminal waits for the user to enter the first variable before displaying the second prompt. ``` r !,"Better one, or two? ",lorem," Better two, or three? ",ipsum ``` #### Set (abbreviated as S) Assign a value to a variable ``` SET name="Benjamin Franklin" s centi=0.01,micro=10E-6 w !,centi,!,micro ;.01 ;.00001 ``` #### Kill (abbreviated as K) Remove a variable from memory or remove a database entry from disk. A database node (global variable) is killed depending on the variable name being prefixed by the caret character (^). If it is not, then the local variable is removed from memory. If KILLed, automatic garbage collection occurs. ``` KILL centi k micro ``` ### Globals and Arrays In addition to local variables, M has persistent, shared variables that are the built-in database of M. They are stored to disk and called _globals_. Global names must start with a __caret__ (__^__). Any variable (local or global) can be an array with the assignment of a _subscript_. Arrays are sparse and do not have a predefined size. Only if data is stored will a value use memory. Arrays should be visualized like trees, where subscripts are branches and assigned values are leaves. Not all nodes in an array need to have a value. ``` s ^cars=20 s ^cars("Tesla",1,"Name")="Model 3" s ^cars("Tesla",2,"Name")="Model X" s ^cars("Tesla",2,"Doors")=5 w !,^cars ; 20 w !,^cars("Tesla") ; null value - there's no value assigned to this node but it has children w !,^cars("Tesla",1,"Name") ; Model 3 ``` The index values of Arrays are automatically sorted in order. There is a catchphrase of "MUMPS means never having to say you are sorting". Take advantage of the built-in sorting by setting your value of interest as the last child subscript of an array rather than its value, and then storing an empty string for that node. ``` ; A log of temperatures by date and time s ^TEMPS("11/12","0600",32)="" s ^TEMPS("11/12","1030",48)="" s ^TEMPS("11/12","1400",49)="" s ^TEMPS("11/12","1700",43)="" ``` ### Operators ``` ; Assignment: = ; Unary: + Convert a string value into a numeric value. ; Arthmetic: ; + addition ; - subtraction ; * multiplication ; / floating-point division ; \ integer division ; # modulo ; ** exponentiation ; Logical: ; & and ; ! or ; ' not ; Comparison: ; = equal ; '= not equal ; > greater than ; < less than ; '> not greater / less than or equal to ; '< not less / greater than or equal to ; String operators: ; _ concatenate ; [ contains ­ a contains b ; ]] sorts after ­ a comes after b ; '[ does not contain ; ']] does not sort after ``` #### Order of operations Operations in M are _strictly_ evaluated left to right. No operator has precedence over any other. For example, there is NO order of operations where multiply is evaluated before addition. To change this order, just use parentheses to group expressions to be evaluated first. ``` w 5+3*20 ;160 ;You probably wanted 65 write 5+(3*20) ``` ### Flow Control, Blocks, & Code Structure A single M file is called a _routine_. Within a given routine, you can break your code up into smaller chunks with _tags_. The tag starts in column 1 and the commands pertaining to that tag are indented. A tag can accept parameters and return a value, this is a function. A function is called with '$$': ``` ; Execute the 'tag' function, which has two parameters, and write the result. w !,$$tag^routine(a,b) ``` M has an execution stack. When all levels of the stack have returned, the program ends. Levels are added to the stack with _do_ commands and removed with _quit_ commands. #### Do (abbreviated as D) With an argument: execute a block of code & add a level to the stack. ``` d ^routine ;run a routine from the beginning. ; ;routines are identified by a caret. d tag ;run a tag in the current routine d tag^routine ;run a tag in different routine ``` Argumentless do: used to create blocks of code. The block is indented with a period for each level of the block: ``` set a=1 if a=1 do . write !,a . read b . if b > 10 d . . w !, b w "hello" ``` #### Quit (abbreviated as Q) Stop executing this block and return to the previous stack level. Quit can return a value, following the command with a single space. Quit can stop a loop. remember to follow with two spaces. Quit outside a loop will return from the current subroutine followed by two spaces or a linefeed #### New (abbreviated as N) Hide with a cleared value a given variable's value _for just this stack level_. Useful for preventing side effects. Putting all this together, we can create a full example of an M routine: ``` ; RECTANGLE - a routine to deal with rectangle math q ; quit if a specific tag is not called main n length,width ; New length and width so any previous value doesn't persist w !,"Welcome to RECTANGLE. Enter the dimensions of your rectangle." r !,"Length? ",length,!,"Width? ",width d area(length,width) ;Do/Call subroutine using a tag s per=$$perimeter(length,width) ;Get the value of a function w !,"Perimeter: ",per quit area(length,width) ; This is a tag that accepts parameters. ; It's not a function since it quits with no value. w !, "Area: ",length*width q ; Quit: return to the previous level of the stack. perimeter(length,width) q 2*(length+width) ; Returns a value using Quit ; this is a function ``` ### Conditionals, Looping and $Order() F(or) loops can follow a few different patterns: ```jinja ;Finite loop with counter ;f var=start:increment:stop f i=0:5:25 w i," " ;0 5 10 15 20 25 ; Infinite loop with counter ; The counter will keep incrementing forever. Use a conditional with Quit to get out of the loop. ;f var=start:increment f j=1:1 w j," " i j>1E3 q ; Print 1-1000 separated by a space ;Argumentless for - infinite loop. Use a conditional with Quit. ; Also read as "forever" - f or for followed by two spaces. s var="" f s var=var_"%" w !,var i var="%%%%%%%%%%" q ; % ; %% ; %%% ; %%%% ; %%%%% ; %%%%%% ; %%%%%%% ; %%%%%%%% ; %%%%%%%%% ; %%%%%%%%%% ``` #### I(f), E(lse), Postconditionals M has an if/else construct for conditional evaluation, but any command can be conditionally executed without an extra if statement using a _postconditional_. This is a condition that occurs immediately after the command, separated with a colon (:). ```jinja ; Conditional using traditional if/else r "Enter a number: ",num i num>100 w !,"huge" e i num>10 w !,"big" e w !,"small" ; Postconditionals are especially useful in a for loop. ; This is the dominant for loop construct: ; a 'for' statement ; that tests for a 'quit' condition with a postconditional ; then 'do'es an indented block for each iteration s var="" f s var=var_"%" q:var="%%%%%%%%%%" d ;Read as "Quit if var equals "%%%%%%%%%%" . w !,var ;Bonus points - the $L(ength) built-in function makes this even terser s var="" f s var=var_"%" q:$L(var)>10 d ; . w !,var ``` #### Array Looping - $Order As we saw in the previous example, M has built-in functions called with a single $, compared to user-defined functions called with $$. These functions have shortened abbreviations, like commands. One of the most useful is __$Order()__ / $O(). When given an array subscript, $O returns the next subscript in that array. When it reaches the last subscript, it returns "". ```jinja ;Let's call back to our ^TEMPS global from earlier: ; A log of temperatures by date and time s ^TEMPS("11/12","0600",32)="" s ^TEMPS("11/12","0600",48)="" s ^TEMPS("11/12","1400",49)="" s ^TEMPS("11/12","1700",43)="" ; Some more s ^TEMPS("11/16","0300",27)="" s ^TEMPS("11/16","1130",32)="" s ^TEMPS("11/16","1300",47)="" ;Here's a loop to print out all the dates we have temperatures for: n date,time ; Initialize these variables with "" ; This line reads: forever; set date as the next date in ^TEMPS. ; If date was set to "", it means we're at the end, so quit. ; Do the block below f s date=$ORDER(^TEMPS(date)) q:date="" d . w !,date ; Add in times too: f s date=$ORDER(^TEMPS(date)) q:date="" d . w !,"Date: ",date . f s time=$O(^TEMPS(date,time)) q:time="" d . . w !,"Time: ",time ; Build an index that sorts first by temperature - ; what dates and times had a given temperature? n date,time,temp f s date=$ORDER(^TEMPS(date)) q:date="" d . f s time=$O(^TEMPS(date,time)) q:time="" d . . f s temp=$O(^TEMPS(date,time,temp)) q:temp="" d . . . s ^TEMPINDEX(temp,date,time)="" ;This will produce a global like ^TEMPINDEX(27,"11/16","0300") ^TEMPINDEX(32,"11/12","0600") ^TEMPINDEX(32,"11/16","1130") ``` ## Further Reading There's lots more to learn about M. A great short tutorial comes from the University of Northern Iowa and Professor Kevin O'Kane's [Introduction to the MUMPS Language][1] presentation. More about M using VistA is at Intersystems has some products which are a super-set of the M programming language. * [Iris Description Page][5] * [Cache Description Page][6] To install an M interpreter / database on your computer, try a [YottaDB Docker image][2]. YottaDB and its precursor, GT.M, have thorough documentation on all the language features including database transactions, locking, and replication: * [YottaDB Programmer's Guide][3] * [GT.M Programmer's Guide][4] [1]: https://www.cs.uni.edu/~okane/source/MUMPS-MDH/MumpsTutorial.pdf [2]: https://yottadb.com/product/get-started/ [3]: https://docs.yottadb.com/ProgrammersGuide/langfeat.html [4]: http://tinco.pair.com/bhaskar/gtm/doc/books/pg/UNIX_manual/index.html [5]: https://www.intersystems.com/products/intersystems-iris/ [6]: https://en.wikipedia.org/wiki/InterSystems_Caché ================================================ FILE: make.md ================================================ --- category: tool name: Make contributors: - ["Robert Steed", "https://github.com/robochat"] - ["Stephan Fuhrmann", "https://github.com/sfuhrm"] filename: Makefile --- A Makefile defines a graph of rules for creating a target (or targets). Its purpose is to do the minimum amount of work needed to update a target to the most recent version of the source. Famously written over a weekend by Stuart Feldman in 1976, it is still widely used (particularly on Unix and Linux) despite many competitors and criticisms. There are many varieties of make in existence, however this article assumes that we are using GNU make which is the standard on Linux. ```make # Comments can be written like this. # File should be named Makefile and then can be run as `make `. # Otherwise we use `make -f "filename" `. # Warning - only use TABS to indent in Makefiles, never spaces! #----------------------------------------------------------------------- # Basics #----------------------------------------------------------------------- # Rules are of the format # target: # where prerequisites are optional. # A rule - this rule will only run if file0.txt doesn't exist. file0.txt: echo "foo" > file0.txt # Even comments in these 'recipe' sections get passed to the shell. # Try `make file0.txt` or simply `make` - first rule is the default. # This rule will only run if file0.txt is newer than file1.txt. file1.txt: file0.txt cat file0.txt > file1.txt # use the same quoting rules as in the shell. @cat file0.txt >> file1.txt # @ stops the command from being echoed to stdout. -@echo 'hello' # - means that make will keep going in the case of an error. # Try `make file1.txt` on the commandline. # A rule can have multiple targets and multiple prerequisites file2.txt file3.txt: file0.txt file1.txt touch file2.txt touch file3.txt # Make will complain about multiple recipes for the same rule. Empty # recipes don't count though and can be used to add new dependencies. #----------------------------------------------------------------------- # Phony Targets #----------------------------------------------------------------------- # A phony target. Any target that isn't a file. # It will never be up to date so make will always try to run it. all: maker process # We can declare things out of order. maker: touch ex0.txt ex1.txt # Can avoid phony rules breaking when a real file has the same name by .PHONY: all maker process # This is a special target. There are several others. # A rule with a dependency on a phony target will always run ex0.txt ex1.txt: maker # Common phony targets are: all make clean install ... #----------------------------------------------------------------------- # Automatic Variables & Wildcards #----------------------------------------------------------------------- process: file*.txt #using a wildcard to match filenames @echo $^ # $^ is a variable containing the list of prerequisites @echo $@ # prints the target name #(for multiple target rules, $@ is whichever caused the rule to run) @echo $< # the first prerequisite listed @echo $? # only the dependencies that are out of date @echo $+ # all dependencies including duplicates (unlike normal) #@echo $| # all of the 'order only' prerequisites # Even if we split up the rule dependency definitions, $^ will find them process: ex1.txt file0.txt # ex1.txt will be found but file0.txt will be deduplicated. #----------------------------------------------------------------------- # Patterns #----------------------------------------------------------------------- # Can teach make how to convert certain files into other files. %.png: %.svg inkscape --export-png $^ # Pattern rules will only do anything if make decides to create the # target. # Directory paths are normally ignored when matching pattern rules. But # make will try to use the most appropriate rule available. small/%.png: %.svg inkscape --export-png --export-dpi 30 $^ # make will use the last version for a pattern rule that it finds. %.png: %.svg @echo this rule is chosen # However make will use the first pattern rule that can make the target %.png: %.ps @echo this rule is not chosen if *.svg and *.ps are both present # make already has some pattern rules built-in. For instance, it knows # how to turn *.c files into *.o files. # Older makefiles might use suffix rules instead of pattern rules .png.ps: @echo this rule is similar to a pattern rule. # Tell make about the suffix rule .SUFFIXES: .png #----------------------------------------------------------------------- # Variables #----------------------------------------------------------------------- # aka. macros # Variables are basically all string types name = Ted name2="Sarah" echo: @echo $(name) @echo ${name2} @echo $name # This won't work, treated as $(n)ame. @echo $(name3) # Unknown variables are treated as empty strings. # There are 4 places to set variables. # In order of priority from highest to lowest: # 1: commandline arguments # 2: Makefile # 3: shell environment variables - make imports these automatically. # 4: make has some predefined variables name4 ?= Jean # Only set the variable if environment variable is not already defined. override name5 = David # Stops commandline arguments from changing this variable. name4 +=grey # Append values to variable (includes a space). # Pattern-specific variable values (GNU extension). echo: name2 = Sara # True within the matching rule # and also within its remade recursive dependencies # (except it can break when your graph gets too complicated!) # Some variables defined automatically by make. echo_inbuilt: echo $(CC) echo ${CXX} echo $(FC) echo ${CFLAGS} echo $(CPPFLAGS) echo ${CXXFLAGS} echo $(LDFLAGS) echo ${LDLIBS} #----------------------------------------------------------------------- # Variables 2 #----------------------------------------------------------------------- # The first type of variables are evaluated each time they are used. # This can be expensive, so a second type of variable exists which is # only evaluated once. (This is a GNU make extension) var := hello var2 ::= $(var) hello #:= and ::= are equivalent. # These variables are evaluated procedurally (in the order that they # appear), thus breaking with the rest of the language ! # This doesn't work var3 ::= $(var4) and good luck var4 ::= good night #----------------------------------------------------------------------- # Functions #----------------------------------------------------------------------- # make has lots of functions available. sourcefiles = $(wildcard *.c */*.c) objectfiles = $(patsubst %.c,%.o,$(sourcefiles)) # Format is $(func arg0,arg1,arg2...) # Some examples ls: * src/* @echo $(filter %.txt, $^) @echo $(notdir $^) @echo $(join $(dir $^),$(notdir $^)) #----------------------------------------------------------------------- # Directives #----------------------------------------------------------------------- # Include other makefiles, useful for platform specific code include foo.mk sport = tennis # Conditional compilation report: ifeq ($(sport),tennis) @echo 'game, set, match' else @echo "They think it's all over; it is now" endif # There are also ifneq, ifdef, ifndef foo = true ifdef $(foo) bar = 'hello' endif ``` ### More Resources - [GNU Make documentation](https://www.gnu.org/software/make/manual/make.html) - [Software Carpentry tutorial](https://swcarpentry.github.io/make-novice/) - [Makefile Tutorial By Example](https://makefiletutorial.com/#makefile-cookbook) ================================================ FILE: markdown.md ================================================ --- name: Markdown contributors: - ["Dan Turkel", "http://danturkel.com/"] - ["Jacob Ward", "http://github.com/JacobCWard/"] - ["Tomáš Hartman", "https://github.com/tomas-hartman"] filename: markdown.md --- Markdown was created by John Gruber in 2004. It's meant to be an easy to read and write syntax which converts easily to HTML (and now many other formats as well). Markdown also varies in implementation from one parser to a next. This guide will attempt to clarify when features are universal or when they are specific to a certain parser. ## HTML Elements Markdown is a superset of HTML, so any HTML file is valid Markdown. ```md ``` ## Headings You can create HTML elements `

` through `

` easily by prepending the text you want to be in that element by a number of hashes (#). ```md # This is an

## This is an

### This is an

#### This is an

##### This is an

###### This is an
``` Markdown also provides us with two alternative ways of indicating h1 and h2. ```md This is an h1 ============= This is an h2 ------------- ``` ## Simple text styles Text can be easily styled as italic or bold using markdown. ```md *This text is in italics.* _And so is this text._ **This text is in bold.** __And so is this text.__ ***This text is in both.*** **_As is this!_** *__And this!__* ``` In GitHub Flavored Markdown, which is used to render markdown files on GitHub, we also have strikethrough: ```md ~~This text is rendered with strikethrough.~~ ``` ## Paragraphs Paragraphs are a one or multiple adjacent lines of text separated by one or multiple blank lines. ```md This is a paragraph. I'm typing in a paragraph isn't this fun? Now I'm in paragraph 2. I'm still in paragraph 2 too! I'm in paragraph three! ``` Should you ever want to insert an HTML `
` tag, you can end a paragraph with two or more spaces and then begin a new paragraph. ```md I end with two spaces (highlight me to see them). There's a
above me! ``` Block quotes are easy and done with the > character. ```md > This is a block quote. You can either > manually wrap your lines and put a `>` before every line or you can let your lines get really long and wrap on their own. > It doesn't make a difference so long as they start with a `>`. > You can also use more than one level >> of indentation? > How neat is that? ``` ## Lists Unordered lists can be made using asterisks, pluses, or hyphens. ```md * Item * Item * Another item or + Item + Item + One more item or - Item - Item - One last item ``` Ordered lists are done with a number followed by a period. ```md 1. Item one 2. Item two 3. Item three ``` You don't even have to label the items correctly and Markdown will still render the numbers in order, but this may not be a good idea. ```md 1. Item one 1. Item two 1. Item three ``` (This renders the same as the example above.) You can also use sublists. ```md 1. Item one 2. Item two 3. Item three * Sub-item * Sub-item 4. Item four ``` There are even task lists. This creates HTML checkboxes. ```md Boxes below without the 'x' are unchecked HTML checkboxes. - [ ] First task to complete. - [ ] Second task that needs done This checkbox below will be a checked HTML checkbox. - [x] This task has been completed ``` ## Code blocks You can indicate a code block (which uses the `` element) by indenting a line with four spaces or a tab. ```md This is code So is this ``` You can also re-tab (or add an additional four spaces) for indentation inside your code. ```md my_array.each do |item| puts item end ``` Inline code can be created using the backtick character `` ` ``. ```md John didn't even know what the `go_to()` function did! ``` In GitHub Flavored Markdown, you can use a special syntax for code. ````md ```ruby def foobar puts "Hello world!" end ``` ```` The above text doesn't require indenting, plus GitHub will use syntax highlighting of the language you specify after the opening ```. ## Horizontal rule Horizontal rules (`
`) are easily added with three or more asterisks or hyphens, with or without spaces. ```md *** --- - - - **************** ``` ## Links One of the best things about markdown is how easy it is to make links. Put the text to display in hard brackets [] followed by the url in parentheses () ```md [Click me!](http://test.com/) ``` You can also add a link title using quotes inside the parentheses. ```md [Click me!](http://test.com/ "Link to Test.com") ``` Relative paths work too. ```md [Go to music](/music/). ``` Markdown also supports reference style links. ```md [Click this link][link1] for more info about it! [Also check out this link][foobar] if you want to. [link1]: http://test.com/ "Cool!" [foobar]: http://foobar.biz/ "Alright!" ``` The title can also be in single quotes or in parentheses, or omitted entirely. The references can be anywhere in your document and the reference IDs can be anything so long as they are unique. There is also "implicit naming" which lets you use the link text as the id. ```md [This][] is a link. [This]: http://thisisalink.com/ ``` But it's not that commonly used. ### Table of contents Some Markdown flavors even make use of the combination of lists, links and headings in order to create tables of contents. In this case, heading titles in lowercase are prepended with hash (`#`) and are used as link ids. Should the heading have multiple words, they will be connected with a hyphen (`-`), that also replaces some special characters. (Some other special characters are omitted though.) ```md - [Heading](#heading) - [Another heading](#another-heading) - [Chapter](#chapter) - [Subchapter

](#subchapter-h3-) ``` Nonetheless, this is a feature that might not be working in all Markdown implementations the same way. ## Images Images are done the same way as links but with an exclamation point in front! ```md ![This is the alt-attribute for my image](http://imgur.com/myimage.jpg "An optional title") ``` And reference style works as expected. ```md ![This is the alt-attribute.][myimage] [myimage]: relative/urls/cool/image.jpg "if you need a title, it's here" ``` ## Miscellany ### Auto-links ```md is equivalent to [http://testwebsite.com/](http://testwebsite.com/) ``` ### Auto-links for emails ```md ``` ### Escaping characters ```md I want to type *this text surrounded by asterisks* but I don't want it to be in italics, so I do this: \*this text surrounded by asterisks\*. ``` ### Keyboard keys In GitHub Flavored Markdown, you can use a `` tag to represent keyboard keys. ```md Your computer crashed? Try sending a Ctrl+Alt+Del ``` ### Tables Tables are only available in GitHub Flavored Markdown and are slightly cumbersome, but if you really want it: ```md | Col1 | Col2 | Col3 | | :----------- | :------: | ------------: | | Left-aligned | Centered | Right-aligned | | blah | blah | blah | ``` or, for the same results ```md Col 1 | Col2 | Col3 :-- | :-: | --: Ugh this is so ugly | make it | stop ``` ## Markdownlint In order to simplify work with Markdown and to unify its coding style, `Markdownlint` has been created. Available as a [separate tool](https://github.com/markdownlint/markdownlint) as well as a plugin for some IDEs, it can be used to ensure validity and readability of Markdown. --- ## Further reading For more info, check out John Gruber's official post of syntax [here](http://daringfireball.net/projects/markdown/syntax) and Adam Pritchard's great cheatsheet [here](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). If you want to learn more on some major Markdown flavors' features, see: - [GitHub Flavored Markdown](https://docs.github.com/en/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) - [GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html) ================================================ FILE: matlab.md ================================================ --- name: MATLAB filename: learnmatlab.m contributors: - ["mendozao", "http://github.com/mendozao"] - ["jamesscottbrown", "http://jamesscottbrown.com"] - ["Colton Kohnke", "http://github.com/voltnor"] - ["Claudson Martins", "http://github.com/claudsonm"] --- MATLAB stands for MATrix LABoratory. It is a powerful numerical computing language commonly used in engineering and mathematics. ```matlab %% Code sections start with two percent signs. Section titles go on the same line. % Comments start with a percent sign. %{ Multi line comments look something like this %} % Two percent signs denote the start of a new code section % Individual code sections can be run by moving the cursor to the section followed by % either clicking the "Run Section" button % or using Ctrl+Shift+Enter (Windows) or Cmd+Shift+Return (macOS) %% This is the start of a code section % One way of using sections is to separate expensive but unchanging start-up code like loading data load myFile.mat y %% This is another code section % This section can be edited and run repeatedly on its own, and is helpful for exploratory programming and demos A = A * 2; plot(A); %% Code sections are also known as code cells or cell mode (not to be confused with cell arrays) % commands can span multiple lines, using '...': a = 1 + 2 + ... + 4 % commands can be passed to the operating system !ping google.com who % Displays all variables in memory whos % Displays all variables in memory, with their types clear % Erases all your variables from memory clear('A') % Erases a particular variable openvar('A') % Open variable in variable editor clc % Erases the writing on your Command Window diary % Toggle writing Command Window text to file ctrl-c % Abort current computation edit('myfunction.m') % Open function/script in editor type('myfunction.m') % Print the source of function/script to Command Window profile on % turns on the code profiler profile off % turns off the code profiler profile viewer % Open profiler help command % Displays documentation for command in Command Window doc command % Displays documentation for command in Help Window lookfor command % Searches for command in the first commented line of all functions lookfor command -all % searches for command in all functions % Output formatting format short % 4 decimals in a floating number format long % 15 decimals format bank % only two digits after decimal point - for financial calculations fprintf('text') % print "text" to the screen disp('text') % print "text" to the screen % Variables & Expressions myVariable = 4 % Notice Workspace pane shows newly created variable myVariable = 4; % Semi colon suppresses output to the Command Window 4 + 6 % ans = 10 8 * myVariable % ans = 32 2 ^ 3 % ans = 8 a = 2; b = 3; c = exp(a)*sin(pi/2) % c = 7.3891 % Calling functions can be done in either of two ways: % Standard function syntax: load('myFile.mat', 'y') % arguments within parentheses, separated by commas % Command syntax: load myFile.mat y % no parentheses, and spaces instead of commas % Note the lack of quote marks in command form: inputs are always passed as % literal text - cannot pass variable values. Also, can't receive output: [V,D] = eig(A); % this has no equivalent in command form [~,D] = eig(A); % if you only want D and not V % Logicals 1 > 5 % ans = 0 10 >= 10 % ans = 1 3 ~= 4 % Not equal to -> ans = 1 3 == 3 % equal to -> ans = 1 3 > 1 && 4 > 1 % AND -> ans = 1 3 > 1 || 4 > 1 % OR -> ans = 1 ~1 % NOT -> ans = 0 % Logicals can be applied to matrices: A > 5 % for each element, if condition is true, that element is 1 in returned matrix A( A > 5 ) % returns a vector containing the elements in A for which condition is true % Strings a = 'MyString' length(a) % ans = 8 a(2) % ans = y [a,a] % ans = MyStringMyString % Cells a = {'one', 'two', 'three'} a(1) % ans = 'one' - returns a cell char(a(1)) % ans = one - returns a string % Structures A.b = {'one','two'}; A.c = [1 2]; A.d.e = false; % Vectors x = [4 32 53 7 1] x(2) % ans = 32, indices in MATLAB start 1, not 0 x(2:3) % ans = 32 53 x(2:end) % ans = 32 53 7 1 x = [4; 32; 53; 7; 1] % Column vector x = [1:10] % x = 1 2 3 4 5 6 7 8 9 10 x = [1:2:10] % Increment by 2, i.e. x = 1 3 5 7 9 % Matrices A = [1 2 3; 4 5 6; 7 8 9] % Rows are separated by a semicolon; elements are separated with space or comma % A = % 1 2 3 % 4 5 6 % 7 8 9 A(2,3) % ans = 6, A(row, column) A(6) % ans = 8 % (implicitly concatenates columns into vector, then indexes into that) A(2,3) = 42 % Update row 2 col 3 with 42 % A = % 1 2 3 % 4 5 42 % 7 8 9 A(2:3,2:3) % Creates a new matrix from the old one %ans = % 5 42 % 8 9 A(:,1) % All rows in column 1 %ans = % 1 % 4 % 7 A(1,:) % All columns in row 1 %ans = % 1 2 3 [A ; A] % Concatenation of matrices (vertically) %ans = % 1 2 3 % 4 5 42 % 7 8 9 % 1 2 3 % 4 5 42 % 7 8 9 % this is the same as vertcat(A,A); [A , A] % Concatenation of matrices (horizontally) %ans = % 1 2 3 1 2 3 % 4 5 42 4 5 42 % 7 8 9 7 8 9 % this is the same as horzcat(A,A); A(:, [3 1 2]) % Rearrange the columns of original matrix %ans = % 3 1 2 % 42 4 5 % 9 7 8 size(A) % ans = 3 3 A(1, :) =[] % Delete the first row of the matrix A(:, 1) =[] % Delete the first column of the matrix transpose(A) % Transpose the matrix, which is the same as: A.' % Concise version of transpose (without taking complex conjugate) ctranspose(A) % Hermitian transpose the matrix, which is the same as: A' % Concise version of complex transpose % (the transpose, followed by taking complex conjugate of each element) % Element by Element Arithmetic vs. Matrix Arithmetic % On their own, the arithmetic operators act on whole matrices. When preceded % by a period, they act on each element instead. For example: A * B % Matrix multiplication A .* B % Multiply each element in A by its corresponding element in B % There are several pairs of functions, where one acts on each element, and % the other (whose name ends in m) acts on the whole matrix. exp(A) % exponentiate each element expm(A) % calculate the matrix exponential sqrt(A) % take the square root of each element sqrtm(A) % find the matrix whose square is A % Plotting x = 0:.10:2*pi; % Creates a vector that starts at 0 and ends at 2*pi with increments of .1 y = sin(x); plot(x,y) xlabel('x axis') ylabel('y axis') title('Plot of y = sin(x)') axis([0 2*pi -1 1]) % x range from 0 to 2*pi, y range from -1 to 1 plot(x,y1,'-',x,y2,'--',x,y3,':') % For multiple functions on one plot legend('Line 1 label', 'Line 2 label') % Label curves with a legend % Alternative method to plot multiple functions in one plot. % while 'hold' is on, commands add to existing graph rather than replacing it plot(x, y) hold on plot(x, z) hold off loglog(x, y) % A log-log plot semilogx(x, y) % A plot with logarithmic x-axis semilogy(x, y) % A plot with logarithmic y-axis fplot (@(x) x^2, [2,5]) % plot the function x^2 from x=2 to x=5 grid on % Show grid; turn off with 'grid off' axis square % Makes the current axes region square axis equal % Set aspect ratio so data units are the same in every direction scatter(x, y); % Scatter-plot hist(x); % Histogram stem(x); % Plot values as stems, useful for displaying discrete data bar(x); % Plot bar graph z = sin(x); plot3(x,y,z); % 3D line plot pcolor(A) % Heat-map of matrix: plot as grid of rectangles, coloured by value contour(A) % Contour plot of matrix mesh(A) % Plot as a mesh surface h = figure % Create new figure object, with handle h figure(h) % Makes the figure corresponding to handle h the current figure close(h) % close figure with handle h close all % close all open figure windows close % close current figure window shg % bring an existing graphics window forward, or create new one if needed clf clear % clear current figure window, and reset most figure properties % Properties can be set and changed through a figure handle. % You can save a handle to a figure when you create it. % The function get returns a handle to the current figure h = plot(x, y); % you can save a handle to a figure when you create it set(h, 'Color', 'r') % 'y' yellow; 'm' magenta, 'c' cyan, 'r' red, 'g' green, 'b' blue, 'w' white, 'k' black set(h, 'LineStyle', '--') % '--' is solid line, '---' dashed, ':' dotted, '-.' dash-dot, 'none' is no line get(h, 'LineStyle') % The function gca returns a handle to the axes for the current figure set(gca, 'XDir', 'reverse'); % reverse the direction of the x-axis % To create a figure that contains several axes in tiled positions, use subplot subplot(2,3,1); % select the first position in a 2-by-3 grid of subplots plot(x1); title('First Plot') % plot something in this position subplot(2,3,2); % select second position in the grid plot(x2); title('Second Plot') % plot something there % To use functions or scripts, they must be on your path or current directory path % display current path addpath /path/to/dir % add to path rmpath /path/to/dir % remove from path cd /path/to/move/into % change directory % Variables can be saved to .mat files save('myFileName.mat') % Save the variables in your Workspace load('myFileName.mat') % Load saved variables into Workspace % M-file Scripts % A script file is an external file that contains a sequence of statements. % They let you avoid repeatedly typing the same code in the Command Window % Have .m extensions % M-file Functions % Like scripts, and have the same .m extension % But can accept input arguments and return an output % Also, they have their own workspace (ie. different variable scope). % Function name should match file name (so save this example as double_input.m). % 'help double_input.m' returns the comments under line beginning function function output = double_input(x) %double_input(x) returns twice the value of x output = 2*x; end double_input(6) % ans = 12 % You can also have subfunctions and nested functions. % Subfunctions are in the same file as the primary function, and can only be % called by functions in the file. Nested functions are defined within another % functions, and have access to both its workspace and their own workspace. % If you want to create a function without creating a new file you can use an % anonymous function. Useful when quickly defining a function to pass to % another function (eg. plot with fplot, evaluate an indefinite integral % with quad, find roots with fzero, or find minimum with fminsearch). % Example that returns the square of its input, assigned to the handle sqr: sqr = @(x) x.^2; sqr(10) % ans = 100 doc function_handle % find out more % User input a = input('Enter the value: ') % Stops execution of file and gives control to the keyboard: user can examine % or change variables. Type 'return' to continue execution, or 'dbquit' to exit keyboard % Reading in data (also xlsread/importdata/imread for excel/CSV/image files) fopen(filename) % Output disp(a) % Print out the value of variable a disp('Hello World') % Print out a string fprintf % Print to Command Window with more control % Conditional statements (the parentheses are optional, but good style) if (a > 23) disp('Greater than 23') elseif (a == 23) disp('a is 23') else disp('neither condition met') end % Looping % NB. looping over elements of a vector/matrix is slow! % Where possible, use functions that act on whole vector/matrix at once for k = 1:5 disp(k) end k = 0; while (k < 5) k = k + 1; end % Timing code execution: 'toc' prints the time since 'tic' was called tic A = rand(1000); A*A*A*A*A*A*A; toc % Connecting to a MySQL Database dbname = 'database_name'; username = 'root'; password = 'root'; driver = 'com.mysql.jdbc.Driver'; dburl = ['jdbc:mysql://localhost:8889/' dbname]; javaclasspath('mysql-connector-java-5.1.xx-bin.jar'); %xx depends on version, download available at http://dev.mysql.com/downloads/connector/j/ conn = database(dbname, username, password, driver, dburl); sql = ['SELECT * from table_name where id = 22'] % Example sql statement a = fetch(conn, sql) %a will contain your data % Common math functions sin(x) cos(x) tan(x) asin(x) acos(x) atan(x) exp(x) sqrt(x) log(x) log10(x) abs(x) %If x is complex, returns magnitude min(x) max(x) ceil(x) floor(x) round(x) rem(x) rand % Uniformly distributed pseudorandom numbers randi % Uniformly distributed pseudorandom integers randn % Normally distributed pseudorandom numbers %Complex math operations abs(x) % Magnitude of complex variable x phase(x) % Phase (or angle) of complex variable x real(x) % Returns the real part of x (i.e returns a if x = a +jb) imag(x) % Returns the imaginary part of x (i.e returns b if x = a+jb) conj(x) % Returns the complex conjugate % Common constants pi NaN inf % Solving matrix equations (if no solution, returns a least squares solution) % The \ and / operators are equivalent to the functions mldivide and mrdivide x=A\b % Solves Ax=b. Faster and more numerically accurate than using inv(A)*b. x=b/A % Solves xA=b inv(A) % calculate the inverse matrix pinv(A) % calculate the pseudo-inverse % Common matrix functions zeros(m,n) % m x n matrix of 0's ones(m,n) % m x n matrix of 1's diag(A) % Extracts the diagonal elements of a matrix A diag(x) % Construct a matrix with diagonal elements listed in x, and zeroes elsewhere eye(m,n) % Identity matrix linspace(x1, x2, n) % Return n equally spaced points, with min x1 and max x2 inv(A) % Inverse of matrix A det(A) % Determinant of A eig(A) % Eigenvalues and eigenvectors of A trace(A) % Trace of matrix - equivalent to sum(diag(A)) isempty(A) % Tests if array is empty all(A) % Tests if all elements are nonzero or true any(A) % Tests if any elements are nonzero or true isequal(A, B) % Tests equality of two arrays numel(A) % Number of elements in matrix triu(x) % Returns the upper triangular part of x tril(x) % Returns the lower triangular part of x cross(A,B) % Returns the cross product of the vectors A and B dot(A,B) % Returns scalar product of two vectors (must have the same length) transpose(A) % Returns the transpose of A fliplr(A) % Flip matrix left to right flipud(A) % Flip matrix up to down % Matrix Factorisations [L, U, P] = lu(A) % LU decomposition: PA = LU,L is lower triangular, U is upper triangular, P is permutation matrix [P, D] = eig(A) % eigen-decomposition: AP = PD, P's columns are eigenvectors and D's diagonals are eigenvalues [U,S,V] = svd(X) % SVD: XV = US, U and V are unitary matrices, S has non-negative diagonal elements in decreasing order % Common vector functions max % largest component min % smallest component length % length of a vector sort % sort in ascending order sum % sum of elements prod % product of elements mode % modal value median % median value mean % mean value std % standard deviation perms(x) % list all permutations of elements of x find(x) % Finds all non-zero elements of x and returns their indexes, can use comparison operators, % i.e. find( x == 3 ) returns indexes of elements that are equal to 3 % i.e. find( x >= 3 ) returns indexes of elements greater than or equal to 3 % Classes % MATLAB can support object-oriented programming. % Classes must be put in a file of the class name with a .m extension. % To begin, we create a simple class to store GPS waypoints. % Begin WaypointClass.m classdef WaypointClass % The class name. properties % The properties of the class behave like Structures latitude longitude end methods % This method that has the same name of the class is the constructor. function obj = WaypointClass(lat, lon) obj.latitude = lat; obj.longitude = lon; end % Other functions that use the Waypoint object function r = multiplyLatBy(obj, n) r = n*[obj.latitude]; end % If we want to add two Waypoint objects together without calling % a special function we can overload MATLAB's arithmetic like so: function r = plus(o1,o2) r = WaypointClass([o1.latitude] +[o2.latitude], ... [o1.longitude]+[o2.longitude]); end end end % End WaypointClass.m % We can create an object of the class using the constructor a = WaypointClass(45.0, 45.0) % Class properties behave exactly like MATLAB Structures. a.latitude = 70.0 a.longitude = 25.0 % Methods can be called in the same way as functions ans = multiplyLatBy(a,3) % The method can also be called using dot notation. In this case, the object % does not need to be passed to the method. ans = a.multiplyLatBy(1/3) % MATLAB functions can be overloaded to handle objects. % In the method above, we have overloaded how MATLAB handles % the addition of two Waypoint objects. b = WaypointClass(15.0, 32.0) c = a + b ``` ## More on MATLAB * [The official website](http://www.mathworks.com/products/matlab/) * [The official MATLAB Answers forum](http://www.mathworks.com/matlabcentral/answers/) * [Loren on the Art of MATLAB](http://blogs.mathworks.com/loren/) * [Cleve's Corner](http://blogs.mathworks.com/cleve/) ================================================ FILE: mercurial.md ================================================ --- category: tool name: Mercurial contributors: - ["Will L. Fife", "http://github.com/sarlalian"] filename: LearnMercurial.txt --- Mercurial is a free, distributed source control management tool. It offers you the power to efficiently handle projects of any size while using an intuitive interface. It is easy to use and hard to break, making it ideal for anyone working with versioned files. ## Versioning Concepts ### What is version control? Version control is a system that keeps track of changes to a set of file(s) and/or directorie(s) over time. ### Why use Mercurial? * Distributed Architecture - Traditionally version control systems such as CVS and Subversion are a client server architecture with a central server to store the revision history of a project. Mercurial however is a truly distributed architecture, giving each developer a full local copy of the entire development history. It works independently of a central server. * Fast - Traditionally version control systems such as CVS and Subversion are a client server architecture with a central server to store the revision history of a project. Mercurial however is a truly distributed architecture, giving each developer a full local copy of the entire development history. It works independently of a central server. * Platform Independent - Mercurial was written to be highly platform independent. Much of Mercurial is written in Python, with small performance critical parts written in portable C. Binary releases are available for all major platforms. * Extensible - The functionality of Mercurial can be increased with extensions, either by activating the official ones which are shipped with Mercurial or downloading some [from the wiki](https://www.mercurial-scm.org/wiki/UsingExtensions) or by [writing your own](https://www.mercurial-scm.org/wiki/WritingExtensions). Extensions are written in Python and can change the workings of the basic commands, add new commands and access all the core functions of Mercurial. * Easy to use - The Mercurial command set is consistent with what subversion users would expect, so they are likely to feel right at home. Most dangerous actions are part of extensions that need to be enabled to be used. * Open Source - Mercurial is free software licensed under the terms of the [GNU General Public License Version 2](http://www.gnu.org/licenses/gpl-2.0.txt) or any later version. ## Terminology | Term | Definition | | ------------- | ---------------------------------- | | Repository | A repository is a collection of revisions | | hgrc | A configuration file which stores the defaults for a repository. | | revision | A committed changeset: has a REV number | | changeset | Set of changes saved as diffs | | diff | Changes between file(s) | | tag | A named named revision | | parent(s) | Immediate ancestor(s) of a revision | | branch | A child of a revision | | head | A head is a changeset with no child changesets | | merge | The process of merging two HEADS | | tip | The latest revision in any branch | | patch | All of the diffs between two revisions | | bundle | Patch with permis­sions and rename support | ## Commands ### init Create a new repository in the given directory, the settings and stored information are in a directory named `.hg`. ```bash $ hg init ``` ### help Will give you access to a very detailed description of each command. ```bash # Quickly check what commands are available $ hg help # Get help on a specific command # hg help $ hg help add $ hg help commit $ hg help init ``` ### status Show the differences between what is on disk and what is committed to the current branch or tag. ```bash # Will display the status of files $ hg status # Get help on the status subcommand $ hg help status ``` ### add Will add the specified files to the repository on the next commit. ```bash # Add a file in the current directory $ hg add filename.rb # Add a file in a sub directory $ hg add foo/bar/filename.rb # Add files by pattern $ hg add *.rb ``` ### branch Set or show the current branch name. *Branch names are permanent and global. Use 'hg bookmark' to create a light-weight bookmark instead. See 'hg help glossary' for more information about named branches and bookmarks.* ```bash # With no argument it shows the current branch name $ hg branch # With a name argument it will change the current branch. $ hg branch new_branch marked working directory as branch new_branch (branches are permanent and global, did you want a bookmark?) ``` ### tag Add one or more tags for the current or given revision. Tags are used to name particular revisions of the repository and are very useful to compare different revisions, to go back to significant earlier versions or to mark branch points as releases, etc. Changing an existing tag is normally disallowed; use -f/--force to override. ```bash # List tags $ hg tags tip 2:efc8222cd1fb v1.0 0:37e9b57123b3 # Create a new tag on the current revision $ hg tag v1.1 # Create a tag on a specific revision $ hg tag -r efc8222cd1fb v1.1.1 ``` ### clone Create a copy of an existing repository in a new directory. If no destination directory name is specified, it defaults to the basename of the source. ```bash # Clone a remote repo to a local directory $ hg clone https://some-mercurial-server.example.com/reponame # Clone a local repo to a remote server $ hg clone . ssh://username@some-mercurial-server.example.com/newrepo # Clone a local repo to a local repo $ hg clone . /tmp/some_backup_dir ``` ### commit / ci Commit changes to the given files into the repository. ```bash # Commit with a message $ hg commit -m 'This is a commit message' # Commit all added / removed files in the current tree $ hg commit -A 'Adding and removing all existing files in the tree' # amend the parent of the working directory with a new commit that contains the # changes in the parent in addition to those currently reported by 'hg status', $ hg commit --amend -m "Correct message" ``` ### diff Show differences between revisions for the specified files using the unified diff format. ```bash # Show the diff between the current directory and a previous revision $ hg diff -r 10 # Show the diff between two previous revisions $ hg diff -r 30 -r 20 ``` ### grep Search revision history for a pattern in specified files. ```bash # Search files for a specific phrase $ hg grep "TODO:" ``` ### log / history Show revision history of entire repository or files. If no revision range is specified, the default is "tip:0" unless --follow is set, in which case the working directory parent is used as the starting revision. ```bash # Show the history of the entire repository $ hg log # Show the history of a single file $ hg log myfile.rb # Show the revision changes as an ASCII art DAG with the most recent changeset # at the top. $ hg log -G ``` ### merge Merge another revision into working directory. ```bash # Merge changesets to local repository $ hg merge # Merge from a named branch or revision into the current local branch $ hg merge branchname_or_revision # After successful merge, commit the changes hg commit ``` ### move / mv / rename Rename files; equivalent of copy + remove. Mark dest as copies of sources; mark sources for deletion. If dest is a directory, copies are put in that directory. If dest is a file, there can only be one source. ```bash # Rename a single file $ hg mv foo.txt bar.txt # Rename a directory $ hg mv some_directory new_directory ``` ### pull Pull changes from a remote repository to a local one. ```bash # List remote paths $ hg paths remote1 = http://path/to/remote1 remote2 = http://path/to/remote2 # Pull from remote 1 $ hg pull remote1 # Pull from remote 2 $ hg pull remote2 ``` ### push Push changesets from the local repository to the specified destination. ```bash # List remote paths $ hg paths remote1 = http://path/to/remote1 remote2 = http://path/to/remote2 # Pull from remote 1 $ hg push remote1 # Pull from remote 2 $ hg push remote2 ``` ### rebase Move changeset (and descendants) to a different branch. Rebase uses repeated merging to graft changesets from one part of history (the source) onto another (the destination). This can be useful for linearizing *local* changes relative to a master development tree. * Draft the commits back to the source revision. * -s is the source, ie. what you are rebasing. * -d is the destination, which is where you are sending it. ```bash # Put the commits into draft status # This will draft all subsequent commits on the relevant branch $ hg phase --draft --force -r 1206 # Rebase from from revision 102 over revision 208 $ hg rebase -s 102 -d 208 ``` ### revert Restore files to their checkout state. With no revision specified, revert the specified files or directories to the contents they had in the parent of the working directory. This restores the contents of files to an unmodified state and unschedules adds, removes, copies, and renames. If the working directory has two parents, you must explicitly specify a revision. ```bash # Reset a specific file to its checked out state $ hg revert oops_i_did_it_again.txt # Revert a specific file to its checked out state without leaving a .orig file # around $ hg revert -C oops_i_did_it_again.txt # Revert all changes $ hg revert -a ``` ### rm / remove Remove the specified files on the next commit. ```bash # Remove a specific file $ hg remove go_away.txt # Remove a group of files by pattern $ hg remove *.txt ``` ## Further information * [Learning Mercurial in Workflows](https://www.mercurial-scm.org/guide) * [Mercurial Quick Start](https://www.mercurial-scm.org/wiki/QuickStart) * [Mercurial: The Definitive Guide by Bryan O'Sullivan](http://hgbook.red-bean.com/) ================================================ FILE: mercury.md ================================================ --- name: Mercury contributors: - ["Julian Fondren", "https://mercury-in.space/"] --- Mercury is a strict, pure functional/logic programming language, with influences from Prolog, ML, and Haskell. ```prolog % Percent sign starts a one-line comment. % foo(Bar, Baz) % % Documentation comments are indented before what they describe. :- pred foo(bar::in, baz::out) is det. % All toplevel syntax elements end with a '.' -- a full stop. % Mercury terminology comes from predicate logic. Very roughly: % | Mercury | C | % | | | % | Goal | statement | % | expression | expression | % | predicate rule | void function | % | function rule | function | % | head (of a rule) | function name and parameters | % | body (of a rule) | function body | % | fact | (rule without a body) | % | pred/func declaration | function signature | % | A, B (conjunction) | A && B | % | A ; B (disjunction) | if (A) {} else if (B) {} | % some facts: man(socrates). % "it is a fact that Socrates is a man" man(plato). man(aristotle). % a rule: mortal(X) :- man(X). % "It is a rule that X is a mortal if X is a man." % ^^^^^^-- the body of the rule % ^^-- an arrow <--, pointing to the head from the body %^^^^^^^^-- the head of the rule % this is also a single clause that defines the rule. % that X is capitalized is how you know it's a variable. % that socrates is uncapitalized is how you know it's a term. % it's an error for 'socrates' to be undefined. It must have a type: % declarations begin with ':-' :- type people ---> socrates ; plato ; aristotle ; hermes. %<--first tab stop (using 4-space tabs) %<--third tab stop (first after --->) :- pred man(people). % rules and facts also require types % a rule's modes tell you how it can be used. :- mode man(in) is semidet. % man(plato) succeeds. man(hermes) fails. :- mode man(out) is multi. % man(X) binds X to one of socrates ; plato ; aristotle % a semidet predicate is like a test. It doesn't return a value, but % it can succeed or fail, triggering backtracking or the other side of % a disjunction or conditional. % 'is semidet' provides the determinism of a mode. Other determinisms: % | Can fail? | 0 solutions | 1 | more than 1 | % | | | | | % | no | erroneous | det | multi | % | yes | failure | semidet | nondet | :- pred mortal(people::in) is semidet. % type/mode in one declaration % this rule's body consists of two conjunctions: A, B, C % this rule is true if A, B, and C are all true. % if age(P) returns 16, it fails. % if alive(P) fails, it fails. :- type voter(people::in) is semidet. voter(P) :- alive(P), registered(P, locale(P)), age(P) >= 18. % age/1 is a function; int.>= is a function used as an operator % "a P is a voter if it is alive, is registered in P's locale, and if % P's age is 18 or older." % the >= used here is provided by the 'int' module, which isn't % imported by default. Mercury has a very small 'Prelude' (the % 'builtin' module). You even need to import the 'list' module if % you're going to use list literals. ``` Complete runnable example. File in 'types.m'; compile with 'mmc --make types'. ```prolog :- module types. :- interface. :- import_module io. % required for io.io types in... % main/2 is usually 'det'. threading and exceptions require 'cc_multi' :- pred main(io::di, io::uo) is cc_multi. % program entry point :- implementation. :- import_module int, float, string, list, bool, map, exception. % enum. :- type days ---> sunday ; monday ; tuesday ; wednesday ; thursday ; friday ; saturday. % discriminated union, like datatype in ML. :- type payment_method ---> cash(int) ; credit_card( name :: string, % named fields cc_number :: string, cvv :: int, expiration :: string ) ; crypto(coin_type, wallet, amount). :- type coin_type ---> etherium ; monero. % "other coins are available" % type aliases. :- type wallet == string. :- type amount == int. % !IO is the pair of io.io arguments % pass it to anything doing I/O, in order to perform I/O. % many otherwise-impure functions can 'attach to the I/O state' by taking !IO main(!IO) :- Ints = [ 3, 1 + 1, 8 - 1, 10 * 2, 35 / 5, 5 / 2, % truncating division int.div(5, 2), % floored division div(5, 2), % (module is unambiguous due to types) 5 `div` 2, % (any binary function can be an operator with ``) 7 `mod` 3, % modulo of floored division 7 `rem` 3, % remainder of truncating division 2 `pow` 4, % 2 to the 4th power (1 + 3) * 2, % parens have their usual meaning 2 >> 3, % bitwise right shift 128 << 3, % bitwise left shift \ 0, % bitwise complement 5 /\ 1, % bitwise and 5 \/ 1, % bitwise or 5 `xor` 3, % bitwise xor max_int, min_int, 5 `min` 3, % ( if 5 > 3 then 3 else 5 ) 5 `max` 3 ], Bools = [ yes, no % bools are much less important in Mercury because control flow goes by % semidet goals instead of boolean expressions. ], Strings = [ "this is a string", "strings can have "" embedded doublequotes via doubling", "strings support \u4F60\u597D the usual escapes\n", % no implicit concatenation of strings: "concat:" "together" "but you can " ++ " use the string.++ operator", % second param is a list(string.poly_type) % s/1 is a function that takes a string and returns a poly_type % i/1 takes an int. f/1 takes a float. c/1 takes a char. string.format("Hello, %d'th %s\n", [i(45), s("World")]) ], % start with purely functional types like 'map' and 'list'! % arrays and hash tables are available too, but using them % requires knowing a lot more about Mercury get_map1(Map1), get_map2(Map2), % list.foldl has *many* variations % this one calls io.print_line(X, !IO) for each X of the list foldl(io.print_line, Ints, !IO), foldl(io.print_line, Bools, !IO), foldl(io.print_line, Strings, !IO), io.print_line(Map1, !IO), % ( if Cond then ThenGoal else ElseGoal ) % I/O not allowed in Cond: I/O isn't allowed to fail! ( if Map2^elem(42) = Elem then io.print_line(Elem, !IO) else % always required true % do nothing, successfully (vs. 'fail') ), % exception handling: ( try [io(!IO)] ( % io/1 param required or no I/O allowed here io.print_line(received(cash(1234)), !IO), io.print_line(received(crypto(monero, "invalid", 123)), !IO) ) then io.write_string("all payments accepted\n", !IO) % never reached catch "monero not yet supported" -> % extremely specific catch! io.write_string("monero payment failed\n", !IO) ). :- pred get_map1(map(string, int)::out) is det. get_map1(!:Map) :- % !:Map in the head is the final (free, unbound) Map !:Map = init, % !:Map in the body is the next Map det_insert("hello", 1, !Map), % pair of Map vars det_insert("world", 2, !Map), % debug print of current (bound) Map % other [Params] can make it optional per runtime or compiletime flags trace [io(!IO)] (io.print_line(!.Map, !IO)), det_insert_from_corresponding_lists(K, V, !Map), % this code is reordered so that K and V and defined prior to their use K = ["more", "words", "here"], V = [3, 4, 5]. :- pred get_map2(map(int, bool)::out) is det. get_map2(Map) :- det_insert(42, yes, map.init, Map). :- func received(payment_method) = string. received(cash(N)) = string.format("received %d dollars", [i(N)]). received(credit_card(_, _, _, _)) = "received credit card". % _ is throwaway received(crypto(Type, _Wallet, Amount)) = S :- % _Wallet is named throwaway ( % case/switch structure Type = etherium, S = string.format("receiving %d ETH", [i(Amount)]) ; Type = monero, throw("monero not yet supported") % exception with string as payload ). ``` ## That was quick! Want more? ### More Tutorials * [Mercury Tutorial](https://mercurylang.org/documentation/papers/book.pdf) (pdf link) - a more traditional tutorial with a more relaxed pace * [Mercury Crash Course](https://mercury-in.space/crash.html) - a dense example-driven tutorial with Q&A format * [GitHub Wiki Tutorial](https://github.com/Mercury-Language/mercury/wiki/Tutorial) * [Getting Started with Mercury](https://bluishcoder.co.nz/2019/06/23/getting-started-with-mercury.html) - installation and your first steps ### Documentation * Language manual, user's guide, and library reference are all at [mercurylang.org](https://mercurylang.org/documentation/documentation.html) ================================================ FILE: messagepack.md ================================================ --- category: framework name: MessagePack filename: learnmessagepack.mpac contributors: - ["Gabriel Chuan", "https://github.com/gczh"] --- MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. The benefits over other formats is that it's faster and smaller. In MessagePack, small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves. This makes MessagePack useful for efficient transmission over wire. ``` # 0. Understanding The Structure ==== JSON, 40 Bytes UTF-8 ---------------------------------------------- | {"name":"John Doe","age":12} | ---------------------------------------------- | {" | 7B 22 | | name | 6E 61 6D 65 | | ":" | 22 3A 22 | | John Doe | 4A 6F 68 6E 20 44 6F 65 | | "," | 22 2C 22 | | age | 61 67 65 | | ": | 22 3A 20 | | 12 | 31 32 | | } | 7D | ---------------------------------------------- MessagePack, 27 Bytes UTF-8 ---------------------------------------------- | ‚¤name¨John Doe£age.12 | ---------------------------------------------- | ‚¤ | 82 84 | | name | 6E 61 6D 65 | | ¨ | A8 | | John Doe | 4A 6F 68 6E 20 44 6F 65 | | £ | A3 | | age | 61 67 65 | | . | 0C | | 12 | 31 32 | ---------------------------------------------- # 1. JAVA ==== """ Installing with Maven """ ... org.msgpack msgpack ${msgpack.version} ... """ Simple Serialization/Deserialization """ // Create serialize objects. List src = new ArrayList(); src.add("msgpack"); src.add("kumofs"); MessagePack msgpack = new MessagePack(); // Serialize byte[] raw = msgpack.write(src); // Deserialize directly using a template List dst1 = msgpack.read(raw, Templates.tList(Templates.TString)); System.out.println(dst1.get(0)); System.out.println(dst1.get(1)); // Or, Deserialize to Value then convert type. Value dynamic = msgpack.read(raw); List dst2 = new Converter(dynamic) .read(Templates.tList(Templates.TString)); System.out.println(dst2.get(0)); System.out.println(dst2.get(1)); # 2. RUBY ==== """ Installing the Gem """ gem install msgpack """ Streaming API """ # serialize a 2-element array [e1, e2] pk = MessagePack::Packer.new(io) pk.write_array_header(2).write(e1).write(e2).flush # deserialize objects from an IO u = MessagePack::Unpacker.new(io) u.each { |obj| ... } # event-driven deserialization def on_read(data) @u ||= MessagePack::Unpacker.new @u.feed_each(data) { |obj| ... } end # 3. NODE.JS ==== """ Installing with NPM """ npm install msgpack5 --save """ Using in Node """ var msgpack = require('msgpack5')() // namespace our extensions , a = new MyType(2, 'a') , encode = msgpack.encode , decode = msgpack.decode msgpack.register(0x42, MyType, mytipeEncode, mytipeDecode) console.log(encode({ 'hello': 'world' }).toString('hex')) // 81a568656c6c6fa5776f726c64 console.log(decode(encode({ 'hello': 'world' }))) // { hello: 'world' } console.log(encode(a).toString('hex')) // d5426161 console.log(decode(encode(a)) instanceof MyType) // true console.log(decode(encode(a))) // { value: 'a', size: 2 } function MyType(size, value) { this.value = value this.size = size } function mytipeEncode(obj) { var buf = new Buffer(obj.size) buf.fill(obj.value) return buf } function mytipeDecode(data) { var result = new MyType(data.length, data.toString('utf8', 0, 1)) , i for (i = 0; i < data.length; i++) { if (data.readUInt8(0) != data.readUInt8(i)) { throw new Error('should all be the same') } } return result } ``` # References - [MessagePack](http://msgpack.org/index.html) - [MsgPack vs. JSON: Cut your client-server exchange traffic by 50% with one line of code](http://indiegamr.com/cut-your-data-exchange-traffic-by-up-to-50-with-one-line-of-code-msgpack-vs-json/) ================================================ FILE: miniscript.md ================================================ --- name: MiniScript contributors: - ["Joe Strout", "https://github.com/JoeStrout"] filename: miniscript.ms --- **MiniScript** is a simple scripting language designed to be easily embedded in games and other software. It can also be used on the command line, or as a cross-platform game development environment via [Soda](https://github.com/JoeStrout/soda) or [Mini Micro](https://miniscript.org/MiniMicro). An easy way to get started with MiniScript is on the [Try-It! page](https://miniscript.org/tryit/), which runs MiniScript code on the server. Note however that the code on this page is limited to 2000 characters. (The tutorial scripts below are broken up into blocks 2048 characters or less so they will run on the Try-It! page.) Once you are ready to go beyond the Try-It! page, your next stop should probably be to download [Mini Micro](https://miniscript.org/MiniMicro), a free virtual computer that uses MiniScript both on the command line and in programs. In that environment, enter **edit** at the prompt to edit code, then click the Run button in the editor to run it. ``` print "Hello world" // MiniScript is very syntax-light. Notice that no parentheses are // needed on the print statement above. Comments begin with //, and // extend to the end of the line. MiniScript is case-sensitive. // CONTROL FLOW // Use if blocks to do different things depending on some condition. // Include zero or more else if blocks, and one optional else block. if 2+2 == 4 then print "math works!" else if pi > 3 then print "pi is tasty" else if "a" < "b" then print "I can sort" else print "last chance" end if // LOOPING // MiniScript has only two loop constructs: while loops and for loops. // Use a while block to loop as long as a condition is true. s = "Spam" while s.len < 50 s = s + ", spam" end while print s + " and spam!" // A for loop can loop over any list, including ones easily created // with the range function. for i in range(10, 1) print i + "..." end for print "Liftoff!" // Two additional keywords are useful inside loops. The break statement // jumps out of the nearest while or for loop. The continue statement // jumps to the top of the loop, skipping the rest of the current iteration. for i in range(1,100) if i % 3 == 0 then continue // skip multiples of 3 if i^2 > 200 then break // stop when i^2 is over 200 print i + " squared is " + i^2 end for ``` ### Numbers ``` // All numbers are stored in full-precision format. Numbers also // represent true (1) and false (0), and there are built-in keywords // (true and false) for those. a = 7 b = 3 ultimateAnswer = 42 pi = 3.14159 n = true m = false print ultimateAnswer + ", " + pi + ", " + n + ", " + m // Numbers support the following operators: print "Basic math:" print a + b // addition print a - b // subtraction print a * b // multiplication print a / b // division print a % b // modulo (remainder) print a ^ b // power print "Logic:" print n and m // logical "and" print n or m // logical "or" print not n // logical negation print "Comparisons:" print a == b // equality test (note == rather than = here!) print a != b // inequality print a > b // greater than print a >= b // greater than or equal print a < b // less than print a <= b // less than or equal ``` ### Strings ``` // Text is stored in strings of Unicode characters. Write strings // by surrounding them with quotes. If you need to include a // quotation mark in a string, type it twice. print "Hello, ""Bob""." a = "Hello" b = "Spam" // Strings support the following operators: print "String ""math"":" print a + b // string concatenation print b - "m" // string subtraction (chop) print b * 4 // string replication print a / 2 // string division print "Comparisons:" print a == b // equality test (note == rather than = here!) print a != b // inequality print a > b // greater than print a >= b // greater than or equal print a < b // less than print a <= b // less than or equal // Indexing and slicing in a string is done with an index (or two) // in square brackets. Use a 0-based index to count from the front, // or a negative index to count from the end. Get a slice (substring) // with two indices, separated by a colon. Either one may be omitted // to extend the slice to the beginning or end of the string. print "Indexing and slicing:" print a[0] // get a character, starting with 0 ("H") print a[1] // get second character ("e") print a[-1] // negative numbers count from the end ("o") print a[1:4] // get slice from 1 up to (but not including) 4 ("ell") print a[1:-1] // same as above, but using a negative index print a[1:] // get slice from 1 to the end ("ello") print a[:2] // get slice from beginning up to 2 ("He") // Note that strings in MiniScript are immutable. You can't reach // into a string and change what characters it contains (but you can // always create a new string with different characters). ``` ### Lists ``` // A list is an ordered sequence of values of any type. You can // iterate over a list with a for loop, or iterate over the indexes // using .indexes. x = ["alpha", "beta", "gamma", "delta"] for item in x print item end for for i in x.indexes print "x[" + i + "] is " + x[i] end for // Indexing and slicing in a list is exactly like a string: use a // 0-based index to count from the front, or a negative number to // count from the end. Get a slice (subset) of a list with two // indices, separated by a colon. Either one may be omitted // to extend the slice to the beginning or end of the list. print x[0] // alpha print x[-1] // delta print x[1:3] // [beta, gamma] print x[2:] // [gamma, delta] print x[:-1] // [alpha, beta, gamma] // Lists support the following operators: y = ["a", "be", "ce", "de"] print "List ""math"":" print x + y // list concatenation print y * 3 // list replication print x / 2 // list division print "Comparisons:" print x == y // equality test (note == rather than = here!) print x != y // inequality ``` ### Maps ``` // A map is a set of values associated with unique keys. Maps // are an extremely powerful and versatile data type, used to // represent data records, objects, sparse arrays, and much more. // Create a map with curly braces; get or set a single value // with square brackets. Keys and values may be any type. // ("Key" and "index" mean the same thing in the context of a map.) m = {1:"one", 2:"two"} print m[1] // one m[2] = "dos" // change the value associated with index 2 print m[2] // dos // In the special case where the key (index) is a string that // would be a valid variable name, there is an alternate to the // square-bracket syntax called dot syntax. Just put the key, // without quotes, after the map and a dot (period). m.pi = 3.14 // equivalent to: m["pi"] = 3.14 print m["pi"] // 3.14 m["e"] = 2.72 // equivalent to: m.e = 2.72 print m.e // 2.72 // Maps support only the + operator, which combines all the key/value // pairs from two maps into one. m1 = {1:"one", 2:"two"} m2 = {2:"dos", 3:"tres"} print m1 + m2 // map concatenation // You can iterate over the key/value pairs in a map with a for loop. // On each iteration, the variable will be itself a little map with // "key" and "value" indexes. for kv in m1+m2 print kv.key + " -> " + kv.value end for // Note that the order of key/value pairs in a map is undefined. // You should never rely on them appearing in a particular order // when you print or iterate over a map. ``` ### Functions ``` // Create a function in miniscript with a function...end function // block. In most cases you will assign the result to a variable // so you can call it later. If a function needs to return a // a result, do that with the return keyword. rollDie = function return ceil(rnd * 6) // return a random number from 1-6 end function print rollDie print rollDie // If it needs parameters, put them after function keyword inside // parentheses. Parameters may have default values. roll = function(numberOfDice, sides=6) sum = 0 for i in range(1, numberOfDice) sum = sum + ceil(rnd * sides) end for return sum end function print roll(2) // roll two 6-sided dice print roll(2,20) // roll two 20-sided dice // Variables are always local by default in MiniScript. The // variables i and sum in the function above are not accessible // outside the function, and disappear as soon as the function // returns. (We'll talk more about variable scope later.) // Parentheses are needed only if (1) you're passing arguments // (parameter values) to the function, and (2) you're using the // result as part of some larger statement. Notice how the first // example above, rollDie did not need any parentheses because we // weren't passing any arguments. Here's an example of a function // that, like the built-in print function, is used as a statement // by itself, and so does not need parentheses. doRoll = function(numberOfDice, sides=6) print "Rolling " + numberOfDice + "d" + sides + "..." sum = 0 for i in range(1, numberOfDice) roll = ceil(rnd * sides) print "You rolled a " + roll + "." sum = sum + roll end for print "Your total is: " + sum end function doRoll 3 // roll 3d6 -- note no parentheses needed doRoll 3, 8 // same here, but rolling 3d6 // If you ever need to refer to a function without invoking it, // you can do so with the @ operator. f = @doRoll // makes f refer to the same function as doRoll f 2,4 // rolls 2d4 ``` ### Classes and Objects ``` // MiniScript uses prototype-based inheritance. A class or object // is just a map with a special __isa entry that points to the // parent class. This is set automatically when you use the new // operator. Shape = {} // make a base class Shape.sides = 0 // give it 0 sides by default Square = new Shape // make a subclass of Shape called Square Square.sides = 4 // override the number of sides x = new Square // create an instance of the Square class print x.sides // 4, because x is a Square and Square.sides is 4 // A method is just a function stored in a class (map). These // are inherited through the __isa chain, just like other values. // Within a method, the keyword self refers to the object on which // the method was invoked (using dot syntax). This is how you // refer to data or methods on the object. Shape.describe = function print print "This is a " + self.sides + "-sided shape." end function x.describe // This is a 4-sided shape. // Methods may be overridden (again just like values). In a // subclass/instance method, you may use super to invoke the next // version of the method up the inheritance chain, while still // keeping self bound to the object this method was called on. Square.describe = function super.describe // first, do the standard description print "It looks very squarish." // then add this end function x.describe ``` ### More on Variable Scope ``` // Variables assignments in MiniScript always create or update // a local variable, i.e., one that exists only within the function // containing the assignment, unless dot syntax is used to specify // some other scope. x = 42 // here's a global variable called x f = function x = 1234 // make a local variable, also called x print "Inside the function, x is now " + x end function f print "Outside the function, x is " + x // In the example above, the assignment to x inside the function // has no effect on the global value of x, even though they happen // to have the same name. (This is a Good Thing because it helps // you avoid unintended side-effects in your code.) Global variables // are generally discouraged, but if you must update one inside // a function, you can use a "globals." prefix to do so. f = function print "Using the globals prefix..." globals.x = 1234 // update the global variable x print "Inside the function, x is now " + x end function f print "Outside the function, x is " + x // This is very similar to the "self." prefix used with // class methods; in both cases, you are giving a more specific // scope to a variable (which is really just specifying a map // to index into with dot syntax). // However there is an important difference: when READING (not // assigning to) a variable, if the variable name is not found // among the local variables, MiniScript will automatically look // for a global variable of that name. Thus no "globals." prefix // is needed when reading a variable, but only when assigning it. count = 0 addToCount = function(amount=1) globals.count = count + amount end function addToCount addToCount print "count is now: " + count // In the addToCount function above, note how we need the globals // prefix on the left-hand side of the assignment, since otherwise // it would create a local variable. But we don't need it on the // right-hand side, where we are merely reading the global value. ``` ### Handy Intrinsic Methods ``` // Intrinsic methods are ones that are built into MiniScript or its // environment. Particular MiniScript environments (e.g. Mini Micro, // Soda, command-line MiniScript, some game using MiniScript as an // embedded language, etc.) will probably add additional intrinsics. // But there is a core of about 50 intrinsics that should always be // available. // Here's a quick demo of some of the most commonly used ones. print abs(-42) // absolute value print pi // get value of pi (yep, this is built in!) print cos(pi) // cosine print sqrt(100) // square root print round(pi, 2) // round (to 2 decimal places) print char(65) // get Unicode character 65 print s = "Hello world!" print s.upper // convert to upper case print s.len // get length (number of characters) print s.replace("Hello", "Heya") // string substitution print s.split(" ") // split on spaces to make a list print s.remove("l") // remove first occurrence of "l" print a = range(2,15,3) // make a list: 2 through 10, in steps of 3 print "a: " + a print "a.len:" + a.len // get length (number of values) print "a.sum:" + a.sum // get sum of adding all values together print a.pop // pop off the last value print a.pull // pull off the first value print "popped and pulled: " + a a.push 99 // push a new item onto the end a.insert 0, 101 // insert a new item at index 0 print "after push and insert: " + a a.remove 2 // remove index 2 from the list print "after remove 2: " + a s = a.join("#") // make a string by joining values with # print s print m = {"one": "uno", "two": "dos", "three": "tres"} print m.hasIndex("one") // check whether a key exists print m.indexes // get all the indexes print m.values // get all the values m.remove "two" // remove an index (and its value) print m ``` ## Further Reading * [MiniScript.org website](https://miniscript.org/) — center of the MiniScript universe * [MiniScript Quick Reference](https://miniscript.org/files/MiniScript-QuickRef.pdf) — this tutorial, in one page * [MiniScript User's Manual](https://miniscript.org/files/MiniScript-Manual.pdf) — more in-depth documentation * [MiniScript Wiki](https://miniscript.org/wiki/) — community-driven documentation ================================================ FILE: mips.md ================================================ --- name: "MIPS Assembly" filename: MIPS.asm contributors: - ["Stanley Lim", "https://github.com/Spiderpig86"] --- The MIPS (Microprocessor without Interlocked Pipeline Stages) Assembly language is designed to work with the MIPS microprocessor paradigm designed by J. L. Hennessy in 1981. These RISC processors are used in embedded systems such as gateways and routers. [Read More](https://en.wikipedia.org/wiki/MIPS_architecture) ```asm # Comments are denoted with a '#' # Everything that occurs after a '#' will be ignored by the assembler's lexer. # Programs typically contain a .data and .text sections .data # Section where data is stored in memory (allocated in RAM), similar to # variables in higher-level languages # Declarations follow a ( label: .type value(s) ) form of declaration hello_world: .asciiz "Hello World\n" # Declare a null terminated string num1: .word 42 # Integers are referred to as words # (32-bit value) arr1: .word 1, 2, 3, 4, 5 # Array of words arr2: .byte 'a', 'b' # Array of chars (1 byte each) buffer: .space 60 # Allocates space in the RAM # (not cleared to 0) # Datatype sizes _byte: .byte 'a' # 1 byte _halfword: .half 53 # 2 bytes _word: .word 3 # 4 bytes _float: .float 3.14 # 4 bytes _double: .double 7.0 # 8 bytes .align 2 # Memory alignment of data, where # number indicates byte alignment # in powers of 2. (.align 2 # represents word alignment since # 2^2 = 4 bytes) .text # Section that contains # instructions and program logic .globl _main # Declares an instruction label as # global, making it accessible to # other files _main: # MIPS programs execute # instructions sequentially, where # the code under this label will be # executed first # Let's print "hello world" la $a0, hello_world # Load address of string stored # in memory li $v0, 4 # Load the syscall value (number # indicating which syscall to make) syscall # Perform the specified syscall # with the given argument ($a0) # Registers (used to hold data during program execution) # $t0 - $t9 # Temporary registers used for # intermediate calculations inside # subroutines (not saved across # function calls) # $s0 - $s7 # Saved registers where values are # saved across subroutine calls. # Typically saved in stack # $a0 - $a3 # Argument registers for passing in # arguments for subroutines # $v0 - $v1 # Return registers for returning # values to caller function # Types of load/store instructions la $t0, label # Copy the address of a value in # memory specified by the label # into register $t0 lw $t0, label # Copy a word value from memory lw $t1, 4($s0) # Copy a word value from an address # stored in a register with an # offset of 4 bytes (addr + 4) lb $t2, label # Copy a byte value to the # lower order portion of # the register $t2 lb $t2, 0($s0) # Copy a byte value from the source # address in $s0 with offset 0 # Same idea with 'lh' for halfwords sw $t0, label # Store word value into # memory address mapped by label sw $t0, 8($s0) # Store word value into address # specified in $s0 and offset of # 8 bytes # Same idea using 'sb' and 'sh' for bytes and halfwords. 'sa' does not exist ### Math ### _math: # Remember to load your values into a register lw $t0, num # From the data section li $t0, 5 # Or from an immediate (constant) li $t1, 6 add $t2, $t0, $t1 # $t2 = $t0 + $t1 sub $t2, $t0, $t1 # $t2 = $t0 - $t1 mul $t2, $t0, $t1 # $t2 = $t0 * $t1 div $t2, $t0, $t1 # $t2 = $t0 / $t1 (Might not be # supported in some versions of MARS) div $t0, $t1 # Performs $t0 / $t1. Get the # quotient using 'mflo' and # remainder using 'mfhi' # Bitwise Shifting sll $t0, $t0, 2 # Bitwise shift to the left with # immediate (constant value) of 2 sllv $t0, $t1, $t2 # Shift left by a variable amount # in register srl $t0, $t0, 5 # Bitwise shift to the right (does # not sign preserve, sign-extends # with 0) srlv $t0, $t1, $t2 # Shift right by a variable amount # in a register sra $t0, $t0, 7 # Bitwise arithmetic shift to # the right (preserves sign) srav $t0, $t1, $t2 # Shift right by a variable amount # in a register # Bitwise operators and $t0, $t1, $t2 # Bitwise AND andi $t0, $t1, 0xFFF # Bitwise AND with immediate or $t0, $t1, $t2 # Bitwise OR ori $t0, $t1, 0xFFF # Bitwise OR with immediate xor $t0, $t1, $t2 # Bitwise XOR xori $t0, $t1, 0xFFF # Bitwise XOR with immediate nor $t0, $t1, $t2 # Bitwise NOR ## BRANCHING ## _branching: # The basic format of these branching instructions typically follow #