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.
 
  • Post
  • Reply
Vanadium
Jan 8, 2005

in my hubris i keep writing shell scripts that inevitably grow to the point where I want to say "ok and now spawn a couple threads and then use channels to combine the results again" and then it turns out bash isn't go

Adbot
ADBOT LOVES YOU

Shaggar
Apr 26, 2006

jony neuemonic posted:

perl's great at working with text and faking a portable unix. there's really no way it was going to be bad for scripting.

its actually the worst at everything

Carthag Tuek
Oct 15, 2005

Tider skal komme,
tider skal henrulle,
slægt skal følge slægters gang



Shaggar posted:

its actually the worst at everything

-pe 's/worst/best/g'

Arcsech
Aug 5, 2008

Shaggar posted:

its actually the worst at everything

hey man, I'm no fan of perl but at least it's not php

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Vanadium posted:

in my hubris i keep writing shell scripts that inevitably grow to the point where I want to say "ok and now spawn a couple threads and then use channels to combine the results again" and then it turns out bash isn't go
that sounds like a routine shell programming task 2 me

Ator
Oct 1, 2005

i went with haskell because new irl friend is also learning the language with me :3:

fyi bash scripting is utter garbage and only bitter old men use it
bash is worse than javascript even

Ator
Oct 1, 2005

this haskell error tripped me up for a while:

code:
wtf :: String -> String
wtf str = do
    return "wtf: " ++ str
error:
* Couldn't match type `Char' with `[Char]'
Expected type: [[Char]]
Actual type: String
* In the second argument of `(++)', namely `str'
In a stmt of a 'do' block: return "wtf: " ++ str
In the expression: do { return "wtf: " ++ str }

where did the [[Char]] come from?

code:
Prelude> :t return "hello"
return "hello" :: Monad m => m [Char]
so 'return' is a function that produces a monad??

you're not supposed to use 'return', this isn't C.
this works:

code:
wtf :: String -> String
wtf str = do
    "wtf: " ++ str

Carthag Tuek
Oct 15, 2005

Tider skal komme,
tider skal henrulle,
slægt skal følge slægters gang



Ator posted:

this haskell error tripped me up for a while:

code:
wtf :: String -> String
wtf str = do
    return "wtf: " ++ str
error:
* Couldn't match type `Char' with `[Char]'
Expected type: [[Char]]
Actual type: String
* In the second argument of `(++)', namely `str'
In a stmt of a 'do' block: return "wtf: " ++ str
In the expression: do { return "wtf: " ++ str }

where did the [[Char]] come from?

code:
Prelude> :t return "hello"
return "hello" :: Monad m => m [Char]
so 'return' is a function that produces a monad??

you're not supposed to use 'return', this isn't C.
this works:

code:
wtf :: String -> String
wtf str = do
    "wtf: " ++ str

son i cant talk about this its got too may layers

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Ator posted:

fyi bash scripting is utter garbage and only bitter old men use it
*better

brap
Aug 23, 2004

Grimey Drawer
in the context you're in, return is a function that takes some argument and produces a list containing that argument as its only element. So you basically did (return "wtf: ") ++ str, which is like doing ["wtf: "] ++ str

basically, this is happening because haskell people generalize poo poo compulsively and most of it is silly and useless

brap fucked around with this message at 07:48 on Feb 19, 2017

sarehu
Apr 20, 2007

(call/cc call/cc)
that was a nice writeup rjmccall

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

fleshweasel posted:

in the context you're in, return is a function that takes some argument and produces a list containing that argument as its only element. So you basically did (return "wtf: ") ++ str, which is like doing ["wtf: "] ++ str

basically, this is happening because haskell people generalize poo poo compulsively and most of it is silly and useless

even if you accept all the generalizations, there are like three major language design fuckups here

the first is that the consensus call syntax in non-sexpr functional languages is terrible bullshit that trips newcomers up brutally all the time

the second is that you can just put "do" there and it does nothing, completely accidentally, unless it fails to compile for reasons that once again make no sense to newcomers

the third is that "return" is such an appallingly bad name for that operation that i can only imagine it was chosen as a placeholder that never got fixed (like most functional language and library "design")

