Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
xtal
Jan 9, 2011

by Fluffdaddy
I don't know if any other functional programmers run into this problem, but I have a really hard time deciding which language I want to use for new projects. My two main choices are Racket and Haskell. I think that Racket programs can be developed much faster because of the minimal syntax, dynamic typing and macro system. But they're less safe than Haskell programs, which have static typing and pure functions.

Are there any languages that are a compromise between the two, like a statically-typed, purely functional Lisp language? I'm trying to get into Typed Racket and I figure I could use the monad library for side effects. The benefit I see is that I can start with an untyped program and add types as needed.

xtal fucked around with this message at 22:55 on May 18, 2015

Adbot
ADBOT LOVES YOU

xtal
Jan 9, 2011

by Fluffdaddy

comedyblissoption posted:

I talked about Haskell briefly a couple times IRL.

Both times people initially thought I was talking about Pascal.

Are you mispronouncing Haskell like I did for a long time? (Or am I still mispronouncing Pascal?)

xtal
Jan 9, 2011

by Fluffdaddy

Athas posted:

I don't think there is any answer to this question that lies between "use recursion" and "study algebratic recursion schemes". I suggest reading Purely Functional Data Structures, which is an awesome demonstration of how to engineer simple high-performance data structures in both lazy and strict languages. You can skip the theory if it's not your cup of tea.

Unfortunately, in a cruel twist of fate, the data structures you usually want to use in a purely functional language (recursive structures) tend to be terrible for parallelisation, despite the fact that the code itself has no side effects, and thus should not be too hard to run in parallel. I have yet to see a really convincing parallel functional language - NESL is probably the best I have seen, but it's old.

What do you mean by that? I've enjoyed writing concurrent code in Clojure, Haskell and Scala much more than other languages. Immutable data structures and pure functions make for dead simple parallelism.

In any case, I'm starting to see that the right way to do concurrency is multiple processes communicating through a message broker.

xtal
Jan 9, 2011

by Fluffdaddy

Zemyla posted:

If you were compiling the code, you'd see a much more dramatic decrease in the memory used with foldl', because of something called list fusion. Basically, in GHC, a lot of functions in the Prelude, and a good number of functions in other modules, use rewrite rules to pretend a list is actually a function that produces elements of the list on demand.

The key here is GHC.Base.build, which uses the RankNTypes extension (which allows polymorphism in function arguments):
code:
build :: forall a. (forall b. (a -> b -> b) -> b -> b) -> [a]
build g = g (:) []
If you're familiar with the type of foldr, you may notice a similarity between the two. It's intentional, and there is in fact a rewrite rule that says:
code:
forall k z (g :: forall b. (a -> b -> b) -> b -> b)
foldr k z (build g) = g k z
This enables it to directly consume the list as it would have been produced, without producing an intermediate list at all in the first place.

As an example of what this lets you do, let's take a simple function from the Prelude, map:

code:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
Looks pretty simple, huh? Well, the rule-rewriting engine will trigger a transformation into:

code:
{-# RULES "map" [~1] forall f xs. map f xs = build (\c n -> foldr (mapFB c f) n xs #-}

mapFB :: (b -> r -> r) -> (a -> b) -> a -> r -> r
mapFB c f = \x ys -> c (f x) ys
This basically causes that map code to be turned into a build which uses a foldr on its argument, causing what would be an intermediate list to vanish. Note that this produces a list in the form of build g as well. If the incipient list is turned into an actual list, then another rule fires:
code:
{-# RULES "mapFB" [1] forall f. foldr (mapFB (:) f) [] = map f #-}
This is controlled by inlining level annotations: the [1] means "only use this rule on inlining levels 1 and 0" and [~1] means "use this rule on all levels before 1" - there are 5 levels, and in order they are 4, 3, 2, 1, and 0.

What all this means is that, if you were to use foldl' to do the summation, then the compiler would use rules, inlining, strictness analysis, arity analysis, and others (they're tedious to perform by hand, but not complicated or obscure) to turn:
code:
value :: Int
value = foldl' (+) 0 $ take 10000000 $ repeat 5
into
code:
value :: Int
value = let
    xs !m !z = case m of
        1 -> z + 5
        _ -> xs (m - 1) (z + 5)
    in xs 10000000 0
And a simple tail-recursive function with a strict index can easily be turned into a loop in assembly.

So the lesson is that if you're consuming a list, use either foldr (if you're producing a lazy structure or consuming a possibly-infinite list) or foldl' (if you're producing something strict like a number and you know the list is finite).

