
Embrace the Ideal: Never Give Up
In this mortal life, striving for the ideal is essential despite the gap between ideal and reality. Remember Elder Dieter F. Uchtdorf's words and stay resilient. Explore evaluation functions, applying operators, and declarative programming concepts along the way.
Download Presentation

Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.
E N D
Presentation Transcript
Dont Give Up on the Ideal [I]n this mortal life, we rarely get to experience the ideal. And until the perfect day, there will always be a gap between the ideal and the real. So, what should we do ? One thing we should not do is give up on the ideal! - Elder Dieter F. Uchtdorf By This All Will Know That You Are My Disciples Apr. 2025 Gen. Conf.
The eval() function The eval function computes the value of an expression. It is a generic function that behaves according to the type of the expression (primitive or call). You'll use isinstance() to check the type It recursively calls itself when it encounters sub-expressions (/ 3 (+ 4 5)) this generates a recursive call If you have just an operator and operands as values, you call the apply() function to apply the operator to the operands
Applying built-in operators The apply function applies some operation to a (Calculator) list of argument values In calculator, all operations are named by built-in operators: +, -, *, / Implementation Language semantics def calc_apply(operator, args): if operator == '+': return reduce(add, args, 0) elif operator == '-': ... elif operator == '*': ... elif operator == '/': ... else: raise TypeError + Sum of the arguments - ... * ... / ...
(/ 3 (+ 4 5)) Pair('/', Pair(3, Pair(Pair('+', Pair(4, Pair(5, nil))), nil))) The Calculator eval() algorithm (* 3 (+ 4 5) (* 6 7 8)) 1. If the expression is a primitive (int or float), we just return the value 2. If the expression is a Pair object it is some sort of expression 1. Get the operator from the first item of the Pair object 2. Call eval() on the first item of each Pair in the rest of the expression, building a Pair list with the operands as the values. 3. Call the apply() function passing in the operator and the results of step 2.2. 4. Return the result of the apply() function from the previous step. 3. If the expression is not a primitive or a Pair, raise a TypeError exception.
Regular Expressions & Efficiency
Declarative programming (review) In imperative languages: A "program" is a description of computational processes The interpreter carries out execution/evaluation rules In declarative languages: A "program" is a description of the desired result The interpreter figures out how to generate the result
Domain-specific languages Many declarative languages are domain-specific: they are designed to tackle problems in a particular domain, instead of being general purpose multi-domain programming languages. Language Domain Regular expressions Pattern-matching strings Backus-Naur Form Parsing strings into parse trees SQL Querying and modifying database tables HTML Describing the semantic structure of webpage content CSS Styling webpages based on selectors Prolog Describes and queries logical relations
Pattern matching Pattern matching in strings is a common problem in computer programming. An imperative approach: def is_email_address(str): parts = str.split('@') if len(parts) != 2: return False domain_parts = parts[1].split('.') return len(domain_parts) >= 2 and len(domain_parts[-1]) == 3 An equivalent regular expression: (.+)@(.+)\.(.{3}) With regular expressions, a programmer can just describe the pattern using a common syntax, and a regular expression engine figures out how to do the pattern matching for them.
Matching exact strings The following are special characters in regular expressions: \ ( ) [ ] { } + * ? | $ ^ . To match an exact string that has no special characters, just use the string: Provo, UT 84602 Matches: Provo, UT 84602 But if the matched string contains special characters, they must be escaped using a backslash. \(1\+3\) Matches: (1+3)
The dot The . character matches any single character that is not a new line. .a.a.a Matches: banana It also matches: Canada It's typically better to match a more specific range of characters, however..
Character classes Pattern Description Denotes a character class. Matches characters in a set (including ranges of characters like 0-9). Use [^] to match characters outside a set. Matches any character other than the newline character. Matches any digit character. Equivalent to [0-9]. \D is the complement and refers to all non-digit characters. Matches any word character. Equivalent to [A-Za-z0-9_]. \W is the complement. Example Matches: t , o, or p [] [top] 1?, 12, 1!, 1B, . 1. 12, 62, 20 \d \d\d 11, 1A, 3F \w \d\w 7 a, 3 Z, 4 F Matches any whitespace character: spaces, tabs, or line breaks. \S is the complement. \s \d\s\w
Quantifiers These indicate how many of a character/character class to match. Pattern Description Example Matches: a , aa, aaa, * a* Matches 0 or more of the previous pattern lol, lool, loool, + lo+l Matches 1 or more of the previous pattern. ll, lol, lool ? lo?l Matches 0 or 1 of the previous pattern. Used like {Min, Max}. Matches a quantity between Min and Max of the previous pattern. If only a single number is given, it must have exactly that number of characters a, aa, aaa, aaaa, aaaaa {} a{2,4}
Anchors These don't match an actual character; they indicate the position where the surrounding pattern should be found. Pattern Description Example Matches: aww aw ^ ^aw+ Matches the beginning of a string Stay away $ \w+y$ Matches the end of a string. Matches a word boundary, the beginning or end of a word. A blue tent \b \w+e\b
Combining patterns Patterns P and P can be combined in various ways. Combination Description Example Matches: A match for P followed immediately by one for P . ab. or ab, ab[.,] P P Matches anything that either P or P does. 1, 12, 523, Inf, \d+|Inf P |P Matches whatever P does. Parentheses group, just as in arithmetic expressions. <3, <3<3, <3<3<3, (<3)+ (P )
Support for regular expressions Regular expressions are supported natively in many languages and tools. Languages: Perl, ECMAScript, Java, Python, .. Tools: Excel/Google Spreadsheets, SQL, BigQuery, VSCode, grep, ...
Raw strings In normal Python strings, a backslash indicates an escape sequence, like \n for new line or \b for bell. >>> print("I have\na newline in me.") I have a newline in me But backslash has a special meaning in regular expressions. To make it easy to write regular expressions in Python strings, use raw strings by prefixing the string with an 'r': pattern = r"\b[ab]+\b"
The re module The re module provides many helpful functions. Function Description returns a match object representing the first occurrence of pattern within string re.search(pattern, string) returns a match object, requiring that pattern matches the entirety of string re.fullmatch(pattern, string) returns a match object, requiring that string starts with a substring that matches pattern re.match(pattern, string) returns a list of strings representing all matches of pattern within string, from left to right re.findall(pattern, string) substitutes all matches of pattern within string with repl re.sub(pattern, repl, string)
Match objects The functions re.match, re.search, and re.fullmatch all take a string containing a regular expression and a string of text. They return either a Match object or, if there is no match, None. re.fullmatch requires that the pattern matches the entirety of the string: import re re.fullmatch(r'-?\d+', '123') # <re.Match object> re.fullmatch(r'-?\d+', '123 peeps') # None Match objects are treated as true values, so you can use the result as a boolean: bool(re.fullmatch(r'-?\d+', '123')) # True bool(re.fullmatch(r'-?\d+', '123 peeps')) # False
Inspecting a match re.search returns a match object representing the first occurrence of pattern within string. title = "I Know Why the Caged Bird Sings" bool(re.search(r'Bird', title)) # True Match objects also carry information about what has been matched. The .group() method allows you to retrieve it. x = "This string contains 35 characters." mat = re.search(r'\d+', x) mat.group(0) # '35'
Match groups If there are parentheses in a patterns, each of the parenthesized groups will become groups in the match object. x = "There were 12 pence in a shilling and 20 shillings in a pound." mat = re.search(r'(\d+)[a-z\s]+(\d+)', x) mat.group(0) mat.group(1) mat.group(2) mat.groups() # '12 pence in a shilling and 20' # '12' # '20' # ('12', '20')
Finding multiple matches re.findall() returns a list of strings representing all matches of pattern within string, from left to right. locations = "AL 36362, MD 21221, UT 84660" re.findall(r'\d\d\d\d\d', locations) # ['36362', '21221', '84660']
Reusing a Regular Expression Often, we may want to reuse a regular expression on multiple strings. When that is the case, we can use the compile() function to create a regular expression object that can be reused regex = re.compile(r'\d{5}') The same functions we saw in the previous slides can be called on this object, but we no longer need to pass in the expression, it already knows what that is locations = "AL 36362, MD 21221, UT 84660" regex.findall(locations) # ['36362', '21221', '84660'] locations2 = "UT 84602, MD 20740, CA 94043" regex.findall(locations2) # ['84602', '20740', '94043'] This can be more efficient as it only has to figure out how to identify the string once, instead of recreating it each time we call the function.
Ambiguous matches Regular expressions can match a given string in more than one way. Especially when there are parenthesized groups, this can lead to ambiguity: mat = re.match(r'wind|window', 'window') mat.group() # 'wind' mat = re.match(r'window|wind', 'window') mat.group() # 'window' mat = re.match(r'(wind|window)(.*)shade', 'window shade') mat.groups() # ('wind', 'ow ') mat = re.match(r'(window|wind)(.*)shade', 'window shade') mat.groups() # ('window', ' ') Python resolves these particular ambiguities in favor of the first option.
Ambiguous quantifiers Likewise, there is ambiguity with *, +, and ?. mat = re.match(r'(x*)(.*)', 'xxx') mat.groups() # ('xxx', '') mat = re.match(r'(x+)(.*)', 'xxx') mat.groups() # ('xxx', '') mat = re.match(r'(x?)(.*)', 'xxx') mat.groups() # ('x', 'xx') mat = re.match(r'(.*)/(.+)', '12/10/2020') mat.groups() # ('12/10', '2020') Python chooses to match greedily, matching the pattern left-to-right and, when given a choice, matching as much as possible while still allowing the rest of the pattern to match.
Lazy operators Sometimes, you don t want to match as much as possible. The lazy operators *?, +?, and ?? match only as much as necessary for the whole pattern to match. mat = re.match(r'(.*)(\d*)', 'I have 5 dollars') mat.groups() # ('I have 5 dollars', '') mat = re.match(r'(.*?)(\d+)', 'I have 5 dollars') mat.groups() # ('I have ', '5') mat = re.match(r'(.*?)(\d*)', 'I have 5 dollars') mat.groups() # ('', '') The ambiguities introduced by *, +, ?, and |don t matter if all you care about is whether there is a match!
A word of caution Regular expressions can be very useful. However: Very long regular expressions can be difficult for other programmers to read and modify. See also: Write-only Since regular expressions are declarative, it's not always clear how efficiently they'll be processed. consuming, it can take down a server. Some processing can be so time- Regular expressions can't parse everything! Don't write an HTML parser with regular expressions.
Exponentiation approach #1 Based on this recursive definition: ?? ? = 0 ?? ?????? 1 ??= ? ?? 1 def exp(b, n): if n == 0: return 1 else: return b * exp(b, n-1) How many calls required to calculate exp(2,16)? Can we do better?
Exponentiation approach #2 Based on this recursive definition: 1 1 2?)2 ?? ? = 0 ?? ? ?? ???? ?? ? ?? ??? ??= (? ? ?(? 1) square = lambda x: x * x def exp_fast(b, n): if n == 0: return 1 elif n % 2 == 0: return square(exp_fast(b, n//2)) else: return b * exp_fast(b, n-1) How many calls required to calculate exp(2,16)? Some algorithms are more efficient than others!