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
Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
It's interesting that type classes would bloat the language, but record field addition/deletion was a-OK until they realized that it was useless.

Adbot
ADBOT LOVES YOU

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Do they already understand untyped/simply-typed lambda calculus, or are you trying to bypass those?

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Once you get used to them, it's nice to use pure functional languages that force you to cordon off side effects.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
"Where" means that they're defining a term used in the definition of the function. It may be a little easier to understand with 'let' syntax and some parens:

code:
greetIfCool :: String -> IO ()
greetIfCool coolness =
  let
    cool = (coolness == "downright frosty yo")
  in
    if cool
    then ...
    else ...
So we're saying that "cool"'s value is true if the argument coolness is equal to "downright frosty yo", then using "cool" as a Boolean value in the if statement.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
I was interested, so I did the following:

code:
recSum :: Num a => [a] -> a
recSum []    = 0
recSum (h:t) = h + badSum t

iterSum :: Num a => [a] -> a
iterSum = iterSum' 0
  where
    iterSum' a []    = a
    iterSum' a (h:t) = iterSum' (a + h) t

foldlSum :: Num a => [a] -> a
foldlSum = foldl (+) 0

foldrSum :: Num a => [a] -> a
foldrSum = foldr (+) 0

testSum :: ([Int] -> Int) -> Int
testSum f = f $ take 10000000 $ repeat 5

code:
*Main> :set +s
*Main> testSum recSum
50000000
(6.60 secs, 2,271,440,152 bytes)
*Main> testSum iterSum
50000000
(6.57 secs, 2,337,734,568 bytes)
*Main> testSum foldlSum
50000000
(3.32 secs, 1,453,817,584 bytes)
*Main> testSum foldrSum
50000000
(2.24 secs, 1,373,478,464 bytes)
So the builtins do seem to have a significant speed increase over the custom functions.

The real reason to use things like map and fold is for simplicity (most recursive functions follow similar forms which can be abstracted out), but you might also get efficiency gains?

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
I've seen a lot of people online doing an Elixir backend and an Elm frontend, and it seems like it works pretty well. Plus, you learn about two wholly different styles of functional programming (impure, dynamic typed, concurrent vs. pure, static typed, non-concurrent.)

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Redux heavily borrows from Elm's Architecture, and Elm has an equivalent to React in elm-html. If you're comfortable in one, you'll very likely be comfortable in the other.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
I like Idris over Haskell because of some of the historical weirdness it got rid of (switching : and ::, returning Maybe instead of erroring in, i.e., List access functions, the whole Monad/Applicative thing, Int vs. Integer.) I haven't looked too much into GHC 8, though.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
I do like the way Elixir handles local refs - it allows rebinding of names, but the (|>) operator makes it easy to elide names of intermediate forms if you want, so you can just use whichever approach is more appropriate based on the situation. It's kind of annoying that the forms that it allows on the right hand side of the pipe are pretty limited, though (no anonymous functions is the one I really wish it would allow.)

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Glad they finally got the time-traveling debugger working the way they wanted it to.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Making "x |> andThen y" canonical matches with the way all other functions work (the entity they operate on is the last input to the function), so I'm happy about that. I really like the error improvements, especially making type annotations provide more context to errors.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
None, front end is basically forsaken ground. Elm is the best we got, followed by React/Redux.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Elm has a REPL, and has had one for a long time. Also, I'd say that the biggest problem with languages for front-end web dev up to now (Javascript) is that most general functionality is entirely useless for the task at hand, and a language specifically geared to making websites could be - and, in the case of Elm, is - much better.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
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?

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

gonadic io posted:

Well you know what to do! Every language needs a bespoke plugin manager where the config files are a subset of the language itself.

Now I'm wondering how dependent types would effect the expression of packages. Maybe you could have a function

code:
package : String -> Nat -> Type
and to successfully compile, the package manager would provide a proof of that type (the downloaded package)? So the total program proof would rely on the proofs of each of the
packages, which is a version downloaded that matches the specification. You could replace the Nat with a more relaxed bound, perhaps some kind of Version type.

...on second thought, maybe someone can just make a Maven plugin for this stuff. Or just use Nix.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

Jarl posted:

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

You can kind of hack this into Haskell at the moment - if you use the DataKinds language feature, you can get type-level Nats (and other inductive types), which can be used in those kind of type definitions (see this article for more). It's very limited, though.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
In general, it allows you to use the type-checker as a more general theorem prover - using the same principles of checking if a value will always be an Int, you can extend that to check if a value will always be an Int that is between 0 and 255. It's basically using types as specifications of what the program actually means (the idea is that you can encode arbitrary amounts of information in types to asymptotically approach a compile-time check that verifies literally all the features you want from your program. Obviously, we're no where near there, and it's not likely that's a reachable goal, but dependent types let you opt in to compile time checking of interesting guarantees.)

In some arguments, this is meant to take the place of unit tests - instead of writing tests that run a function and check, for some set of inputs, that the outputs are the ones you expect, you can use dependent types to encode in the type of the function that the function will only ever return types you expect (like the type of (++) on Vect embedding the length, ensuring that the Vect you get back is of the correct length.) Theoretically, you could, instead of unit tests of some abstract property, use dependent typing to create functions that express proofs of properties of your system (like the associativity of operations, or invariants of functions.)

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Right - we're trying to reduce the domain of our functions to exactly the ones we're interested in, where traditional typed programming makes us write functions that accept a whole bunch of stuff that we don't care about and don't ever want as input, but have to acknowledge because we need to have total functions over whatever input type we use.