Side note: All of this happens if you consume the list at the same time you produce it. If you have a list with a billion elements, calculate its length, and the later calculate its sum, then you're going to be hanging on to a list with a billion elements in memory. Sucks to be you.

This is all nice and good but does anybody else want to crosspost it to the coding horrors thread? Every pragma in GHC is just awful.

xtal
Jan 9, 2011

by Fluffdaddy
nm

xtal fucked around with this message at 02:08 on May 25, 2016

xtal
Jan 9, 2011

by Fluffdaddy
Lately I've been learning Idris because Haskell has a bunch of warts that make me cry. The library support is, expectedly, lacking, so I'm considering writing Haskell with an alternate prelude instead. Has anybody worked with ClassyPrelude, Protolude or Foundation who can help me decide what to use? (Or tell me if this is even a good idea, because I expect I am going to need to add a whole lot of string conversions for compatibility with libraries.)

xtal
Jan 9, 2011

by Fluffdaddy
I have a bunch of small complaints (Idris improves a lot more than the type system) but the lack of performance (String) and safety (totality) in the Prelude are what gets me. Having an opaque list type already pokes holes in type safety, so at the very least I want a Prelude that is total. Alternatives also tend to be implemented via type classes rather than concrete types which I prefer.

xtal fucked around with this message at 02:16 on Sep 3, 2016

xtal
Jan 9, 2011

by Fluffdaddy
Sorry for the derail but I am sort of only curious about alternative preludes. It would actually not surprise me if there was one that defined operations in terms of lenses.

xtal
Jan 9, 2011

by Fluffdaddy

Ralith posted:



Text is faster than anything Idris has to offer, and [a] certainly isn't opaque! The accessors can be a bit silly, sure, but naive accessors aren't great to use anyway since they don't compose well; use lens!

I just wanted you to know I am really on board with lenses now. I was avoiding them because I think Template Haskell is the plague but I'm able to compartmentalize all of that junk in a Types file.

xtal
Jan 9, 2011

by Fluffdaddy

Ralith posted:

:shobon:
You don't actually need to use Template Haskell to use lenses at all, even advanced things like biplate; the boilerplate is concise and linear wrt. your original code. The TH just saves a few lines and ensures consistency, which is enough reason for me to use it, but it's by no means unavoidable. One of the original design goals of lens was actually to allow people to easily make libraries compatible with it without even depending on the package.

That's good to know, I was under the wrong impression because the first step in every tutorial is Template Haskell.

xtal
Jan 9, 2011

by Fluffdaddy

mystes posted:

That's because the tutorials all start with a bunch of nested record types, and in this case it's convenient to use template haskell to automatically generate the lenses from the record fields. Otherwise the boilerplate code would be pretty verbose and probably immediately cause people to close the tutorial.

So your choices are the horror of template Haskell or the horrors of boilerplate?

xtal
Jan 9, 2011

by Fluffdaddy

Ploft-shell crab posted:

It is! Their implementation can run in constant space while yours, potentially, could blow up the stack. Check out the Wikipedia article on Tail Call Recursion/Optimization for more info.

His implementation is still TCO, it just uses an if statement rather than patterns and guards. The comparison remains linear time (pattern matching can only sometimes be optimized to constant; guards never can.)

This is a matter of preference but functional programmers consider if statements to be ugly and imperative.

