Pycub
13 subscribers
3 photos
2 files
10 links
Experiences of a purely functional mind in a statically typed body.

https://github.com/pycub
Download Telegram
Channel created
Software related stuff; mostly Haskell, Python, and Rust.
1. Transformation on data
2. Referential transparency
2. Type inference
3. Zero side-effects

#haskell
اولین روز که با Haskell آشنا شدم، یکی از افرادی که برای مدت زیادی الگوی خودم قرار داده بودمش این دو خط بالا رو کشید که نمایانگر learning curve که قراره انتظارش رو بکشم بود. من همون روز میدونستم که قراره چقدر از عمرم رو پای این زبان بگذارم.
واقعا شیرین ترین زبانی هست که باهاش کد زدم.
به احترام ایشون من از دست خط اشون اسکرین شات گرفتم و ترجیح دادم که اینجا توی این کانال بمونه.

حالا که دارم صحبت میکنم دوتا مصاحبه Haskell موفق داشتم و یک پیشنهاد کار.
خیلی خوشحالم ازین بابت که ایشون من رو توی این مسیر قرار دادن. علی‌رغم ارتباط کمی که با ایشون دارم همیشه در یاد من خواهند موند.
2. Starting Out

1. : cons operator
2. [1,2,3] is actually just syntactic sugar for 1:2:3:[]
3. To get an element out of a list by index, use !!.
4. When comparing lists, they are compared in lexicographical order. (نظم واژگانی)
5. Some exceptions cannot be caught on compile time. e.g. head []
6. Use null [] instead of [] == [].
7. Ranges are a way of making lists that are arithmetic sequences of elements that can be enumerated.
8. List comprehension are derived from set comprehensions in mathematics. let foo = [OUTPUT FUNCTION | INPUT(s), PREDICATE(s)]
9. Tuples care about other tuples.
10. Tuple are heterogeneous.
3. Types and Typeclasess


1. Type inference: If we write a number, we don't have to tell Haskell it's a number. Haskell can infer the type itself.
2. Given :t foo, :: is read as has type of.
3. Type variable: means that a can be of any type. (Generics).
4. Functions that have type variables are called polymorphic functions.
5. Type Class: A typeclass is a sort of interface that defines some behavior. If a type is a part of a typeclass, that means that it supports and implements the behavior the typeclass describes.
6. Class constraint, everything before => is called class constraints.


Notes
- Get better understanding of type vs typeclass. manually define it!
4. Syntax in functions


1. Order is important when specifying patterns and it's always best to specify the most specific ones first and then the more general ones later.
2. When making patterns, we should always include a catch-all pattern so that our program doesn't crash if we get some unexpected input.
3. as patterns: are a handy way of breaking something up according to a pattern and binding it to names whilst still keeping a reference to the whole thing. capital all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]
4. Guards: A guard is basically a boolean expression which tests some property of value is true or false.
5. Guards can accept multiple parameters.
6. In order to prevent code duplication you can use where to bind some values to your guards.
7. Where can be splitted into multiple lines.
8. Where allow pattern matching.
9. Where can be used to nicely in conjunction with list comprehensions as output function.
10. Let general form is: let <bindings> in <expression>
11. General form for case expression:
case expression of pattern -> result  
pattern -> result
pattern -> result




- Where binding: Where bindings are a syntactic construct that let you bind to variables at the end of a function and the whole function can see them, including all the guards.
- Let bindings: Let bindings let you bind to variables anywhere and are expressions themselves, but are very local, so they don't span across guards.
- Where vs. Let: The difference is that let bindings are expressions themselves. where bindings are just syntactic constructs


Note
1. What does it mean when we say let bindings are expressions?
2. What does it mean when we say where bindings are syntactic constructs?
Rust Generics

- concrete type vs. genetic type
- type parameter
- generic type parameter
- Generic functions read as: the function largest is generic over some type T.
- restricting the types valid for T
- how to specify constraints on generic types?
- How to implement a method only for f32 instances? impl Point<f32> vs impl Point<T>.
- Is there any performance downside upon using generics? monomorphization

#Rust
# Rust module system

What is a module?
A module is a collection of items: functions, structs, traits, impl blocks, and even other modules.

Visibility
By default, the items in a module have private visibility, but this can be overridden with the pub modifier.
Only the public items of a module can be accessed from outside the module scope.
Box<T>

The most straightforward smart pointer is a box. Boxes allow you to store data on the heap rather than the stack. What remains on the stack is the pointer to the heap data.
Cases you would use Box smart pointer:
- When you have a type whose size can’t be known at compile time and you want to use a value of that type in a context that requires an exact size
- When you have a large amount of data and you want to transfer ownership but ensure the data won’t be copied when you do so
- When you want to own a value and you care only that it’s a type that implements a particular trait rather than being of a specific type

fn main() {
let b = Box::new(5);
println!("b = {b}");
}


use crate::List::{Cons, Nil};

fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}


#Rust #smartpointer
Computing the Size of a Type

Non-Recursive
Given
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}

To determine how much space to allocate for a Message `value, Rust goes through each of the variants to see which variant needs the most space. Rust sees that `Message::Quit `doesn’t need any space, `Message::Move needs enough space to store two i32 values, and so forth. Because only one variant will be used, the most space a Message value will need is the space it would take to store the largest of its variants.

Recursive
Contrast this with what happens when Rust tries to determine how much space a recursive type like the List enum needs. The compiler starts by looking at the Cons variant, which holds a value of type i32 and a value of type List. Therefore, Cons needs an amount of space equal to the size of an i32 plus the size of a List. To figure out how much memory the List type needs, the compiler looks at the variants, starting with the Cons variant. The Cons variant holds a value of type i32 and a value of type List, and this process continues infinitely

Because Rust can’t figure out how much space to allocate for recursively defined types, the compiler gives an error with this helpful suggestion:

help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
2 | Cons(i32, Box<List>),
| ++++ +


enum List {
Cons(i32, Box<List>),
Nil,
}

use crate::List::{Cons, Nil};

fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}


# Rust