To some extent, what these dependent types let us do is move specification from the output of a function, where we weaken the image of the function to allow for more inputs, to a function where we've strengthened the domain instead (for example - Haskell List head operates on all Lists, but will error on an empty list; Idris Vects operate only on non-empty lists, and guarantee that they don't error.) This does sometimes constitute a burden when calling a function (having to provide proof of a non-empty list), but allows us to use the result of functions much more easily (not having to care about errors; we can also get rid of a lot of functions that return Maybe a by restricting the input type to only inputs that would allow defined outputs, which means when we call those functions, we can assume that we have valid output.)

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

Ralith posted:

e: Whoops, this has already been answered thoroughly. Oh well.
No, you did bring up a great point - because of greater specification of types, dependently typed languages allow the compiler to do way more generation of code than ordinary type systems; that's one of the subjects Edwin Brady was interested in (you can see one of his talks about this here.)

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Another interesting approach to encoding/checking code is Dafny.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Not sure I quite understand, but "a ++ b" concatenates two lists. The second clause of squish returns x ++ squish xs, where x is a list and squish xs is also a list. If we apply it to [[1,2,3],[4,5]], we match like:

code:
squish [[1,2,3],[4,5]]
squish ([1,2,3]:[[4,5]])       -- desugar list
[1,2,3] ++ squish [[4,5]]      -- match on second clause of squish
[1,2,3] ++ squish ([4,5]:[])   -- desugar list
[1,2,3] ++ [4,5] ++ squish []  -- match on second clause of squish
[1,2,3] ++ [4,5] ++ []         -- match on first clause of squish
[1,2,3] ++ [4,5]               -- concatenate
[1,2,3,4,5]                    -- concatenate

Asymmetrikon fucked around with this message at 07:19 on Jan 2, 2017

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Not exactly sure of the source of confusion - when you say "I don't think it's a function call because it's not given a parameter", what do you mean specifically? (calculatePrefixFunction "DEBUG") returns a function, which is stored in the variable prefixer. This function is then applied to "My message", returning the prefixed message.

e: Maybe a translation into pseudo-C# could help?

code:
public Function<string, string> calculatePrefixFunction(String prefix)
{
    String prefix' = Printf.sprintf("[%s]:", prefix);
    Function<string, string> prefixFunction = (String appendee) =>
        Printf.sprintf("%s%s", prefix', appendee);
    return prefixFunction;
}

Function<string, string> prefixer = calculatePrefixFunction("DEBUG");

printfn("%s", prefixer.Apply("My message"));  // C# treats function objects and functions differently, requiring a .Apply or whatever, while F# doesn't.

Asymmetrikon fucked around with this message at 18:36 on Jan 17, 2017

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Yeah, that's exactly right. Functional languages are big on tossing around functions as concrete things (usually described as them being first-class constructs like any other data.)

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
I'm not super sure how F# handles it, but most functional languages (that I use, anyway) don't do references; they always copy.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

xtal posted:

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?

Well, I'm doing this for C (with intent to create a lot of macros to automatically do generics/monomorphisation/better types/etc.,) so I'd be a hypocrite if I didn't say go for it :getin:

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

Ralith posted:

Not to be an evangelist or anything, but FYI Rust is basically what you get if you start with C and add all those things. Maybe have a look!

Oh, I've written a fair amount of Rust, and I would totally use it for any actual serious low-level work I'd want to do. This is just for my own curiosity - I have some ideas about macros and reinterpretation of Sized types that I want to test out.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
They wrote Haxl, a library for remote data retrieval (like SQL, I suppose?) Haskell is pretty good for server-side web-based stuff like APIs. Also parsing and language design.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Fin n represents a finite set of size n (where n is greater than 0) - so like the natural numbers, but bounded by n.

FZ is the zero element, which is a member of all finite sets. You can think of its constructor as "for all natural numbers n, FZ is a member of Fin n iff n is greater than zero".

FS is the successor function; pretty much the same as the Nat successor.

Probably a point of confusion is that FZ and FS can inhabit multiple different types. FZ is a member of Fin 1, Fin 2, and so on. The finite sets are generated inductively, so Fin (S n) contains all of the elements of Fin n, plus FS applied on the greatest element. If we look at the members of each of the Fin instances, we see:

Fin 0 {}
Fin 1 {FZ}
Fin 2 {FZ, FS FZ}
Fin 3 {FZ, FS FZ, FS FS FZ}
...

So (FS FS FS FZ) is a member of Fins 4+.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
I'm not super familiar with Scala, but from a Haskell POV, you might have an Event ADT like:
code:
type Event
    = ClickEvent Click
    | KeyEvent Key
    | FooEvent Foo
and if you had an enhancement for Click, Key, and Foo, you'd make a function:
code:
enhance :: Event -> Event
enhance (ClickEvent click) = ClickEvent $ enhanceClick click
enhance (KeyEvent key) = KeyEvent $ enhanceKey key
enhance (FooEvent foo) = FooEvent $ enhanceFoo foo
where enhanceClick, enhanceKey, and enhanceFoo are specific enhancers for each sub-type.

That's if the enhancement function for each sub-event type returned the same type of event; otherwise, you'd either have to add more things to the Event or make an EnhancedEvent or something.

Adbot
ADBOT LOVES YOU

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Haven't used it since they moved from Effects to Control.ST (still wrapping my head around that), probably going to get back into it now that it's got a concrete release and see if I can contribute. A package manager would definitely be a good thing.

  • Locked thread