Beginner: Let Expressions

849 views
Skip to first unread message

Kirkkaf13

unread,
Apr 8, 2013, 8:48:53 PM4/8/13
to elm-d...@googlegroups.com
Hi Everyone,

First of all I would like to let you know that I am extremely new to functional programming and have chosen Elm to get started due to the ease of compile and general feel for the language.

I am very impressed with some of the examples and have been working my way through the basic examples trying to understand "how".

The first example I am having difficulty understanding is;



-- Focus on the display screen (i.e. click the right half of this window)
-- and start pressing keys!

latestKey = let step curr prev = maybe prev Char.fromCode curr in
            foldp step '_' Keyboard.Raw.charPressed

display char =
  plainText "The last key you pressed was: " `beside` asText char

main = lift display latestKey

 Now my issue is understanding what is going on in latestKey. Please can someone break it down and help me understand what is happening? I have read the documentation on each function but it hasn't helped.

Thanks.

Conrad Parker

unread,
Apr 8, 2013, 9:39:16 PM4/8/13
to elm-d...@googlegroups.com
Hi,

latestKey is a "signal". Signal is a funny word; it's more like a crystal ball than a smoke signal. Whenever you look at the crystal ball called "latestKey", it shows you the latest key that was pressed (actually, it shows you its character code, which can then be displayed).

The difficult part of latestKey is the foldp. Now, foldp is a very funny word. It's more like a cat than a piece of paper. Some mean person has hooked up the Keyboard.Raw.charPressed signal to poke the "foldp" cat every time a key is pressed. The cat remembers what happened the last time it got poked. Being a very diligent cat, it always wants to do its job (which, as we mentioned above, is to show you a character code which can then be displayed). It tries to do that by calling Char.fromCode with the current pressed key, but if that fails then it just shows you whatever it remembers from last time it got poked.

Now all this intuition about cats inside of crystal balls is very operational. What's really going on is that all the values of keys that have been pressed, and ever will be pressed, are written out on little bits of paper tied to a long ball of yarn. As time goes on, the ball of yarn is unrolled and the cat chases it, stepping along, folding itself over and over, snatching at the little bits of paper that say what key has been pressed and trying each time to work out how to display that.

Whenever it works that out, it writes out the value on a new bit of paper, and attaches it to another piece of yarn. Cats love yarn! You see now, there is actually no crystal ball, just this second ball of yarn which has all the bits of paper the cat has ever written attached to it, and also all the pieces of paper the cat will ever write. It is this second ball of yarn that we feed into our display, and it unfurls as time goes on.

The two (infinite!) lengths of yarn are the signals we work with: the first is the Keyboard.Raw.charPressed signal (the input to the foldp), and the second is latestKey (the output of the foldp). The mental stretch is the idea that these signals exist as concrete things across time, and that they can affect each other (via 'foldp step').

Another detail of foldp is that it always remembers the previous value it calculated, and passes that to the next calculation (step). However, the first time it gets called (the first time a key is pressed), there is no previous value! so we pass it a default value to use in case it needs to fall back to something. The default value here is an underscore, '_' , which the author of the example obviously chose to depict a cat's grin.

Conrad.

Kirkkaf13

unread,
Apr 8, 2013, 10:08:35 PM4/8/13
to elm-d...@googlegroups.com
Damn that is one clever cat. So just to clarify foldp can provide the last value entered within step, if no value is entered it will default, in this case to underscore and all previous values entered are stored in memory just in case they are used again?

I think I got a good understanding on how this works now.

Conrad Parker

unread,
Apr 8, 2013, 10:28:22 PM4/8/13
to elm-d...@googlegroups.com
On 9 April 2013 10:08, Kirkkaf13 <kirk...@gmail.com> wrote:
Damn that is one clever cat. So just to clarify foldp can provide the last value entered within step, if no value is entered it will default, in this case to underscore and all previous values entered are stored in memory just in case they are used again?

The first time it is called it will default to underscore, every subsequent time it will default to the previous value. Only the previous value is stored in memory, and only because foldp holds onto it. All the earlier values are forgotten (not stored in memory), as long as nothing else that's reading the signal holds onto them.

