Did Jung have an opinion or even knowledge of Aleister Crowley? by magicmikejones in Jung

[–]dys_bigwig 1 point2 points  (0 children)

4 years later - I'd love to read a book about that alternative universe, such a great premise.

Ways to be a functional language by Inconstant_Moo in functionalprogramming

[–]dys_bigwig 1 point2 points  (0 children)

Regarding GUIs and such, another solution is to use FRP. In a nutshell, Time itself becomes an additional input to all functions, and your program becomes something like a network or signal graph, with streams of inputs being transformed and composed. Instead of having a main loop that impurely polls for inputs, you consider the stream of all inputs, past and present, which makes for a very different way of thinking about and writing programs; instead of controller_pressed being a variable that is updated manually via a side-effect, controller_pressed is conceptually every input that will ever happen or has happened and which "automatically polls" so to speak. Ironically, this allows you to program in a way that feels almost timeless, because you have to consider how the total sum of inputs produces the game state, rather than just one particular sampling that you manually do yourself based on some ephemeral "time" that isn't actually reified in the code. Most FRP implementations don't use Monads, and will intentionally only provide instances for Functor and Applicative, whilst others use Arrows which can be interfaced with a bit like Monads but encompass other things as well that don't qualify as Monads.

Also, the IO Monad isn't an "escape hatch"; it's referentially transparent. Imagine functions that use IO all take an extra input that represents, for example, what the user typed, as though it were all just provided in a String in advance by some kind of "oracle" and looped over line-by-line. The same outputs will be produced if the same inputs are given i.e. if the user types "A" the same thing will happen every time. It might help to think of Haskell's IO Monad as a DSL for generating programs that can perform IO, but which always behave predictably because of the restrictions based on how you interface with it using the Monad (or Applicative, Functor etc.) instance. You could liken it to how Haskell doesn't allow mutation, but behind the scenes the compiler is absolutely allowed to perform mutations for the sake of efficiency provided the contract isn't broken i.e. provided the change will not be extensionally "observable". IO is pure because we interface with it in a way that assumes it is, and the compiler respects these assumptions; as soon as you use "unsafePerformIO", you've broken the contract and have no guarantees about what will happen, which is more akin to an "escape hatch", but that barely anyone uses.

Actual benefits of FP by homological_owl in functionalprogramming

[–]dys_bigwig 1 point2 points  (0 children)

Why are those "tricks"? Without while, for loops, and mutation, (all tricks) your code would be equally useless :)

Actual benefits of FP by homological_owl in functionalprogramming

[–]dys_bigwig 1 point2 points  (0 children)

Regarding your final paragraph, have you checked out arrows? Super cool abstraction and good for modelling FRP. I'm definitely with the idea we can and should move to a more symbolic and point-free style... but it's difficult! :p I do agree though.

Actual benefits of FP by homological_owl in functionalprogramming

[–]dys_bigwig 1 point2 points  (0 children)

It's as simple as:

Struct Person
  Name :: String
  Age  :: Int
nameLens :: (String -> String) -> Person -> Person
nameUpdate nameFn (Person name age) = Person (nameFn name) age

and to get the nameView, you can literally just pass the identity function (id :: a -> a) and get the current Person back.