xtal fucked around with this message at 23:27 on Oct 10, 2016

xtal
Jan 9, 2011

by Fluffdaddy
Is local mutation necessary with sufficiently advanced COW and GC? You don't need to bust out transients in Clojure often and I don't think Haskell even includes them. I don't think the real world performance improvement is big enough to involve mutable state; and, if you spent the time improving the implementation of your immutable structures instead, its benefits would apply to all your code implicitly.

xtal
Jan 9, 2011

by Fluffdaddy
With those criteria I would say that GC and mutability are two sides of one coin. If you're using immutable structures you need good GC. If your performance needs are such that you can't afford immutability, you can't afford a GC either.

xtal
Jan 9, 2011

by Fluffdaddy
Elm is great if you like enduring the horrors of front-end web development and the horrors of learning a new gimped language that has no other purpose than the horrors of front-end web development at the same time

xtal
Jan 9, 2011

by Fluffdaddy

9-Volt Assault posted:

so what is good way to do front-end web dev if you don't like JavaScript (besides not doing it at all :v: )? Purescript? Typescript? Some ocaml-to-js thing? React? Clojurescript?

HTML, CSS and as little JavaScript as possible. If you're using React you've already lost the battle

xtal
Jan 9, 2011

by Fluffdaddy

Shinku ABOOKEN posted:

Eh... it's not gimped that much v:shobon:v

Does it still only run in browsers because building and learning a language just for front end web dev is straight up farcical

Like at least use blaze-react or whatever

xtal
Jan 9, 2011

by Fluffdaddy
99.999% of UIs are that trivial and if you think you're the exception you're probably wrong but knock yourself out

xtal
Jan 9, 2011

by Fluffdaddy

NihilCredo posted:

Do you feel the same way about SQL ("building and learning a language just for relational databases is straight up farcical")?

That's pretty clearly apples-and-oranges. http://www.andl.org is straight up farcical and a better comparison

xtal
Jan 9, 2011

by Fluffdaddy
http://www.idris-lang.org/towards-version-1-0/

*starts countdown on uninstalling ghc*

kujeger posted:

to be fair, ten minutes on the internet is enough to drive most anyone to contempt

Ten years in this case. gently caress the web

xtal
Jan 9, 2011

by Fluffdaddy

Asymmetrikon posted:

God, I can't wait for Idris 1.0. It's already a really good language, and I'm interested in the final steps they're taking to get it stable and ready for that milestone.

Replacing effects with states is something that might take some getting used to - effects was a much better alternative to MTL, so I wonder what states is going to do to improve upon that?

I would be using Idris already if it had a package manager

xtal
Jan 9, 2011

by Fluffdaddy
What we need to do is make Nix not suck, then this problem will be permanently solved

xtal
Jan 9, 2011

by Fluffdaddy

Athas posted:

Does Idris produce decently efficient code nowadays? Does it have arrays? I remember that it was supposed to be more practical than Agda, but I also heard someone claim that runtime efficiency had gotten derailed a bit along the way. I don't know what to believe anymore!

It's decently efficient. Performance is, by their admittance, not a priority. You can generate more than just C, though. JavaScript, CLR, JVM and LLVM backends are under development by third-parties.

xtal
Jan 9, 2011

by Fluffdaddy

Jarl posted:

app : Vect n a -> Vect m a -> Vect (n + m) a

Is this a sort of thing we can expect in Haskell?

Yes, but not any time soon, and it will probably happen through ugly, arcane language extensions.

xtal
Jan 9, 2011

by Fluffdaddy

Doc Hawkins posted:

I was going to say that nix is already good, but then I remembered how much trouble people seem to have with git, and I admit it's not as good as git.

But really, everyone, please use nix.

code:
{
  config.language.quality = poo poo;
}
Maybe Guix solves this?

xtal
Jan 9, 2011

by Fluffdaddy

Shinku ABOOKEN posted:

Genuine question: What's the real world utility of dependent types?