The abstraction that FRP gives you lets you ignore what's going on with memory and callbacks etc., and pretend the signal history is infinite. It's up to the FRP system to work all that out for you as efficiently as possible.

 I think I got a good understanding on how this works now.

Cool :)

Conrad. 

Kirkkaf13

unread,
Apr 9, 2013, 8:00:17 AM4/9/13
to elm-d...@googlegroups.com
Now I see, due to the level of abstraction where you was coming from with the infinite ball of yarn.

Thank you for your assistance.

Izzet Pembeci

unread,
Apr 9, 2013, 4:25:48 PM4/9/13
to elm-d...@googlegroups.com
That cat is indeed one clever cat and can do other things with the same yarn. Try these also:

latestKey2 = let combine str charCode = str ++ [Char.fromCode charCode]
                 step curr prev = maybe prev (combine prev) curr in
             foldp step "" Keyboard.Raw.charPressed

display2 char = plainText "Keys you pressed : " `beside` asText char
 
-- main = lift display2 latestKey2
 
latestKey3 = let combine str charCode = (Char.fromCode charCode):str
                 step curr prev = maybe prev (combine prev) curr in
             foldp step "" Keyboard.Raw.charPressed

display3 char =  plainText "Keys you pressed (reversed): " `beside` asText char

-- main = lift display3 latestKey3

latestKey4 = let combine str charCode = str ++ [Char.fromCode charCode]
                 step curr prev = maybe (prev ++ " (Nothing) ") (combine prev) curr in
             foldp step "" Keyboard.Raw.charPressed

display4 char = plainText "Keys you pressed (and didn't press): " `beside` asText char

main = lift display4 latestKey4


iZzeT



On Tue, Apr 9, 2013 at 3:00 PM, Kirkkaf13 <kirk...@gmail.com> wrote:
Now I see, due to the level of abstraction where you was coming from with the infinite ball of yarn.

Thank you for your assistance.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



Kirkkaf13

unread,
Apr 10, 2013, 11:28:26 AM4/10/13
to elm-d...@googlegroups.com
Hi all,

As my background has generally been programming in Lua, I am finding it difficult to grasp certain concepts of Elm which is disappointing as I think this language has a lot of potential. I am not sure if its just because I have only been playing around with Elm for a couple of days or if this is due to the documentation. I find a lot of the documentation doesn't go in-depth enough, I am still unsure on the purpose of let expressions and what the main function is doing. I understand the program starts here but does it also provide a constant loop? I thought recursive functions are used in functional looping? I was also unable to locate a complete list of all the data types & structures supports by Elm.

Thank you for reading.

Evan Czaplicki

unread,
Apr 10, 2013, 1:30:18 PM4/10/13
to elm-d...@googlegroups.com
I'm hoping to improve the docs a lot in the next few months, so thank you for letting me know the confusing parts!

Let expressions are for creating local variables. I think this example shows that fairly well. You can't break the definitions in there out because the depend on the functions arguments.

The `main` value gets hooked up to the render, so as long as you pass it new values, the screen will update; I wouldn't think of it in terms of a loop. I'd use things like `fps` and `every` from the Time library if you need to do an action on a regular basis. Recursion takes the place of for-loops and while-loops. This page should cover all of the data structures that currently exist.

Let me know if I can clarify any of this more!
Evan

--

Kirkkaf13

unread,
Apr 10, 2013, 4:54:22 PM4/10/13
to elm-d...@googlegroups.com
Hi Evan,

Thank you for your response. It's good to hear the documentation will be looked at in the future, don't get me wrong what is there is good, just a few concepts need to be more in-depth. I had a feeling it was creating 3 local variables to hold values. So as long as signals provide an update to main the screen will render, that is nice. As soon as I am home I will read over the page you provided. I will take a look at some more examples this evening and let you know if I have further questions.

Once again, thank you everyone who has helped me.

Evan Czaplicki

unread,
Apr 15, 2013, 1:07:30 PM4/15/13
to elm-d...@googlegroups.com
No problem! Let us know if you have any other questions :) We are happy to help!
Reply all
Reply to author
Forward
0 new messages