gonadic io
Feb 16, 2011

>>=
yeah, 'return' is badly named and trips up people every single loving time

String showing up as [Char] in error messages isn't good either

last time i checked you got a pretty unhelpful error message for doing this too:
'c' ++ "butt"

e: i didn't even notice the 'do' lol

e2: this is what you want:

wtf :: String -> String
wtf str = "wtf: " ++ str

only use 'do' and 'return' when you're doing IO (to start with)

gonadic io fucked around with this message at 09:03 on Feb 19, 2017

Athas
Aug 6, 2007

fuck that joker

rjmccall posted:

the first is that the consensus call syntax in non-sexpr functional languages is terrible bullshit that trips newcomers up brutally all the time

What is this?

rjmccall posted:

the third is that "return" is such an appallingly bad name for that operation that i can only imagine it was chosen as a placeholder that never got fixed (like most functional language and library "design")

I think the motivation for this was to write cute imperative-like code. "See, it even ends with a return, like in C!" Agreed it is stupid, and most Haskell people think it is stupid, too.

But functional languages are good and pretty.

Sinestro
Oct 31, 2010

The perfect day needs the perfect set of wheels.
I'm probably gonna keep it around as an alias or whatever, but pure is the much better name.

Workaday Wizard
Oct 23, 2009

by Pragmatica
someone explain do syntax to me please 😁

redleader
Aug 18, 2005

Engage according to operational parameters
it's monads. nothing but monads

gonadic io
Feb 16, 2011

>>=

Shinku ABOOKEN posted:

someone explain do syntax to me please 😁

yeah it's used for threading monad computations. in a gross simplification you can use it to "get" a value out of a monad (usually IO) to do stuff with it

the restriction is that the thing you want to return has to be in the monad too. so if the last thing you do is like printLine which returns "IO ()" then you're fine and don't need return:

code:
printWtf :: IO ()
printWtf = do
   x <- getLine
   let y = "wtf " ++ x
   println y

however if you want to return a pure value from a do-block then you need to wrap it in return. there is NO other use case for return until you're using more complicated monads

code:
getWtf :: IO String
getWtf = do
   x <- getLine
   let y = "wtf " ++ x
   return y
so do notation basically means that you can't escape IO - the moment you use any IO function, you are stuck in the IO monad forever. (this is why you want to split all the computations you can into their own pure function that does all the processing and then just call it in the do-block)

i can't really think of any use for do-notation other than for IO ffor beginners. it technically works with lists and options and stuff but imo don't use it until you know how it works behind the scenes

i'm happy to do a post on what it actually means if people want (all continuations all the time), but this is a crash course into how to use it without looking like an idiot.

in short: it threads around values from IO. it's syntactic sugar so "<-" is not a function with a type or anything.

gonadic io fucked around with this message at 12:09 on Feb 19, 2017

Workaday Wizard
Oct 23, 2009

by Pragmatica

gonadic io posted:

yeah it's used for threading monad computations. in a gross simplification you can use it to "get" a value out of a monad (usually IO) to do stuff with it

the restriction is that the thing you want to return has to be in the monad too. so if the last thing you do is like printLine which returns "IO ()" then you're fine and don't need return:

code:
printWtf :: IO ()
printWtf = do
   x <- getLine
   let y = "wtf " ++ x
   println y

however if you want to return a pure value from a do-block then you need to wrap it in return. there is NO other use case for return until you're using more complicated monads

code:
getWtf :: IO String
getWtf = do
   x <- getLine
   let y = "wtf " ++ x
   return y

so do notation basically means that you can't escape IO - the moment you use any IO function, you are stuck in the IO monad forever. (this is why you want to split all the computations you can into their own pure function that does all the processing and then just call it in the do-block)

i can't really think of any use for do-notation other than for IO ffor beginners. it technically works with lists and options and stuff but imo don't use it until you know how it works behind the scenes

i'm happy to do a post on what it actually means if people want (all continuations all the time), but this is a crash course into how to use it without looking like an idiot.

in short: it threads around values from IO. it's syntactic sugar so "<-" is not a function with a type or anything.

does do notation get any special treatment in the compiler/type system? from what i understand it's 100% sugar.