Dependent types are p much the best CS invention in my short lifetime. They can theoretically eliminate runtime errors. Making your program total and terminating is sometimes an additional benefit.

xtal
Jan 9, 2011

by Fluffdaddy
Racket requires a runtime be installed so imho you might as well use Clojure. SBCL and Chicken can make static linked binaries from Common Lisp and Scheme code but they are hard to cross compile.

xtal
Jan 9, 2011

by Fluffdaddy
Does anyone know if Typed Racket or Clojure has support for quasi-dependent types? Gradual types seem like a nice compromise to me since you don't need to type absolutely​ everything​, and you can still statically verify them.

xtal
Jan 9, 2011

by Fluffdaddy
What is the best language to use on a Raspberry Pi? Haskell runs fine but lens has been compiling for over a day

xtal
Jan 9, 2011

by Fluffdaddy

VikingofRock posted:

How is ghc cross-compilation? Could you compile it on a different machine and then just move the binaries over?

It 's awful, but maybe I can compile to C or an intermediate LLVM code and finish the process on the pi. The problem is that my build pipeline doesn't really support that.

xtal
Jan 9, 2011

by Fluffdaddy

xtal posted:

What is the best language to use on a Raspberry Pi? Haskell runs fine but lens has been compiling for over a day

Ralith posted:

If you can live without being MAXIMUM FUNCTIONAL, rust's nice, and has a pretty good embedded story.

Self-quoting for context. How much of a coding horror would it be for me to make a Lisp syntax for Rust using Haskell and parsec?

xtal
Jan 9, 2011

by Fluffdaddy

Pollyanna posted:

I can understand why you'd want to write your systems and applications as a process tree, but I haven't yet developed a sense of what use cases those would be. I guess I haven't had a need to work on uptime critical systems before, but it sure sounds interesting. I got pretty far into LYAH, so maybe LYSE is up next.

Edit: I have to say, Elixir/Erlang, OTP and the BEAM are how I expected computer programs to work in the first place, so it's nice to see that I wasn't totally off.


As long as it isn't a security critical thing, :getin:

What implications would that have for security? Do you mean it's just silly to make our own language?

xtal
Jan 9, 2011

by Fluffdaddy
That's pretty much the status quo, as someone who uses w3m and surf with JavaScript off. Someone should have seen this horror show coming.

xtal
Jan 9, 2011

by Fluffdaddy
If you think the web is good enough I don't even know where to begin with that.

xtal
Jan 9, 2011

by Fluffdaddy

Ploft-shell crab posted:

I'm looking at Idris.

Can anyone shed some light on what's going on here:
code:
data Fin : Nat -> Type where
   FZ : Fin (S k)
   FS : Fin k -> Fin (S k)
I think I understand what Fin 5 represents, but what's going on with these constructors??

Do you notice a similarity between that type and the linked list? It's numbers represented at the type level by recursion. A function like 'length' on link lists could convert this type to an integer.

xtal
Jan 9, 2011

by Fluffdaddy
Any of you guys hosed with Idris? 1.0 just came out and I want to use it but there's still no package manager...

xtal
Jan 9, 2011

by Fluffdaddy
Having Idris use a general package manager would be way better than building another package manager for every single language but Nix looks kind of hacky and cruddy tbh

xtal
Jan 9, 2011

by Fluffdaddy
Yes. The difference is that Lisp has first class functions and also macros. First class functions let you build things from very small components like map and fold. Macros allow you to implement​ your own control flow structures which is not possible with C (afaik.)

xtal
Jan 9, 2011

by Fluffdaddy
core.async and core.typed are my favourite examples here. Goroutines and the type system are libraries not language

Adbot
ADBOT LOVES YOU

xtal
Jan 9, 2011

by Fluffdaddy
Clojure is very nice but I'm going to recommend Racket as well. Those are probably your two best bets. SBCL is blazing-fast and battle-tested but shows its age, and Lisp-2 semantics were never not awful.

  • Locked thread