Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
#!/usr/bin/env hy ; =========== ; Excersise 2 ; =========== ; ; .. contents:: ; ; Prelude ; ======= ; ; Instead of `Python <http://www.python.org/>`_ this solution uses `Hy ; <http://www.hylang.org/>`_ to solve the assignments. Hy is a Lisp dialect ; implemented in Python which can use the Python ecosystem, including the standard ; library and third party modules. It has many functions, macros, and special ; forms to provide Python's language features in a ”lispy” syntax. ; ; Let us start with some imports of macros and functions used. The ``factorial`` ; function is used to check the results of our own implementations in `assignment ; 5 b`_. ; ; .. code-block:: hylang (require [hy.contrib.loop [loop]]) (import [math [factorial sqrt]]) ; Assignment 1 ; ============ ; ; **Q** Read an integer from the command line (hint: ``input`` function). Double ; the number and if it is positive. Halve the number if it is negative. Print the ; result. ; ; **A** Asking the user for integer numbers is part of several of the assignments, ; this subproblem is solved its own function which repeatedly asks the user until ; a suitable input was made. ; ; .. code-block:: hylang (defn ask-for-integer [] (while True (try (setv result (int (input "Enter integer: "))) (except [ValueError] (print "Not a number, please try again.")) (else (break)))) result) ; .. admonition:: The DRY Principle ; ; Functions are one way to follow the DRY principle: „**D**\on't **R**\epeat ; **Y**\ourself“. Programmers strive to avoid redundancy in code and data. ; ; Testrun:: ; ; => (ask-for-integer) ; Enter integer: ; Not a number, please try again. ; Enter integer: x ; Not a number, please try again. ; Enter integer: 42 ; 42 ; ; The solution asks the user for a number with the ``ask-for-integer`` function ; just defined above and then prints the result of either dividing or multiplying ; the value by two. ; ; .. code-block:: hylang (defn assignment-1 [] (let [value (ask-for-integer)] (print ((if (neg? value) / *) value 2)))) ; Testrun:: ; ; => (assignment-1) ; Enter integer: 5 ; 10 ; => (assignment-1) ; Enter integer: -5 ; -2.5 ; ; Assignment 2 ; ============ ; ; **Q** Define a list of at least ten strings. Print every second string. ; ; **A** This seems straight forward. The function declares a list with the first ; ten letters of the alphabet, "a" to "j", and then uses ``take-nth`` to get every ; second element to ``print`` it. ; ; .. code-block:: hylang (defn assignment-2 [] (let [strings ["a" "b" "c" "d" "e" "f" "g" "h" "i" "j"]] (for [s (take-nth 2 strings)] (print s)))) ; Testrun:: ; ; => (assignment-2) ; a ; c ; e ; g ; i ; ; Assignment 3 ; ============ ; ; **Q** Read numbers from the command line. Add them up until 0 is entered. ; Afterwards print the sum. ; ; **A** As reading a sequence of numbers from the command line, with zero as end ; marker, is part of both this and `assignment 4`_ we write a short function for ; this. DRY again. ; ; First we inform the user what we expect and how the input can be ended. Then ; the function uses ``iter`` to create an iterable which repeatedly calls ; ``ask-for-integer`` defined in `assignment 1`_ until that function returns a ; zero. ; ; .. code-block:: hylang (defn ask-for-integers [] (print "Enter integers. Enter 0 to end.") (iter ask-for-integer 0)) ; Testrun:: ; ; => (list (ask-for-integers)) ; Enter integers. Enter 0 to end. ; Enter integer: 1 ; Enter integer: -2 ; Enter integer: x ; Not a number, please try again. ; Enter integer: 3 ; Enter integer: 0 ; [1, -2, 3] ; ; Now the actual function becomes trivial: Just sum the elements of the iterable ; returned by ``ask-for-integers``. ; ; .. code-block:: hylang (defn assignment-3 [] (print (sum (ask-for-integers)))) ; Testrun:: ; ; => (assignment-3) ; Enter integers. Enter 0 to end. ; Enter integer: 1 ; Enter integer: 2 ; Enter integer: 3 ; Enter integer: -4 ; Enter integer: 0 ; 2 ; ; Assignment 4 ; ============ ; ; **Q** Read numbers from the command line. Sum them up if they are positive, ; ignore them if they are negative and stop when 0 is entered. Use ``continue`` ; and ``break``! ; ; **A** The function starts by setting the local variable ``result`` to 0. ; Then it goes with a ``for`` loop over the numbers entered by the user based ; by repeatedly calling ``ask-for-integer`` defined in `assignment 1`_. ; ; For each ``value`` it then checks two conditions from the question and ; acts accordingly. If the value is 0 the ``for`` loop is left by ``break``. ; If the value is negative the loop ``continue``\s with the next value from ; the user. That leaves only positive values so the result is updated by adding ; the value to the current result at the end, if the loop was not left by ; ``break`` and the last expression was not skipped by ``continue``. ; ; .. code-block:: hylang (defn assignment-4 [] (setv result 0) (for [value (repeatedly ask-for-integer)] (if (zero? value) (break)) (if (neg? value) (continue)) (setv result (+ result value))) (print result)) ; Testrun:: ; ; => (assignment-4) ; Enter integer: 1 ; Enter integer: -2 ; Enter integer: 3 ; Enter integer: -4 ; Enter integer: 0 ; 4 ; ; The ``if``\s are ordered in a way there are no unneccessary checks made. ; First we check for zero because then the other two checks are irrelevant. ; Then the negativ check is made because if it is true we can skip the positive ; check. ; ; But wait, didn't we define ``ask-for-integers`` in `assignment 3`_ for ; repeatedly asking the user for numbers? Yes we did. But if we used it here we ; would have a hard time to justify the zero test and the ``break`` because ; ``ask-for-integers`` already stops at zero, so the first condition is never met ; and we have no use for ``break``. ; ; ``continue`` is also only neccessary because of the way the tests are odered and ; expressed. Instead of skipping the addition at the end of the ``for`` loop, we ; could reverse the test and only execute the addition if the result is positive. ; All this leads to a much simpler and shorter function: ; ; .. code-block:: hylang (defn assignment-4-simplified [] (setv result 0) (for [value (ask-for-integers)] (if (pos? value) (setv result (+ result value)))) (print result)) ; Testrun:: ; ; => (assignment-4-simplified) ; Enter integers. Enter 0 to end. ; Enter integer: 1 ; Enter integer: -2 ; Enter integer: 3 ; Enter integer: -4 ; Enter integer: 0 ; 4 ; ; A function which still is not the most elegant and concise way to solve this ; problem. We want to ``filter`` the numbers so only positive ones are summed. ; Extending the solution from `assignment 3`_ we get: ; ; .. code-block:: hylang (defn assignment-4-concise [] (print (sum (filter pos? (ask-for-integers))))) ; Testrun:: ; ; => (assignment-4-concise) ; Enter integers. Enter 0 to end. ; Enter integer: 1 ; Enter integer: -2 ; Enter integer: 3 ; Enter integer: -4 ; Enter integer: 0 ; 4 ; ; Assignment 5 ; ============ ; ; **Q** Try do solve at least one of `assignment 5 b`_ and `assignment 5 c`_, if ; you can (yes, they are a bit tougher!) ; ; Assignment 5 a ; -------------- ; ; **Q** Write a function which returns the absolute difference between two numbers ; `a` and `b`: \| `a`-`b` \|. Call the function for five combinations for `a` and ; `b`. ; ; **A** Given there is an ``abs`` function and the substraction is a very basic ; operation this almost seems to be too simple. ; ; .. code-block:: hylang (defn assignment-5-a [a b] (abs (- a b))) ; And a small function to test five pairs of numbers against their expected ; results. ; ; .. code-block:: hylang (defn test-assignment-5-a [] (for [[a b expected] [[1 2 1] [2 1 1] [2 2 0] [-1 1 2] [1 -1 2]]] (assert (= (assignment-5-a a b) expected)))) ; Testrun:: ; ; => (test-assignment-5-a) ; ; Assignment 5 b ; -------------- ; ; **Q** Write a function that computes and returns the factorial of any positive ; integer. Use either a ``for`` loop, a ``while`` loop, or recursion. Call the ; function for 13 and print the returned factorial to the console. ; ; **A** We don't just solve `assignment 5 b`_ *and* `5 c <assignment 5 c>`_ but ; also all three alternatives for looping: ``for``, ``while``, and recursion. Plus ; an implementation with no explicit code for looping at all, leveraging the power ; of the rich set of functional building blocks available in Python and therefore ; also in Hy. ; ; As factorial is defined for positive numbers only we start with a small function ; to check if a number is negative. It throws an ``ValueError`` exception if the ; number is negative and returns the number otherwise. The check is in an own ; function to avoid repeating the code in each of the following implementations. ; ; .. code-block:: hylang (defn check-positive [n] (if (neg? n) (raise (ValueError "value must be positive")) n)) ; Testrun:: ; ; => (check-positive 42) ; 42 ; => (check-positive -23) ; Traceback (most recent call last): ; ... ; ValueError: value must be positive ; => (check-positive 0) ; 0 ; ; ``factorial`` with ``for`` ; ^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; After initialising the result to 1 the ``for`` loop iterates over the range of ; integer numbers from 1 to the given number. The upper bound is checked if it is ; positive and the increased by 1 because ``range`` yields the range of numbers ; *excluding* the given endpoint. Within the loop all numbers are multiplied to ; the result. ; ; .. code-block:: hylang (defn assignment-5-b-1 [n] (setv result 1) (for [x (range 1 (inc (check-positive n)))] (setv result (* result x))) result) ; ``factorial`` with ``while`` ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; First the function checks if the given number is positive. Then the result is ; initialised with 1. As long as the number is greater that one, the result is ; multiplied with the current number, which is decreased by one before the next ; iteration of the loop starts. ; ; This is the most ”primitive”, imperative variant of the four alternatives ; presented here, as we had to spell out each step explicitly, in the exact order ; it is executed by the computer. Although the `recursive factorial`_ in the very ; next section has the same amount of expressions, the order of execution of each ; single one is not that obviously encoded, as initialising and updating the two ; variables looks more ”parallel” there. ; ; .. code-block:: hylang (defn assignment-5-b-2 [n] (check-positive n) (setv result 1) (while (> n 1) (setv result (* result n) n (dec n))) result) ; Recursive ``factorial`` ; ^^^^^^^^^^^^^^^^^^^^^^^ ; ; For recursion we use the ``loop`` and ``recur`` macros. ``loop`` is used to ; define and call an anonymous function and ``recur`` calls this function ; recursively. The advantage of ``loop`` and ``recur`` over defining an ordinary ; function is that those macros do a little extra work to do `tail call ; optimization`_ (TCO) for which the function must be tail recursive. ; ; .. _tail call optimization: ; https://stackoverflow.com/questions/310974/what-is-tail-call-optimization#310980 ; ; The recursive function gets the number to calculatue the factorial of and the ; result which is given as 1 at the first call. If the number is smaller than 1 ; the result is returned, else the function is called recursively with the number ; decreased by one and the accumulated result mulipliplied by the (non-decreased) ; number. ; ; .. code-block:: hylang (defn assignment-5-b-3 [n] (loop [[i (check-positive n)] [result 1]] (if (< i 1) result (recur (dec i) (* result i))))) ; Without ``loop`` and ``recur`` it would look like this and there would be no ; TCO: ; ; .. code-block:: hylang (defn assignment-5-b-3-without-loop [n] (let [f (fn [i result] (if (< i 1) result (f (dec i) (* result i))))] (f (check-positive n) 1))) ; ``factorial`` with functional building blocks ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; Practising different kind of looping techniques and learning when to use them is ; important. So is knowing the functional building blocks to write concise and ; elegant solutions without explicit loops. Here we can use ``reduce``. It takes ; a binary function, an iterable of values, and an initial value, and applies the ; given function to each of the values from the iterable, using the call from the ; last result as first argument — or the given initial argument for the very first ; call. ; ; .. code-block:: hylang (defn assignment-5-b-4 [n] (reduce * (range 1 (inc (check-positive n))) 1)) ; Testing ``factorial`` ; ^^^^^^^^^^^^^^^^^^^^^ ; ; For testing all the factorial implementations we first calculate the expected ; result by means of the ``factorial`` function from the ``math`` module. Then ; all four variations defined above will be called an their result is ; ``assert``\ed to be the expected. ; ; .. code-block:: hylang (defn test-assignment-5-b [] (let [n 13 expected (factorial n)] (for [f [assignment-5-b-1 assignment-5-b-2 assignment-5-b-3 assignment-5-b-4]] (let [result (f n)] (assert (= result expected)) (print result))))) ; Testrun:: ; ; => (test-assignment-5-b) ; 6227020800 ; 6227020800 ; 6227020800 ; 6227020800 ; ; Assignment 5 c ; -------------- ; ; **Q** Write a function that decomposes any positive integer into its prime ; factors and returns them as a list. Call the function for 12341234 and print the ; list of prime factors to the console. ; ; **A** The basic idea for a solution is to to test numbers from 2 on upwards as ; candidates for (prime) factors and each time a candidate divides the number ; without a remainder to take the quotient as new number and note down the ; candidate as a prime factor. Although it seems tempting to determine prime ; numbers upfront to test them as factors, that step would not be necessary and ; will not speed up the solution unless we would cache those prime numbers for ; multiple calls to the function. ; ; The implementation uses two simple optimizations: ; ; * We do not test every number from 2 on upwards but just 2 and then every *odd* ; number greater than 2; ; ; * and we do not test the numbers up to the current number we want to factor but ; just until the candidate reaches the square root of that number, as between ; that and the number there can not be another factor. ; ; First we create an iterable with the candidates by chaining the list containing ; the 2 and an iterable counting from 3 on in steps of 2. In other words odd ; numbers. ; ; Then we start a loop function with the number, its square root as upper limit ; for the candidates, and an empty list for the result as arguments. ; ; After getting the next candidate it is checked against the current limit value. ; If the limit is lower than the candidate we are done and know the current number ; is itself the last prime factor needing to be ``cons``\ed to the result and ; being the result of the function. ; ; Otherwise the quotient and the remainder for the number and the candidate are ; calculated. If the remainder is zero the loop function is called recursively ; with the quotient as the new number to factor, its square root as new limit and ; a result that is extended by the candidate. For a non-zero remainder the loop ; function is called with the same arguments from the previous call to check the ; next candidate. ; ; .. code-block:: hylang (defn assignment-5-c [n] (let [candidates (chain [2] (count 3 2))] (loop [[number n] [limit (sqrt n)] [result []]] (let [candidate (next candidates)] (if (< limit candidate) (cons number result) (let [[quotient remainder] (divmod number candidate)] (if (zero? remainder) (recur quotient (sqrt quotient) (cons candidate result)) (recur number limit result)))))))) ; The result to test against was calculated with the linux command line tool ; ``factor``. As ``cons`` prepends elements to the list, the comparison value ; goes from the highest to the lowest prime factor. ; ; .. code-block:: hylang (defn test-assignment-5-c [] (let [result (assignment-5-c 12341234)] (assert (= result [617 137 73 2])) (print result))) ; Testrun:: ; ; => (test-assignment-5-c) ; [617, 137, 73, 2] ; ; .. pylit.py --comment-string='; ' -m '.. code-block:: hylang' -c test.hy ; .. pylit.py --comment-string='; ' -m '.. code-block:: hylang' -t test.hy.txt ; .. rst2pdf -c --footer '###Page###' -e dotted_toc test.hy.txt
Optional Paste Settings
Category:
None
Cryptocurrency
Cybersecurity
Fixit
Food
Gaming
Haiku
Help
History
Housing
Jokes
Legal
Money
Movies
Music
Pets
Photo
Science
Software
Source Code
Spirit
Sports
Travel
TV
Writing
Tags:
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
Decentralized Moneys
43 min ago | 0.42 KB
120 million in 5 years
1 hour ago | 0.12 KB
December smells like money
1 hour ago | 0.07 KB
Crypto Liquidity Pools
2 hours ago | 0.47 KB
Trustless Finance
2 hours ago | 0.51 KB
The Lunar Kitsune - Yohana Tsukiko
3 hours ago | 21.38 KB
Crypto profits are insane
3 hours ago | 0.12 KB
Decentralized Money
3 hours ago | 0.42 KB
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the
Cookies Policy
.
OK, I Understand
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!