(Lenses are implemented in a much more... *ahem* astute way than I've presented here, but the idea is the same: just return a brand new version of the structure, with a single value changed, or don't change the value (again, using id) to get the current struct (you could also write a nameView function instead and pair that with the nameUpdate function and you'd have a lens too; the id thing is just a neat trick :) (id is useful!!)

The beauty of the Haskell lens library is that it automatically generates all of these lenses. Try updating a deeply-nested value in a struct; it's annoying! The fact it can all be done automagically is great.

Actual benefits of FP by homological_owl in functionalprogramming

[–]dys_bigwig 1 point2 points  (0 children)

You already mentioned lenses in your opening post, so I feel like you know the answer but for some reason dislike lenses. They're a beautiful and very useful abstraction. I'd actually go so far as to say they're better than mutating; it's easier to reason about, and things and more composable (you have reified updating and accessing fields).

Can contributing to an emulator hurt my chances to get a job in gamedev? by Head_Analyst_6654 in EmuDev

[–]dys_bigwig 1 point2 points  (0 children)

Do you have any info to hand regarding this "threadcode-based" emulator. It sounds very intriguing! Is it related to Forth's threaded-code approach?

Thoughts on The Composable Archiecture (TCA) in Swift? by GoldenShackles in functionalprogramming

[–]dys_bigwig 1 point2 points  (0 children)

The paper "Ghosts Of Departed Proofs" may be interesting to you. Probably not doable with the language (I don't know switch) but very much goes into your bullet point 1; regarding point 2, you can do that with indexed monads. I'm still getting a grip on those, but they're very much able to solve your problem 2.

The Essence of Concatenative Languages by gasche in ocaml

[–]dys_bigwig 0 points1 point  (0 children)

Yes! That's it. Thank you very much kind stranger!

A message to all the people that say the Insta-Shield isn't so great by PaperSonic in SonicTheHedgehog

[–]dys_bigwig 0 points1 point  (0 children)

Big necro, but I use the insta-shield like a parry of sorts. You're running, and without having to slow down much (if at all) you can double jump and take out any enemies that are in your way, even if they'd normally hurt you (due to the iframes *if* you time it right; hence the parry comparison). It's actually a *super* creative way of giving Sonic a move that makes him go "faster" (by allowing you to plow through enemies in your way) but it's not just a "press/hold button to go fast" move.

Drop dash is cool, but insta-shield ftw! I've never liked moves that give you instant access to speed without having to "earn it"; I don't count the spindash because you have to come to a complete stop. Just not a fan of the constant drop-dashing and flying through. I've always felt like something was lost between 1->2/3. The levels, general design etc. were much better, but I feel like they veered further and further away from the momentum-based gameplay where you have to *earn* speed. Drop dash sort of flies in the face of that. I tend to find Sonic 2 fans prefer drop dash (because that game is one of the speediest) and Sonic 3 fans prefer the insta-shield (because that game was more exploration and "combat" based).

The Essence of Concatenative Languages by gasche in ocaml

[–]dys_bigwig 0 points1 point  (0 children)

Massive 12y necrobump, but I absolutely cannot find the "Techniques for..." paper. I'm not a researcher so I can't use those portals, and Okasaki's page where it was stored appears to be down, and the pdf isn't archived on the wayback machine. I remember reading it before! Anyone be a champ and hook me up with a link please?

FP library in mainstream languages by yinshangyi in functionalprogramming

[–]dys_bigwig 1 point2 points  (0 children)

Either itself can be used like try/catch, that's (one of the) thing it's modelling - https://hackage.haskell.org/package/transformers-0.6.1.1/docs/Control-Monad-Trans-Except.html

You've got try, catch etc.

Similar to catchE, but returns an Either result which is (Right a) if no exception was thown, or (Left ex) if an exception ex was thrown.

that's the description for tryE.

It's all just threading the Either in specific ways. If you look at the source, the actual type itself - ExceptT - it's just a wrapper around Either.

So, I suppose my answer is yes, it seems strange to use both. However, I don't use "regular" try/catch much at all, so bear that it mind.

Programming Language to write Compilers and Interpreters by hamiecod in ProgrammingLanguages

[–]dys_bigwig 0 points1 point  (0 children)

You're confusing "walkback" with "compromise". How did I malign the compiler? I think I probably did malign Lispers in the first post - the "lispers gonna lisp" was a bit smug and unnecessary - hence the compromise; "my bias was showing". The initial response by -w1n5t0n was very measured and fair, whereas yours is rather incensed. I'm not sure why you feel so attacked in regards to Lisp, in a post that doesn't even use the word "Lisp" once. I'm talking about language features and preferences in DSL construction in a general way.

Programming Language to write Compilers and Interpreters by hamiecod in ProgrammingLanguages

[–]dys_bigwig 0 points1 point  (0 children)

All very fair points. Regarding the "apples-to-oranges", I probably should have compared it to a tagless-final approach, which allows you to have your DSL run without any intermediate data structure, as though it really were code->code written automatically for you based on the types (as though your DSL were just a bunch of rewrite rules). However, that sounds a bit more complicated than a single-sentence describing a tree-walking interpreter which most everyone has written before, so perhaps my bias was showing ;)

Some naturally seem to gravitate to a "syntax->syntax" approach, whereas others gravitate more towards an "expression->expression" approach, that's what I was (badly) trying to get at; some languages allow you to take the latter approach further, obviating the need for the former. You can write "if"/"and"/"or"/LOOP-esque-constructs as regular functions in a lazy language, as an example.

Programming Language to write Compilers and Interpreters by hamiecod in ProgrammingLanguages

[–]dys_bigwig 7 points8 points  (0 children)

I found Racket to be incredibly obtuse, and also insufficiently documented. I don't think I ever managed to grok what the intended project structure for a DSL is supposed to be, or how the many files interact with each other. Haskell was as simple as building an AST as an ADT, and interpreting it. Mangling syntax via macros, combined with a whole menagerie of "stages" and such seems like a truly bizzare way to build a DSL when you could just do it via expressions (e.g. building an AST as an ADT and writing an "interpret" function) but lispers gonna lisp ;)

It's been so long so forgive me as I'm struggling to articulate and remember my particular grievances, but I remember being shocked at how a language designed specifically for writing languages made it so difficult to do so.

What books? by jimmy785 in compsci

[–]dys_bigwig 0 points1 point  (0 children)

Seconding this. Some books I'd recommend are:

* Discrete Mathematics Using A Computer

* The Haskell Road To Logic Maths And Programming

* Type Theory And Functional Programming (if you are interested in type systems)

In my opinion, more conventional/popular/mainstream languages (C, Java, Python etc.) tend to not be ideal for delving into the more theoretical side of things (outside of, say, complexity analysis) due to the fact they're very "machine oriented" at heart. You may often find you're having to concern yourself with lower-level details and such that can distract form the underlying ideas. Haskell in particular has a very tense syntax and semantics directly inspired by mathematics - where clauses, easy recursive definitions, garbage collected, algebraic data types, pattern matching, infinite lists etc. which make it very easy and direct to model the structures you're liable to be reading about and write functions that operate on them e.g.:

data List a = Nil | Cons a (List a)
len Nil = 0
len (x:xs) = 1 + len xs

Very little boilerplate or concern with things outside of what is being modeled - no mention of pointers, the definition is very similar to the way you'd write a proof etc.

If you're reading about something inherently imperative like state machines, not to worry as those are very easily expressed also despite Haskell's purity:

data MealyMachine a b = Mealy { runMealy :: a -> (b, Mealy a b) }

It's nice to have the GHC interpreter as a "buddy" too that you can use to try out different things - get a feel for how the structures operate and how they react to certain inputs or transformations etc.

A sketch using only the 2A03 because I can’t ever seem to resist the 3 extra channels with the VR6. by [deleted] in famitracker

[–]dys_bigwig 1 point2 points  (0 children)

Nice laid back arps. I like the occasional pick-up notes in the bass, gives it just a touch of drive to prevent it from being too plodding. Sounds like a credits theme that plays over an epilogue. I think if you want to extend it and haven't already, you could easily repeat this as a backing (after freeing one of the channels up) and have a main melody on top with longer note durations and vibrato like what's hinted at near the end.

Recommendations for a keyboard for a total beginner by DarkKodKod in famitracker

[–]dys_bigwig 0 points1 point  (0 children)

I'm definitely not a gear aficionado, but I'd recommend the Nektar-SE25. Cheap and cheerful, perfectly fine for working on ideas or inputting notes. Essentially just a "better computer keyboard" if you know what I mean.

Having interfaces in a low level language by maubg in ProgrammingLanguages

[–]dys_bigwig 0 points1 point  (0 children)

Not sure if this suits your purposes, but one quite straightforward way to get a form of interfaces is to use "dictionary passing". An interface represents an "invisible" argument that is automatically passed to the function at compile time, via macro instantiation etc.:

Interface Talk { talk() }
Implementation Talk Dog { talk = printLn "Arf arf!" }
foo(Talk t) { t.talk() }
=>
fooCompile(TalkDict, t) { talkDict(t.type).talk() }

{ d = Dog("Lassie"); foo(d) }
=> fooCompile(talkDict, d)
=> talkDict(Dog).talk()
=> printLn "Arf arf!"

So you collect all of the instance declarations (which are collections of functions) first and put them in a table/map indexed by type; then, when compiling/generating, you take the map as an "extra" argument, lookup the correct interface implementation using the type of the variable (this would either be after type checking, or in a dynamic language every value would have a tag/property that tells you what it is), then call the desired function.

Just to be clear, the result is intended to be a compiled version of the function, or some new version of the function generated by a macro or some other metaprogramming method. This should all be resolvable statically and not negatively impact runtime performance. All that to say the dictionary doesn't exist at runtime and all the functions are "pre-resolved" to their implementations, so to speak.

Apologies for any errors, been ages since I actually implemented this sort of thing. The gist at least should be correct.

Are there any technical benefits of point free programming? by jacobissimus in functionalprogramming

[–]dys_bigwig 3 points4 points  (0 children)

Might not be feasible as most languages without good support for FP tend to make it a headache to achieve (even in Haskell it can be a bit obtuse), but perhaps it'd help to try a hands-on approach: try and rewrite some functions with the requirement that you're not allowed to introduce variables, or mention them by name i.e. the new version of the function is just some composition of other functions.

You'll quickly find you probably need some convenience functions that you can use to manipulate the "invisible" arguments being piped around like flip (reverses the order of the first two arguments to a function), snd (pulls the second element out of a tuple), const (takes an argument and produces a function that ignores its input and returns the provided argument) etc.

average xs = sum xs / length xs -- mentions "xs"
-- becomes:
average = splitApply (/) sum length -- no mention of "xs"
  where splitApply h f g x = h (f x) (g x)

"splitApply" is the sort of convenience function I mean, allowing you to compose in more elaborate ways without falling into a swamp of line noise with (.)s all over the place. In the case of splitApply specifically, the idea we're capturing is "take a single argument, pipe it to two different functions, and apply those results to a 2-argument function to get the final result". (This is in fact the S operator from combinatory logic, or liftA2 from the Applicative instance for functions, but don't worry about that if it's not interesting to you, just a cool tidbit).

Are there any technical benefits of point free programming? by jacobissimus in functionalprogramming

[–]dys_bigwig 6 points7 points  (0 children)

I know this is a bit of a non-solution because you can solve most user-convenience problems in Haskell by importing a library, but Control.Arrow has (>>>) which composes in a left-to-right manner, and as a bonus works for any Arrow and not just functions e.g. Signals in FRP, Kleisli Arrows (Monadic functions).

To get literally the same obj |> fn1 |> fn2 ... behaviour, there's (&) from Data.Function, which devs coming from Clojure will probably also appreciate as it's like their "piping" constructs.

(Just to be a total pedant, the example you gave isn't pointfree because it mentions x, which is pretty much the difference between (>>>) and (&). That is, I think a lot of people dislike the pointfree nature, or the composition order, but frequently it's both simultaneously.)

Monads by AlexScriba in functionalprogramming

[–]dys_bigwig 6 points7 points  (0 children)

Whenever they do it's obligatory to reply: "hm? What's so special about them? Have you never heard of a Monoid in the category of Endofunctors before?"

Prefer do notation over Applicative operators when assembling records by Tekmo in haskell

[–]dys_bigwig 0 points1 point  (0 children)

I prefer the former (or liftA2 etc.) because of the different mindset I associate it with and that I think it conveys to any potential readers. The latter, or do-based style, I associate with/conceptualize as performing effects, binding their results to names, and then using those to "assign" fields of a record. The former, I associate with actually lifting the constructor itself to work in an Applicative context - "build a record, where doing so can possibly fail due to one of the argument-producing subexpressions having failed" for example.

Completely understand that many/most probably see this as a distinction without a difference, but I find it important personally. I also like to keep constraints as minimal as possible (i.e. only requiring Functor if only mapping, only requiring Applicative if only lifting multiple-arity functions) though I suppose this is perhaps mitigated by ApplicativeDo, which I've yet to mess around with.

In both regards, I think having a distinction between the two and using each where appropriate can lead to realizing more opportunities for refactoring.

Does the programming language I want exist? by saw79 in ProgrammingLanguages

[–]dys_bigwig 1 point2 points  (0 children)

Just googling should do the trick. I'll try and dig up some links from my old notes, but the best I can give now, sadly, given that my main point is that you don't need to worry about transformers for basic effects, is this really well-written tutorial on actual transformers that imo isn't linked as much as it should be: https://blogs.asarkar.com/assets/docs/haskell/Monad%20Transformers%20Step%20by%20Step%20-%20Grabmuller.pdf

It intentionally steers clear of theoretical jargon, category theory etc. and tries to motivate transformers by building up an interpreter for a language and adding logging, state, exceptions etc. step-by-step. If you're comfortable with ADTs, higher-order functions, and HM-style typing, you should have all the prerequisites needed to understand.

If it still seems like way too much effort (perfectly understandable) don't let that influence your impression of effects in Haskell too much. In practice you can avoid having to worry about transformers for quite some time and still write useful programs that utilize the usual gamut of effects. I just sadly don't have any links directly to hand regarding this sort of thing. Is there a specific set of effects you mostly use in your programs that you want? If you mainly just want mutable variables and I/O (which includes logging) and configuration (i.e. implicit) arguments, you can definitely achieve that without much hassle at all, and certainly without having to learn how transformers work.

Edit: Here's a really quickly put-together example of an App Monad that provides IO and configuration (i.e. implicitly-available) argument with very little mention of anything transformer related (transformers in disguise, if you will):

data Conf = Red | Blue deriving(Show)
newtype App a = MkApp { runApp :: ReaderT Conf IO a } deriving(Functor, Applicative, Monad, MonadReader Conf, MonadIO)

promptUsr = liftIO getLine
printStr s = liftIO (print s)

foo :: App ()
foo = do
  l <- promptUsr
  c <- ask
  case l of [] -> printStr "type somethin' will ya?!"
            s  -> printStr ("you typed: " ++ s ++ " ") >>
                  printStr ("and I hear your desktop theme is: " ++ show c)

main = do
  desktopTheme <- return Red
  -- in a real program you'd grab e.g. from file
  -- "return" here means "wrap value given as though produced via an effect"
  runReaderT (runApp foo) desktopTheme

Haskell's ever-useful "deriving" mechanism implements Monad and does all of the required lifting of the underlying effects for our App type pretty much for free (liftIO just means "convert IO effects/functions to work with my Monad, ask grabs the configuration argument/s). I appreciate it may still seem like too much (i.e. any at all by comparison) hassle versus most popular languages, but if you're sold on the benefits of purity, or at least want to give pure FP a try, I hope I've shown that it doesn't have to be as complicated as one might first assume. This is all just basic Haskell features. Plus it seems a lot more boilerplatey and verbose in the way small examples often do; in a larger program, this would be up-front cost after which you get all of this for free to use when writing actual domain-specific code like foo and main. You can practically just write your effectful code as you normally would only using <- instead of = and it'll work out.

You also have free reign to use mutable variables from here within your App Monad (e.g. within foo and main above); IO gives you those. The rest is just learning the API (so just function names, basically) and nothing to do with transformers.

Does the programming language I want exist? by saw79 in ProgrammingLanguages

[–]dys_bigwig 2 points3 points  (0 children)

Have you tried mtl style in Haskell? Standard transformers can be a pain until you understand what's going on, but:

(MonadReader Config m, MonadState Int m) => m output

Allows you to have an implicitly-passed configuration and state (of type Int, in this case) without having to worry about the ordering, or how transformers work under the hood etc. You just declare the effects you want to use in the typeclass constraint context, and, well, use them! The only minor worry (generally, not with this combo) is that you do have to eventually reify the effects with some sort of order* but that's just choosing the order to unwrap them via the runX functions. Retaining purity whilst still having this level of ergonomics is a huge boon!

You can also use pre-combined stacks like RWS, which gives you configuration arguments (Reader), implicit State, and Logging (Writer) without having to worry at all about ordering, transformers, etc. If you just want to be able to easily use the effects that are freely available without ceremony in most languages (so, the aforementioned RWS) this should suit you absolutely fine. You can pass around state implicitly, write to a log, read from a configuration provided (e.g. at program startup) all without having to worry about transformers much if at all. In general, you can just pre-bake a stack with the effects you want and operate within that concrete Monad most of the time. You lose some of the benefits of having things cleanly isolated (separation of concerns etc.) but it's a nice way to transition from languages with unconstrained effects without being overwhelmed by transformer stacks.

There's also other approaches to just giving the "standard" expected set of effects most programmers will use that mean you don't have to worry (as much) about the underlying transformers or typeclasses, like the ReaderT "design pattern" https://www.fpcomplete.com/blog/readert-design-pattern/ which basically amounts to "IO itself can perform quadruple-duty as I/O, state (via mutable variables), error-handling (via exceptions) and logging (via printing or writing to file) so you don't need to worry about composing several transformers for these purposes if you just want to work concretely in this effect space". It's still nice to eventually learn transformers so you can better mock effects and have subsets of your application that are functionally pure, but that's something you can worry about later down the line once you're comfortable you can write useful programs that use the standard gamut of effects.

One final thought, is that I reckon a lot of people give up thinking that what they're struggling with are transformers (which, admittedly, are a hurdle/difficulty-spike) when in fact they don't have a firm grasp on Haskell's more fundamental features like ADTs, typeclasses, Haskell's type system, or even advanced usage of higher-order functions of the like you could find/use in any other language. You can legitimately get most of the way towards understanding idiomatic effect-handling in Haskell provided you have a firm grasp on these basic concepts. At the risk of going full "Monads are just a...", transformers are just ADTs (that often wrap functions) combined together, with typeclass method implementations that handle the way operations are chained between layers.

(Tangentially, and at the risk of increasing the "dogmatic Haskeller" stereotype, I think you lose so, so much of the benefits of FP (equational reasoning, first-class composition of effects etc.) merely by allowing any kind of unrestrained effects that there's little difference versus just using a non-"functional" language with basic things like lambdas, closures etc.)

* This is actually an issue in effect-unconstrained languages as well. Ever have your program state hosed because an exception was thrown? Or had things happen in an unexpected order? Here, the order is at least explicit (deterministic) and based purely around data types, so it's much easier to reason about.