Logs: freenode/#haskell
| 2020-11-06 22:18:01 | <cohn> | ski: oh!!! I see exactly what you did above. The pattern (MkFoo n s:foos) matches the head of the list, then assigns the tail to "foos" |
| 2020-11-06 22:18:01 | → | Stanley00 joins (~stanley00@unaffiliated/stanley00) |
| 2020-11-06 22:18:08 | <cohn> | man, I didn't know you could do that |
| 2020-11-06 22:19:42 | <cohn> | ok, that worked perfectly. Thanks so much! |
| 2020-11-06 22:20:43 | <cohn> | that makes me question a lot of other code I wrote that I could probably simplify... lol |
| 2020-11-06 22:21:40 | × | o1lo01ol1o quits (~o1lo01ol1@46.50.92.11) (Remote host closed the connection) |
| 2020-11-06 22:22:22 | <ski> | cohn : not "assigns", but "binds". but, yes. you can nest patterns inside each other |
| 2020-11-06 22:22:28 | × | Stanley00 quits (~stanley00@unaffiliated/stanley00) (Ping timeout: 246 seconds) |
| 2020-11-06 22:22:53 | → | _deepfire joins (~user@80.92.100.69) |
| 2020-11-06 22:23:08 | × | ensyde quits (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) (Ping timeout: 260 seconds) |
| 2020-11-06 22:23:10 | <cohn> | wow, that's *really* powerful. |
| 2020-11-06 22:23:17 | <cohn> | not sure why I never saw that before |
| 2020-11-06 22:23:18 | <ski> | (assignment usually implies overwriting the current value in a location with some (possibly) different value. there is no overwriting here) |
| 2020-11-06 22:23:23 | cohn | shrugs |
| 2020-11-06 22:23:43 | <ski> | if you had had `data Foo = SimpleFoo String | ComplexFoo Int String', then you could have done |
| 2020-11-06 22:23:52 | <ski> | processFoos :: [Foo] -> ... |
| 2020-11-06 22:24:12 | <ski> | processFoos [ ] = ... |
| 2020-11-06 22:24:39 | × | pfurla quits (~pfurla@ool-182ed2e2.dyn.optonline.net) (Ping timeout: 256 seconds) |
| 2020-11-06 22:24:52 | <ski> | processFoos (SimpleFoo s:foos) = ..s..(processFoos foos).. |
| 2020-11-06 22:24:53 | → | thir joins (~thir@p200300f27f0b7e00f4e9381c2bf90854.dip0.t-ipconnect.de) |
| 2020-11-06 22:25:03 | <ski> | processFoos (ComplexFoo n s:foos) = ..n..s..(processFoos foos).. |
| 2020-11-06 22:25:28 | <ski> | so, two non-empty list cases, depending on whether the current/first element is simple or complex |
| 2020-11-06 22:25:48 | <cohn> | ya, that makes sense. really cool stuff |
| 2020-11-06 22:25:49 | × | ddellaco1 quits (dd@gateway/vpn/mullvad/ddellacosta) (Read error: Connection reset by peer) |
| 2020-11-06 22:26:37 | <ski> | this is the kind of thing that makes pattern-matching a breeze to work with, as contrasted with a gnarly maze of nested `if'-`then'-`else's (and possibly also `let'-`in's) |
| 2020-11-06 22:26:47 | <cohn> | exactly! |
| 2020-11-06 22:26:58 | <cohn> | ditto for the `case` statement |
| 2020-11-06 22:27:06 | → | jedws joins (~jedws@101.184.150.81) |
| 2020-11-06 22:27:11 | <ski> | yea, but you can also nest patterns with `case' |
| 2020-11-06 22:27:12 | → | o1lo01ol1o joins (~o1lo01ol1@46.50.92.11) |
| 2020-11-06 22:27:24 | <ski> | processFoos foos0 = case foos0 of |
| 2020-11-06 22:27:32 | <ski> | [ ] -> ... |
| 2020-11-06 22:27:45 | <ski> | SimpleFoo s : foos -> ..s..(processFoos foos).. |
| 2020-11-06 22:27:47 | → | pfurla joins (~pfurla@129.15.195.173.client.static.strong-in52.as13926.net) |
| 2020-11-06 22:27:54 | <ski> | ComplexFoo n s : foos -> ..n..s..(processFoos foos).. |
| 2020-11-06 22:28:00 | → | ensyde joins (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) |
| 2020-11-06 22:28:25 | <cohn> | that does come in handy |
| 2020-11-06 22:28:41 | <ski> | (and that `case' could be nested inside some other expression, if you wanted to. and you could have some other expression (other scrutinee) between the `case' and the `of', than just the direct formal parameter `foos0') |
| 2020-11-06 22:29:25 | × | thir quits (~thir@p200300f27f0b7e00f4e9381c2bf90854.dip0.t-ipconnect.de) (Ping timeout: 244 seconds) |
| 2020-11-06 22:29:27 | → | dbmikus__ joins (~dbmikus@cpe-76-167-86-219.natsow.res.rr.com) |
| 2020-11-06 22:30:00 | <cohn> | oh nice! that's good to know |
| 2020-11-06 22:30:27 | <cohn> | fwiw, I'm coming from a Python world so having to get used to types plus FP patterns like this. |
| 2020-11-06 22:30:40 | <cohn> | sorry if I sometimes ask dumb/obvious questions. |
| 2020-11-06 22:30:42 | <cohn> | :D |
| 2020-11-06 22:31:13 | <ski> | algebraic data types (also called sum types, variant types, discriminated/disjoint union types, variant record types), with pattern-matching, are really great |
| 2020-11-06 22:31:23 | × | Tario quits (~Tario@201.192.165.173) (Read error: Connection reset by peer) |
| 2020-11-06 22:31:24 | <ski> | no worry :) |
| 2020-11-06 22:32:37 | <ski> | it's too bad that only few languages supports them. imho, you really need both them, and record types (aka product types, object types, "class types"). sometimes one is more appropriate, sometimes the other. it depends on what you're doing |
| 2020-11-06 22:32:59 | <ski> | (in a formal sense, they are "duals" of each other. "opposites" in a sense) |
| 2020-11-06 22:33:02 | <cohn> | ya |
| 2020-11-06 22:33:18 | <cohn> | duals... man that brings back memories of linear programming |
| 2020-11-06 22:33:24 | × | ensyde quits (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) (Ping timeout: 272 seconds) |
| 2020-11-06 22:33:34 | <cohn> | or maybe nightmares... ; ) |
| 2020-11-06 22:33:39 | <ski> | (but i've heard rumors that more languages will be gaining them. e.g. C#, and hopefully more) |
| 2020-11-06 22:33:57 | × | conal quits (~conal@198.8.81.71) (Quit: Computer has gone to sleep.) |
| 2020-11-06 22:34:37 | × | nbloomf quits (~nbloomf@2600:1700:ad14:3020:2d48:c414:1e60:fe62) (Quit: My MacBook has gone to sleep. ZZZzzz…) |
| 2020-11-06 22:34:38 | <ski> | heh, okay :) |
| 2020-11-06 22:36:38 | <ski> | (unfortunately, it's common in OO (which is all about record/product/object types), to claim that `switch' is bad. (pattern-matching can be viewed as `switch' on steroids.) it's not bad, it's just that sometimes product types are more appropriate. and sometimes, sum types are more appropriate) |
| 2020-11-06 22:36:51 | → | rprije joins (~rprije@124.148.131.132) |
| 2020-11-06 22:37:43 | → | conal joins (~conal@198.8.81.71) |
| 2020-11-06 22:37:47 | <cohn> | agreed. |
| 2020-11-06 22:38:12 | → | ensyde joins (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) |
| 2020-11-06 22:38:29 | × | o1lo01ol1o quits (~o1lo01ol1@46.50.92.11) (Remote host closed the connection) |
| 2020-11-06 22:38:46 | × | dbmikus__ quits (~dbmikus@cpe-76-167-86-219.natsow.res.rr.com) (Read error: Connection reset by peer) |
| 2020-11-06 22:38:50 | × | knupfer quits (~Thunderbi@mue-88-130-61-134.dsl.tropolys.de) (Ping timeout: 260 seconds) |
| 2020-11-06 22:38:55 | × | ensyde quits (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) (Read error: Connection reset by peer) |
| 2020-11-06 22:39:04 | <ski> | (.. and then, when you really need sum types in OO languages, you're often left with only clumsy ways of simulating them. like either using `switch' with downcasts, or `if'-`else's with downcasts. or (more blessed), the VisitorPattern (which is basically a Continuation-Passing / Church Style encoding of sum types)) |
| 2020-11-06 22:39:22 | → | dbmikus__ joins (~dbmikus@cpe-76-167-86-219.natsow.res.rr.com) |
| 2020-11-06 22:40:12 | <ski> | let's say you want to have some type. and you want to be able to construct values of this type, of some number of different alternative forms. and you also want to be able to query values of this type for "properties" |
| 2020-11-06 22:41:08 | <ski> | if the alternatives that you want to support are relatively fixed, but the properties are likely to be modified, or get extended with new ones, then you probably want sum types |
| 2020-11-06 22:41:44 | → | invaser joins (~Thunderbi@31.148.23.125) |
| 2020-11-06 22:41:45 | <ski> | if the properties are relatively fixed, but the alternatives you want to support are likely to be modified, or extended, then you probably want product types |
| 2020-11-06 22:42:31 | <ski> | for each alternative, you need to implement the property (the "method") on that alternative. so, you can draw a table, where the rows are different alternatives, and the columns are different properties |
| 2020-11-06 22:42:45 | × | borne quits (~fritjof@200116b864a45200fbd62cc7430251a2.dip.versatel-1u1.de) (Quit: WeeChat 2.9) |
| 2020-11-06 22:42:55 | → | ensyde joins (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) |
| 2020-11-06 22:43:15 | <ski> | and each cell contains the implementation of the property of that column, for the alternative that is the row |
| 2020-11-06 22:44:31 | <ski> | then, if you slice this table into rows, you're grouping all the property implementations, for a single alternative, together. this is the product type road. such an alternative is called a "class", in the OO world, and the properties are called "methods" (or "member functions" or perhaps some other term as well) |
| 2020-11-06 22:45:58 | <ski> | so, to add another alternative, you just define a new class, defining all the methods/properties for it. but, to add a new property, you need to add a method to all the existing alternatives/classes (all the classes/alternatives implement the same interface. or maybe they inherit from a common base class, which is likely often abstract) |
| 2020-11-06 22:46:40 | <ski> | so, adding a new property is harder, more error-prone, since you need to modify existing code, and possibly take into account interactions with that code |
| 2020-11-06 22:47:28 | <ski> | on the other hand .. if you instead slice the table into separate columns, then each column is the implementation of a single property, for all the different alternatives. this is called a "pattern-matching function" |
| 2020-11-06 22:47:31 | <cohn> | gonna take me a minute to digest all of that... :D |
| 2020-11-06 22:48:10 | × | ensyde quits (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) (Ping timeout: 260 seconds) |
| 2020-11-06 22:48:15 | <ski> | now, adding a new property is simple, you just add a new pattern-matching function, handling all the data constructors (the alternatives) in separate defining equations of the function |
| 2020-11-06 22:48:57 | <ski> | however, adding (or modifying) a new alternative is more involved, since now you need to go and change all existing pattern-matching functions that takes an input of data type |
| 2020-11-06 22:49:24 | <ski> | so .. it is a trade-off. neither is fundamentally better than the other. it depends on what you expect |
| 2020-11-06 22:49:52 | <ski> | also, then there's issues like recursion in your type that complicates this picture. but the above is the basic summary of the difference |
| 2020-11-06 22:51:33 | <ski> | cohn : as an example : define a type `Shape', meant to describe a simple geometric shape. and say you want to support rectangles (with width,height) and circles (with radius) as possible alternatives. as properties, you want to support circumference and area |
| 2020-11-06 22:51:38 | × | hyperisco quits (~hyperisco@d192-186-117-226.static.comm.cgocable.net) (Ping timeout: 264 seconds) |
| 2020-11-06 22:51:55 | <cohn> | right |
| 2020-11-06 22:52:55 | × | pfurla quits (~pfurla@129.15.195.173.client.static.strong-in52.as13926.net) (Ping timeout: 246 seconds) |
| 2020-11-06 22:52:56 | <ski> | exercise for you : define `Shape' as a product/record type, with circumference and area as fields/methods. and define functions ("constructors"/"classes" in OO terminology) `rectangle' and `circle', taking width & height, respectively radius, and giving you back a `Shape' |
| 2020-11-06 22:53:13 | → | ensyde joins (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) |
| 2020-11-06 22:53:33 | <cohn> | ok |
| 2020-11-06 22:54:33 | <ski> | then, define `Shape' again, but this time as a sum/variant type (algebraic data type), having `Rectangle' (with width & height arguments/components) and `Circle' (with radius component) as alternatives (data constructors), and then define the properties `circumference' and `area' as pattern-matching functions on `Shape' |
| 2020-11-06 22:54:53 | <cohn> | afk for a sec. |
| 2020-11-06 22:55:10 | × | invaser quits (~Thunderbi@31.148.23.125) (Ping timeout: 260 seconds) |
| 2020-11-06 22:55:32 | → | Stanley00 joins (~stanley00@unaffiliated/stanley00) |
| 2020-11-06 22:56:34 | → | pfurla joins (~pfurla@ool-182ed2e2.dyn.optonline.net) |
| 2020-11-06 22:57:49 | × | ensyde quits (~ensyde@99-185-235-117.lightspeed.chrlnc.sbcglobal.net) (Ping timeout: 246 seconds) |
| 2020-11-06 22:57:49 | × | codygman quits (~codygman@47-184-107-46.dlls.tx.frontiernet.net) (Ping timeout: 246 seconds) |
All times are in UTC.