50 views

Skip to first unread message

Feb 27, 2018, 7:32:15 AM2/27/18

to Melbourne Scala User Group

Hi everyone,

Thanks very much for attending - in my mind while writing it - it went a lot better than I think I managed to deliver...

Oh well - brain injuries - what can you do!!!!

I hope you were able to get something from it.

Please find below a link for the slides and notes;

Also,

At the end of the meeting, Oles was kind enough to give me some extra feedback of the presentation that I found really helpful and wished I had included.

I guess the benefit of a PhD and the job of lecturing about FP with Scala at university can give some great insight! - Thanks very much Oles.

I asked Oles if he would mind sharing his comments into this thread - for everyone to share - which he thankfully and happily said "Yes" : over to you Oles!

Mar 1, 2018, 7:39:19 PM3/1/18

to Melbourne Scala User Group

Hi Gevin,

The presentation took us on your journey of "getting" the functional programming and many personal references made it very engaging for me -- thank you!

The feedback below is not about the presentation per se, but only some of the specific points in the presented material. Albert Einsteins once said "The more I learn, the more I realise how much I don't know", and this is exactly my experience -- the depth of the subject of computation is... I want to say "bottomless", but one could say it has a bottom (https://wiki.haskell.org/Bottom) (:. And it is always the case that when presenting something, we're effectively forced to cut at some level to stay "on time". Therefore, I appreciate that some of the items below where potentially omitted/avoided purposefully.

1. In discussing immutability it is easy to lead the listener to believe that the use of "val" ensures immutability. However, naming abstraction "val" simply creates an immutable reference to a value. But is the value immutable? If it is not, then even by using "val", immutability is not present. One could even argue that using "var" referencing an immutable value has much stronger guarantees of immutability.

2. If a type system is not expressive enough then we cannot rely only on type signature to "understand" 100% what is expected of a function. If a type system is expressive enough, such as in Idris (https://www.idris-lang.org/), we have different problems -- the complexity of type expressions may result in difficulty to read them and leads to different kinds of errors. A reasonable alternative is the use of pre-conditions, which in combination with type signatures are expressive enough and remain quite readable. Another very interesting approach is taken by Clojure in a form of Clojure Spec (https://clojure.org/about/spec).

3. Currying is a convenient technique to define HOFs that return functional values (i.e. return a function as their result). An alternative is to declare complex return types that represent HOFs and use inner functions to compute return values -- that is tedious. Currying simplifies this with a convenient syntax by automating type inferencing based on lists of function arguments.

4. A function purity is not violated by a local mutation. The provided example of a function using "for" and "var" represents a pure function. Mutation is not evil per se. In fact, a locally scoped mutation is often a good optimisation technique -- after all we're computing on von Neumann machines (:

5. It is important to differentiate between function definitions and computational processes they generate. This is a simple, but not an easily observable difference -- in casual conversations we often conflate recursive definitions of functions with "what they do" computation wise. A recursive definition generates either a recursive process or an iterative process. And so we know that a tail-recursive definition generates an iterative process, while non-tail recursive definition generates a recursive process. SICP covers this subject, as many other re functional programming, extremely well (https://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2).

6. Pattern matching is a technique for data destructuring. In order to appreciate its usefulness, it is worthwhile using something that would have more than two patterns to match, which cannot be easily emulated with a single "if/else". Otherwise, especially for those that are considering/evaluating whether they want to start using the functional paradigm, it is very easy to dismiss the power of data destructuring with pattern matching.

Some less relevant, but potentially thought-provoking remarks:

1. Unlike functional analysis, λ-calculus is not really about the study of functions, but rather the process of computation and computability, and like the abstract Turing Machine, is a universal model for computation. A curios fact is that functions in λ-calculus are lambdas -- have no names. How could such functions be defined recursively?! It could be instructive to investigate how this can be achieved and try to replicate the approach in Scala. Hint: y-combinator.

2. For those of us coming from statically typed languages, dynamically typed languages often look inferior, and we tend to stick with and search for event more stronger statically typed languages following our, potentially incorrect, intuition that one day successfully compiling a program will mean 100% correct program. And when we program, we tend to think in types and declaring new types does not bother us -- after all this is only natural. However, by introducing a new type we're faced with an interesting dilemma -- there are no functions/operations that can do anything with values of this new type... And so, we get to work implementing such functions, completely convinced that we do a "good job". But what we actually do is create more code, which means more space for defects, more code maintenance, etc. Is there an alternative? Can we minimise creation of new types? Could approaches from dynamically typed languages that utilise the "shape" of data to drive computations in combination with types from standard well tested libraries yield a more pragmatic approach to creating more reliable systems?

3. I wholeheartedly recommend SICP (https://mitpress.mit.edu/sicp) to anyone who has not already read/studied this book. It is truly the most rewarding book on programming I personally come across. It uses Scheme as the medium to convey the material, but all the ideas and concepts are fully applicable to Scala, and it is definitely possible to work though this book by implementing exercises in Scala.

4. Category Theory with Bartosz Milewski (https://www.youtube.com/watch?v=I8LbkfSSR58) -- excellent video lectures on introduction to category theory.

Cheers,

01es

Mar 4, 2018, 4:02:18 AM3/4/18

to scala...@googlegroups.com

Hi Gevin,Thank you for the reminder. I guess having a PhD is not much different to a brain injury -- it has its side effects... so, it is not pure... (:The presentation took us on your journey of "getting" the functional programming and many personal references made it very engaging for me -- thank you!The feedback below is not about the presentation per se, but only some of the specific points in the presented material. Albert Einsteins once said "The more I learn, the more I realise how much I don't know", and this is exactly my experience -- the depth of the subject of computation is... I want to say "bottomless", but one could say it has a bottom (https://wiki.haskell.org/Bottom) (:. And it is always the case that when presenting something, we're effectively forced to cut at some level to stay "on time". Therefore, I appreciate that some of the items below where potentially omitted/avoided purposefully.1. In discussing immutability it is easy to lead the listener to believe that the use of "val" ensures immutability. However, naming abstraction "val" simply creates an immutable reference to a value. But is the value immutable? If it is not, then even by using "val", immutability is not present. One could even argue that using "var" referencing an immutable value has much stronger guarantees of immutability.

2. If a type system is not expressive enough then we cannot rely only on type signature to "understand" 100% what is expected of a function. If a type system is expressive enough, such as in Idris (https://www.idris-lang.org/), we have different problems -- the complexity of type expressions may result in difficulty to read them and leads to different kinds of errors. A reasonable alternative is the use of pre-conditions, which in combination with type signatures are expressive enough and remain quite readable. Another very interesting approach is taken by Clojure in a form of Clojure Spec (https://clojure.org/about/spec).3. Currying is a convenient technique to define HOFs that return functional values (i.e. return a function as their result). An alternative is to declare complex return types that represent HOFs and use inner functions to compute return values -- that is tedious. Currying simplifies this with a convenient syntax by automating type inferencing based on lists of function arguments.

I never thought of it like this... I mentioned in the presentation that HOFs and Currying always seem to be used together "practically" in the same sentence... Even with the research I had been doing for the presentation - it never occured to me that they actually were a linked subject... I just assumed they were "like" each other!

4. A function purity is not violated by a local mutation. The provided example of a function using "for" and "var" represents a pure function. Mutation is not evil per se. In fact, a locally scoped mutation is often a good optimisation technique -- after all we're computing on von Neumann machines (:

Again, Oles and I spoke about this and at the same time said out loud that the definition of mutation - WRT to Pure Functions - was a constraint outside of the local scope... I do wish I had mentioned this in the presentation - it could have helped those new to FP.

5. It is important to differentiate between function definitions and computational processes they generate. This is a simple, but not an easily observable difference -- in casual conversations we often conflate recursive definitions of functions with "what they do" computation wise. A recursive definition generates either a recursive process or an iterative process. And so we know that a tail-recursive definition generates an iterative process, while non-tail recursive definition generates a recursive process. SICP covers this subject, as many other re functional programming, extremely well (https://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2).6. Pattern matching is a technique for data destructuring. In order to appreciate its usefulness, it is worthwhile using something that would have more than two patterns to match, which cannot be easily emulated with a single "if/else". Otherwise, especially for those that are considering/evaluating whether they want to start using the functional paradigm, it is very easy to dismiss the power of data destructuring with pattern matching.

For the presentation, it was quite long... and for the purposes of the presentation being about demystifying FP : hopefully to the point where people could read more / learn more - without necessarily being scared of it terms / definitions - I thought the best approach was to make the example code as simple as possible to show the point being made... But I wholeheartedly agree, that an example that made use of enumerated types could have been really powerful, too.

Some less relevant, but potentially thought-provoking remarks:1. Unlike functional analysis, λ-calculus is not really about the study of functions, but rather the process of computation and computability, and like the abstract Turing Machine, is a universal model for computation. A curios fact is that functions in λ-calculus are lambdas -- have no names. How could such functions be defined recursively?! It could be instructive to investigate how this can be achieved and try to replicate the approach in Scala. Hint: y-combinator.

Hahaha... I am thinking of me sitting in a lecture right now - being given the instructions of my lecturer, Oles : now complete this in your time.. and come back with an explanation for the next class!

2. For those of us coming from statically typed languages, dynamically typed languages often look inferior, and we tend to stick with and search for event more stronger statically typed languages following our, potentially incorrect, intuition that one day successfully compiling a program will mean 100% correct program. And when we program, we tend to think in types and declaring new types does not bother us -- after all this is only natural. However, by introducing a new type we're faced with an interesting dilemma -- there are no functions/operations that can do anything with values of this new type... And so, we get to work implementing such functions, completely convinced that we do a "good job". But what we actually do is create more code, which means more space for defects, more code maintenance, etc. Is there an alternative? Can we minimise creation of new types? Could approaches from dynamically typed languages that utilise the "shape" of data to drive computations in combination with types from standard well tested libraries yield a more pragmatic approach to creating more reliable systems?3. I wholeheartedly recommend SICP (https://mitpress.mit.edu/sicp) to anyone who has not already read/studied this book. It is truly the most rewarding book on programming I personally come across. It uses Scheme as the medium to convey the material, but all the ideas and concepts are fully applicable to Scala, and it is definitely possible to work though this book by implementing exercises in Scala.4. Category Theory with Bartosz Milewski (https://www.youtube.com/watch?v=I8LbkfSSR58) -- excellent video lectures on introduction to category theory.

I think there are about 20 videos totaling a fair bit of time in that they "nearly all" go for around 45 minutes...

I have watched the first few, already - and am hoping the questions I have might be answered in an upcoming one... otherwise, I'll be sure to ask for some help : you have been warned!

Thanks once again for your review of the presentation and typing up your notes - I really appreciate and hope it all contributes to the FP learning curve for everyone!

Gavin Baumanis

On Tuesday, 27 February 2018 23:32:15 UTC+11, Gavin Baumanis wrote:Hi everyone,Thanks very much for attending - in my mind while writing it - it went a lot better than I think I managed to deliver...Oh well - brain injuries - what can you do!!!!I hope you were able to get something from it.Please find below a link for the slides and notes;Also,At the end of the meeting, Oles was kind enough to give me some extra feedback of the presentation that I found really helpful and wished I had included.I guess the benefit of a PhD and the job of lecturing about FP with Scala at university can give some great insight! - Thanks very much Oles.I asked Oles if he would mind sharing his comments into this thread - for everyone to share - which he thankfully and happily said "Yes" : over to you Oles!

--

You received this message because you are subscribed to a topic in the Google Groups "Melbourne Scala User Group" group.

To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-melb/Dz9NHpgBufI/unsubscribe.

To unsubscribe from this group and all its topics, send an email to scala-melb+unsubscribe@googlegroups.com.

To post to this group, send email to scala...@googlegroups.com.

Visit this group at https://groups.google.com/group/scala-melb.

For more options, visit https://groups.google.com/d/optout.

Reply all

Reply to author

Forward

0 new messages

Search

Clear search

Close search

Google apps

Main menu