also does any other func lang have something similar?

gonadic io
Feb 16, 2011

>>=

Shinku ABOOKEN posted:

does do notation get any special treatment in the compiler/type system? from what i understand it's 100% sugar.

also does any other func lang have something similar?

nope*, gets compiled into using the standard method >>=

scala's for-comprehensions and f# computation expressions suit the same need, it comes up when you're e.g. playing around with futures and find yourself with code that chains computations like (in rust)
get_butt().and_then(|butt| butt.get_fart().and_then(|fart| ...))

for an example of doing this in c++ see https://bartoszmilewski.com/2014/02/26/c17-i-see-a-monad-in-your-future/


*: okay yes technically but it's only a tiny tiny hack when it's used with $ to make stuff like
code:
 runST $ do 
    foo 
    bar 
work and not be monomorpised

gonadic io fucked around with this message at 13:04 on Feb 19, 2017

Athas
Aug 6, 2007

fuck that joker

gonadic io posted:

i can't really think of any use for do-notation other than for IO ffor beginners. it technically works with lists and options and stuff but imo don't use it until you know how it works behind the scenes

Do-notation is super widespread and super useful for all monadic Haskell code, even if it doesn't use any IO. I've written a 40k SLOC Haskell program that has no IO apart from initial and terminal faffing about with files, and I use do-notation all over the place.

I would never use do-notation in a teaching context, though. It obscures what's going on.

gonadic io
Feb 16, 2011

>>=

Athas posted:

Do-notation is super widespread and super useful for all monadic Haskell code, even if it doesn't use any IO. I've written a 40k SLOC Haskell program that has no IO apart from initial and terminal faffing about with files, and I use do-notation all over the place.

I would never use do-notation in a teaching context, though. It obscures what's going on.

what monads? list, maybe, state, and then your parser of choice?

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

Ator posted:

i went with haskell because new irl friend is also learning the language with me :3:

fyi bash scripting is utter garbage and only bitter old men use it
bash is worse than javascript even

if they're really old they use rexx

ComradeCosmobot
Dec 4, 2004

USPOL July

Vanadium posted:

in my hubris i keep writing shell scripts that inevitably grow to the point where I want to say "ok and now spawn a couple threads and then use channels to combine the results again" and then it turns out bash isn't go

fork a couple subshells which write to some fifos and then cat the results together maybe?

i did something similar recently to pipe a sample video to three x264 processes with different compression settings (although in this case the processes read from a single input pipe that was tee'd to the fifos, rather than the other way around)

it worked alright, though you do wanna keep track of those pids to know when they've finished using "wait"

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Athas posted:

What is this?

But functional languages are good and pretty.

most core design decisions in functional languages are made by academics who are way more interested in the underlying ideas than they are in the implications for the usability of the language

the call syntax, where you just juxtapose the function and its arguments, is really pretty in simple cases, but it isn't something programmers will have seen in other languages, and it isn't common in math notation (outside of trigonometry). so when novices try to use it they write stuff like "foo hd:tl" or "foo bar(baz)" and get inscrutable errors because the mistake is really a mis-parse, not anything semantic. the second one is particularly bad because the programmer probably thinks they've disambiguated it by "not leaving out the parentheses". to be fair, this is all worse in ml-derivatives than in haskell because they don't emphasize currying so much and so the one-argument unparenthesized call feels more like a special case

and haskell doubles down on it by adding $ into the mix so experts can avoid parentheses even more while novices have even less of an idea what's going on

Cybernetic Vermin
Apr 18, 2005

currying all over the language and library is a sure sign that it is designed by someone far too busy with how clever they are to think about what a program will look like

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS
i've asked and never seen an example of haskell in the wild. i have no concept of what lob haskell looks like.

Shaggar
Apr 26, 2006
"functional" languages are not designed for programming, they're designed for academic exercises. theres no such thing as lob Haskell

Sinestro
Oct 31, 2010

The perfect day needs the perfect set of wheels.

rjmccall posted:

most core design decisions in functional languages are made by academics who are way more interested in the underlying ideas than they are in the implications for the usability of the language

the call syntax, where you just juxtapose the function and its arguments, is really pretty in simple cases, but it isn't something programmers will have seen in other languages, and it isn't common in math notation (outside of trigonometry). so when novices try to use it they write stuff like "foo hd:tl" or "foo bar(baz)" and get inscrutable errors because the mistake is really a mis-parse, not anything semantic. the second one is particularly bad because the programmer probably thinks they've disambiguated it by "not leaving out the parentheses". to be fair, this is all worse in ml-derivatives than in haskell because they don't emphasize currying so much and so the one-argument unparenthesized call feels more like a special case

and haskell doubles down on it by adding $ into the mix so experts can avoid parentheses even more while novices have even less of an idea what's going on

you're a really smart dude and basically everything that I want to be, but I have to disagree

it's true that "it isn't something programmers will have seen in other languages", but that's a really scary, bad precedent to set as a rule for language features, especially because with any other syntax currying is absolute trash unless you special case stuff everywhere and I don't think that "oh, just have func(x, y, z) be func(x)(y)(z) is any better, since it's not like func(x, y) :: z -> a is less startling.

honestly, it should be different because it is fundamentally a different operation than procedural language function calls. it's not loading stuff into registers and then using your architecture's equivalent of call/ret at a conceptual level, term rewriting implementations aren't used because of terrible performance but the fact it is an actual function call is just an implementation detail of no direct relevance to a programmer who is unfamiliar enough to get tripped up by that syntax.

brap
Aug 23, 2004

Grimey Drawer
currying is a silly gimmick at best and makes your code too spicy (unreadable, useless) at worst

Smoke_Max
Sep 7, 2011

I think currying owns and I miss it (at least in its convenient form) every time I'm coding in languages like C++. v0v

kitten emergency
Jan 13, 2008

get meow this wack-ass crystal prison

Blinkz0rz posted:

i've asked and never seen an example of haskell in the wild. i have no concept of what lob haskell looks like.

code:
 

there u go

gonadic io
Feb 16, 2011

>>=
let's just ask our favourite non-biased source, the haskell wiki

https://wiki.haskell.org/Haskell_in_industry

sarehu
Apr 20, 2007

(call/cc call/cc)
lol Bump

Athas
Aug 6, 2007

fuck that joker

gonadic io posted:

what monads? list, maybe, state, and then your parser of choice?

In larger Haskell programs, you usually construct stacks of monads to support whatever effects you need for the task at hand. Each stack is a unique monad. A combination of Maybe (or some other error monad), Reader, and State is pretty common. Just today I worked on a type checker that was a composition of six or seven monad combinators (separated into two distinct layers - it's confusing if you have two visible layers that expose similar effects). And then you get to write code like:

code:
checkSpecs (IncludeSpec e loc : specs) = do
  (e_env, e') <- checkSigExp e
  (env, specs') <- localEnv (e_env<>) $ checkSpecs specs
  return (e_env <> env,
          IncludeSpec e' loc : specs')

rjmccall posted:

most core design decisions in functional languages are made by academics who are way more interested in the underlying ideas than they are in the implications for the usability of the language

the call syntax, where you just juxtapose the function and its arguments, is really pretty in simple cases, but it isn't something programmers will have seen in other languages, and it isn't common in math notation (outside of trigonometry). so when novices try to use it they write stuff like "foo hd:tl" or "foo bar(baz)" and get inscrutable errors because the mistake is really a mis-parse, not anything semantic. the second one is particularly bad because the programmer probably thinks they've disambiguated it by "not leaving out the parentheses". to be fair, this is all worse in ml-derivatives than in haskell because they don't emphasize currying so much and so the one-argument unparenthesized call feels more like a special case

While I'm totally an ivory tower academic, I'm working on a language myself, and I care a lot about making the language usable for others. I thought a lot about the issue of function call syntax, and eventually opted for picking the usual functional application-by-juxtaposition notation. You're right that it's alien to some, but it's conceptually quite simple in a pure language, because application is just substitution (modulo strictness). And given that FP is (slowly) gaining ground, an increasing number of programmers will have seen something like this in Scala or F# or whatever is the vanguard these days.

Most of your concerns are about new programmers. That's pretty reasonable, but I don't think a language design should optimise primarily for programmers who are new to the language, as most won't stay that way for long. Ultimately, the main reason I ended up making most of my syntax decisions was that I felt I couldn't be sure of the quality of the design unless I designed a language that I would want to use. I have little idea how to judge what other people find cool and good, so I just tried to keep it both simple and pretty according to my own sense of aesthetics.


The application-by-juxtaposition notation does have one problem, in that it can be tricky so support usual a[i] array index notation. Most functional languages would see a[i] as applying 'a' to the singleton list '[i]'. In my case, I solved it by treating it specially in the parser when there is no space between a name and an opening bracket. F# solves it by requiring you to write a.[i] I think.

raminasi
Jan 25, 2005

a last drink with no ice

Athas posted:

I have little idea how to judge what other people find cool and good, so I just tried to keep it both simple and pretty according to my own sense of aesthetics.

good enough for ruby, good enough for you

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Sinestro posted:

honestly, it should be different because it is fundamentally a different operation than procedural language function calls. it's not loading stuff into registers and then using your architecture's equivalent of call/ret at a conceptual level

universities often teach assembly-level concepts at the same time they teach c because c has a relatively straightforward compilation model and abi, meaning students can really easily see how the c code they write corresponds to what the compiler produces, not because that's literally the level at which semantics are defined for procedural languages. you could do the same thing for any compiled language, but you'd have to explain a lot more about (say) haskell than you would for c, like why the compiler seems to be assuming strictness here and not there. anyway the point is you can write a naive interpreter for c, it would just create a lot more mutable reference cells than a naive interpreter for ml would, because surprise it's an imperative language. the main difference between c semantics and functional semantics beyond mutability is just that c has a lot of undefined-behavior rules to allow a more efficient implementation, but that is an intentional choice, not a consequence of c really being defined in terms of a naive lowering to assembly

actually it's a fairly regular source of annoyance to (some) systems programmers that c has high-level semantics which compilers can use to optimize allocations, memory accesses, calls, etc.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Athas posted:

While I'm totally an ivory tower academic, I'm working on a language myself, and I care a lot about making the language usable for others. I thought a lot about the issue of function call syntax, and eventually opted for picking the usual functional application-by-juxtaposition notation. You're right that it's alien to some, but it's conceptually quite simple in a pure language, because application is just substitution (modulo strictness). And given that FP is (slowly) gaining ground, an increasing number of programmers will have seen something like this in Scala or F# or whatever is the vanguard these days.

Most of your concerns are about new programmers. That's pretty reasonable, but I don't think a language design should optimise primarily for programmers who are new to the language, as most won't stay that way for long. Ultimately, the main reason I ended up making most of my syntax decisions was that I felt I couldn't be sure of the quality of the design unless I designed a language that I would want to use. I have little idea how to judge what other people find cool and good, so I just tried to keep it both simple and pretty according to my own sense of aesthetics.


The application-by-juxtaposition notation does have one problem, in that it can be tricky so support usual a[i] array index notation. Most functional languages would see a[i] as applying 'a' to the singleton list '[i]'. In my case, I solved it by treating it specially in the parser when there is no space between a name and an opening bracket. F# solves it by requiring you to write a.[i] I think.

i mean, it's your language, it's your taste, don't mind me. i don't see what the simplicity of application being substitution (as if this is somehow untrue of other languages?) has to do with the syntax, though, since notably mathematics has literally no concept of evaluation and seems to get along just fine with f(x)

i agree that partial application is very clean with juxtaposition, but i also tend to think that functional programmers (1) over-estimate how often they're actually partially applying functions, probably due to cognitive bias, and (2) wildly over-use point-free style, which was never intended to be actual programming advice as opposed to an interesting mental exercise

Destroyenator
Dec 27, 2004

Don't ask me lady, I live in beer
the fsharp pipelining operator makes partial application really common, useful and readable fwiw

Adbot
ADBOT LOVES YOU

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
how often is it really partial application vs. non-application? alternatively, how often are you really using arbitrary functions instead of map/filter/whatever which could be designed for this use-case?

also if you really wanted to make partial application easier it wouldn't be hard to add syntax like f(_,x), and then it even works for an arbitrary argument

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply