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
gonadic io
Feb 16, 2011

>>=

fart simpson posted:

i dont mean to be rude but are you sure you took a haskell class at the literal haskell place?

he's doing panic revision, the exam's probably tomorrow and he hasn't slept in 2 days. he probably stared blankly at that code for like 30 mins in a fatigued state before giving up and posting here

or at least, that's the generous interpretation

Adbot
ADBOT LOVES YOU

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

fleshweasel posted:

wow is he completely loving the indentation on the code in order to up the challenge or something

the indentation seems ok except for the comment at the top with the example string to parse. the indentation in the input string doesnt really matter, you just need to get a basic idea of what you're dealing with for the given parsers

gonadic io
Feb 16, 2011

>>=

Ploft-shell crab posted:

This seems absolutely awful and makes me like Haskell less

don't use singly-linked lists for strings and you won't be bitten by this. i really really hate the fact that the good string type that uses arrays, "Data.Text", is in a library whereas the default "String" has absolutely horrendous performance and a whole load of gotchas like this but because it's easy to define* it's in the standard library :(

pretty much every single "i just learnt haskell but why is this simple string manipulation program so slow???" can be attributed to this

*:
code:
type String = List Char
data List a
    = Nill
    | Cons a (List a)

gonadic io fucked around with this message at 19:59 on Apr 28, 2015

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

gonadic io posted:

he's doing panic revision, the exam's probably tomorrow and he hasn't slept in 2 days. he probably stared blankly at that code for like 30 mins in a fatigued state before giving up and posting here

or at least, that's the generous interpretation

yeah sorry i know this is supposed to be a safe space i wont say anything bad anymore

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

gonadic io posted:

don't use singly-linked lists for strings and you won't be bitten by this. i really really hate the fact that the good string type that uses arrays, "Data.Text", is in a library whereas the default "String" has absolutely horrendous performance and a whole load of gotchas like this but because it's easy to define* it's in the standard library :(

*:
code:
type String = List Char
data List a
    = Nill
    | Cons a (List a)

yeah it's dumb and nobody that knows anything is using String for anything real

triple sulk
Sep 17, 2014



i know i'm a terrible programmer but gently caress the web-based and timed coding challenge websites. they're a god drat blight

poty
Jun 21, 2008

虹はどこで終わるのですか? あなたの魂の中で、または地平線で?

fleshweasel posted:

i guess the mongodb people were thinking of the word "humongous" when they made the name but somehow didn't realize that the rest of the world would think "mongoloid...wait wtf?"

its like if they called it niggerdb and said "but we were thinking of the word niggardly, like our database is so niggardly with your resources!"

VikingofRock
Aug 24, 2008




So while we are on the subject of Haskell folds, here's something I've never understood: why doesn't foldr space leak the way that foldl does? I've read both LYAH and RWH and I'm still really confused by that.

crazypenguin
Mar 9, 2005
nothing witty here, move along

gonadic io posted:

(++) is perhaps the best example for lazy evaluation making it hard to reason about code.

well, this is nothing to do with lazy evaluation. you'll see the same thing in even java when working with an immutable list data structure.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

VikingofRock posted:

So while we are on the subject of Haskell folds, here's something I've never understood: why doesn't foldr space leak the way that foldl does? I've read both LYAH and RWH and I'm still really confused by that.

doesnt it depend on the strictness of your arguments? like there's a reason you dontwalways choose foldr. the haskell wiki article explains it pretty nicely i think: https://wiki.haskell.org/Foldr_Foldl_Foldl%27

basically i think the idea is that if your function that consumes the input list can short circuit, then you're better off using foldr, but if it needs both arguments to compute a value then you're better off with foldl'

code:
foldr (+) 0 [1..1000000] -->
1 + (foldr (+) 0 [2..1000000]) -->
1 + (2 + (foldr (+) 0 [3..1000000])) -->
vs.
code:
foldl' (+) 0 [1..1000000] -->
foldl' (+) 1 [2..1000000] -->
foldl' (+) 3 [3..1000000] -->
so in that case foldl' is better because (+) can't short circuit and return a value early if it meets a certain condition. if instead of + you were using && or something, then you'd want the foldr way of doing things.

i think.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

i dont know why foldl exists or at least why foldl' isn't the default one instead. it seems like any time you'd reach for foldl what you really want is foldl'

gonadic io
Feb 16, 2011

>>=

crazypenguin posted:

well, this is nothing to do with lazy evaluation. you'll see the same thing in even java when working with an immutable list data structure.

wait, but in a lazy language wouldn't evaluating the first few elements of `xs ++ (ys ++ zs)' be pretty much instant since yz and zs won't be touched at all, whereas `(xs ++ ys) ++ zs' at least has to pass through n-1 appends, where there are n lists being appended?

i suppose that won't make too much difference you're right, it's far more a consequence of immutability but the laziness does make it more pronounced i think

VikingofRock posted:

So while we are on the subject of Haskell folds, here's something I've never understood: why doesn't foldr space leak the way that foldl does? I've read both LYAH and RWH and I'm still really confused by that.

this isn't quite the case, have a read of https://wiki.haskell.org/Foldr_Foldl_Foldl%27 and if you still have questions i'd be happy to answer them

to directly answer your questions, foldl causes heap overflows and foldr causes stack overflows BUT foldr can produce its output incrementally whereas foldl has to produce it all in one go. for ints it's the same but for lists foldr can chug along bit-by-bit without necessarily consuming all the memory at once (it's very dependent on what you do with the result afterwards, and again, lazy evaluation means that maybe it'll be fast maybe it'll be slow who knows it depends on everything else)

gonadic io fucked around with this message at 20:37 on Apr 28, 2015

gonadic io
Feb 16, 2011

>>=

fart simpson posted:

i dont know why foldl exists or at least why foldl' isn't the default one instead. it seems like any time you'd reach for foldl what you really want is foldl'

gently caress, beaten

also yes, i can't imagine a situation where you'd use foldl over foldl'

gonadic io
Feb 16, 2011

>>=

fart simpson posted:

so in that case foldl' is better because (+) can't short circuit and return a value early if it meets a certain condition. if instead of + you were using && or something, then you'd want the foldr way of doing things.

i think.

this bit isn't right (heh) though, foldl will still short-circuit:
code:
> foldl (&&) True [True, False, undefined]
False
> foldl' (&&) True [True, False, undefined]
False
> foldr (&&) True [True, False, undefined]
False
it's not about the operator short-circuiting, it's that foldr consumes the list as it goes whereas foldl traverses the whole spine of the list before it can produce a result

code:
> foldr (&&) True (True : False : undefined)
False
> foldl (&&) True (True : False : undefined)
*** Exception: Prelude.undefined
if this behaviour isn't useful to you (for example ints, etc) then foldl' happens in constant space. basically foldr is for lazy data structues (List, Map, Set, etc) and foldl' is for concrete structures (arrays, ints, bools, etc)

gonadic io fucked around with this message at 21:09 on Apr 28, 2015

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

gonadic io posted:

wait, but in a lazy language wouldn't evaluating the first few elements of `xs ++ (ys ++ zs)' be pretty much instant since yz and zs won't be touched at all, whereas `(xs ++ ys) ++ zs' at least has to pass through n-1 appends, where there are n lists being appended?

i suppose that won't make too much difference you're right, it's far more a consequence of immutability but the laziness does make it more pronounced i think

im new at this so maybe im wrong but i would say the problem is using a linked list as a string type. in a strict language the situation isnt much better, they'll both be pretty slow (the second one will still be slower i believe). i guess if you're going to blame laziness, its that it makes this scheme workable at all so long as you're careful, but as soon as you arent it becomes as slow as doing it strictly.

gonadic io
Feb 16, 2011

>>=

HappyHippo posted:

im new at this so maybe im wrong but i would say the problem is using a linked list as a string type. in a strict language the situation isnt much better, they'll both be pretty slow (the second one will still be slower i believe). i guess if you're going to blame laziness, its that it makes this scheme workable at all so long as you're careful, but as soon as you arent it becomes as slow as doing it strictly.

this is exactly right

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?
also can't you avoid the whole problem by not using the parenthesis at all?

MononcQc
May 29, 2007

gonadic io posted:

(++) is perhaps the best example for lazy evaluation making it hard to reason about code.
it's O(n) in its first argument and O(1) (amortised) in its second.

so if you have (xs ++ ys) ++ zs that's a fair bit slower than xs ++ (ys ++ zs) because in the former case xs will get traversed twice - once when evaluating ++ys and once when evaluating ++zs (assuming that the expresion as a whole gets evaluated).

this is basically the difference between left folds and right folds. foldl is tail recursive whereas foldr is body recursive. hence reverse gets defined using foldl and map using foldr.

in fact in GHC cabal-install there was a bug causing large compilation times that folded (++) over a list from the left (like (xs ++ ys) ++ zs) which has O(n^2) behaviour over the length of all the lists and the fix was to change it to a right-fold ( like xs ++ (ys ++ zs) which is O(n) which drastically reduced compilation times for the change of a single letter in the code.

e: i exaggerated a bit but the details are largely correct: https://github.com/nominolo/HTTP/commit/b9bd0a08fa09c6403f91422e3b23f08d339612eb

it's a reverse defined in terms of foldr (++), then it got changed to using the built-in foldl one.

The ++ behaviour in Erlang is also right-associative, so that A ++ B ++ C goes and appends B ++ C then A ++ B and reduces the rewriting needed, but this cannot be expanded in the case of strict evaluation -- if the two append calls are separated by a function call, they'll always get the unoptimal (A ++ B) ++ Z equivalent.

So if the Haskell version can't figure out a way to make this lazy (which somehow would be equivalent to body-recursion, I think), then their version is gonna be slowish like the Erlang one I guess.

MononcQc
May 29, 2007

HappyHippo posted:

im new at this so maybe im wrong but i would say the problem is using a linked list as a string type. in a strict language the situation isnt much better, they'll both be pretty slow (the second one will still be slower i believe). i guess if you're going to blame laziness, its that it makes this scheme workable at all so long as you're careful, but as soon as you arent it becomes as slow as doing it strictly.

Erlang has both the linked-list-as-a-string and binaries-as-a-string (closer to a byte array, but mostly immutable). The way to work around it is with iolists, which more or less just let you nest lists arbitrarily (as in a tree of lists) to do append and prepend operations. Breaking up a list is still expensive by comparison but you could decide to go:

code:
[["this", " ", "is", " ", "the", " ", "first", " ", "sentence."], " ",
  <<"This is the second sentence of the first paragraph">>, ".", "\r\n"],
 ["this is the third paragraph"]]
This lets you prepend or append in O(1), and lets you reduce the operating time on whatever structure you have. All IO drivers and most libraries know how to flatten or treat the structure as a flat one so it's really a thing you use to build chunks of output and amortize the cost once you get rid of it.


E: the cool thing about lists for text is really the ability to treat unicode grapheme clusters as single entities. So instead of [f, e, ^, t, e] to represent "fête", you could go [f, [e, ^], t, e] and handle everything as a unit again.

crazypenguin
Mar 9, 2005
nothing witty here, move along

MononcQc posted:

The ++ behaviour in Erlang is also right-associative, so that A ++ B ++ C goes and appends B ++ C then A ++ B and reduces the rewriting needed, but this cannot be expanded in the case of strict evaluation -- if the two append calls are separated by a function call, they'll always get the unoptimal (A ++ B) ++ Z equivalent.

So if the Haskell version can't figure out a way to make this lazy (which somehow would be equivalent to body-recursion, I think), then their version is gonna be slowish like the Erlang one I guess.

Nah, this isn't a case of lazy doing something amazing, the compiler can't do any magic here.

You're imagining lazy evaluation being able to come across a ((x ++ y) ++ z) mid-append and rewriting it to (x ++ (y ++ z)) I think? You need a special list type and append function to do that. And you can do that in a strict language, too, really. (Just saw your next post, that's basically this idea.)

All gonadicio was getting at with laziness being "faster" is that if you access just the 'x' portion of ((x ++ y) ++ z) then that's only a constant factor slower than having some so for (x ++ (y ++ z)), so you haven't yet been exposed to the quadratic blow-up. Or at least, that's what I'm pretty sure they were getting at.

leftist heap
Feb 28, 2013

Fun Shoe
kinda unrelated but is it just me or is the tooling around haskell pretty immature given how long the language has been around and how popular it is (relative to other small languages that is).

seems like emacs is the standard choice for editor/ide, which is fine. haskell-mode itself is pretty good, but once you start looking for more (autocompletion, import suggestions, type info etc.) it gets pretty janky. ghc-mod seems like the most mature and useful choice but it's pretty janky, doesn't currently work with GHC 7.10 and/or cabal 1.18+ (which is whatever, 7.10 just came out but cabal 1.20 has been out for a year now and it's pretty pushy about upgrading) and is maintained by like, one guy who is in school and has no time to devote to it. beyond that is poo poo that's even older, even less active, or more immature.

cabal itself also seems kinda janky. it has sandboxes which seem to work OK for the most part but the one time I tried to hack on a relatively non trivial it kinda blew up in ways that i'm too stupid and lazy to figure out.

so what gives? do srs haskellers just not give a poo poo about bells and whistles? welp, I've got my syntax highlighting and i'm good to go!

VikingofRock
Aug 24, 2008




gonadic io posted:

this isn't quite the case, have a read of https://wiki.haskell.org/Foldr_Foldl_Foldl%27 and if you still have questions i'd be happy to answer them

to directly answer your questions, foldl causes heap overflows and foldr causes stack overflows BUT foldr can produce its output incrementally whereas foldl has to produce it all in one go. for ints it's the same but for lists foldr can chug along bit-by-bit without necessarily consuming all the memory at once (it's very dependent on what you do with the result afterwards, and again, lazy evaluation means that maybe it'll be fast maybe it'll be slow who knows it depends on everything else)

That was a really good article, thanks. I think I understand it much better now.

I've been thinking about making a CoC Haskell thread for a while now, to help with little questions like this. Would other people here have an interest in that? I don't really have a ton of experience writing practical Haskell so it feels a little weird for me to make the thread, but I'd definitely be willing to put in the time to make/maintain the OP if no one else wants to.

Notorious b.s.d.
Jan 25, 2003

by Reene

rrrrrrrrrrrt posted:

kinda unrelated but is it just me or is the tooling around haskell pretty immature given how long the language has been around and how popular it is (relative to other small languages that is).

seems like emacs is the standard choice for editor/ide, which is fine. haskell-mode itself is pretty good, but once you start looking for more (autocompletion, import suggestions, type info etc.) it gets pretty janky. ghc-mod seems like the most mature and useful choice but it's pretty janky, doesn't currently work with GHC 7.10 and/or cabal 1.18+ (which is whatever, 7.10 just came out but cabal 1.20 has been out for a year now and it's pretty pushy about upgrading) and is maintained by like, one guy who is in school and has no time to devote to it. beyond that is poo poo that's even older, even less active, or more immature.

cabal itself also seems kinda janky. it has sandboxes which seem to work OK for the most part but the one time I tried to hack on a relatively non trivial it kinda blew up in ways that i'm too stupid and lazy to figure out.

so what gives? do srs haskellers just not give a poo poo about bells and whistles? welp, I've got my syntax highlighting and i'm good to go!

janky is the norm for small languages

i'm thinking of erlang here

Valeyard
Mar 30, 2012


Grimey Drawer

gonadic io posted:

It looks like there's some text missing in the definition of showParser, as there an infix operator (<|>) without anything to the right of it.

Apart from that, I actually like that question though since it isn't stupidly obfuscated (lack of linebreaks not withstanding), asks you about sensible code and makes sure that you know how to use parsec.

Which year undergrads is it for?

The reason that that's the answer to q1 is because It's trying to parse a haskell type which starts with an uppercase letter then can have and number of upper or lower case letters as in the example given in the question. It's not D because if it were, that would allow lists and tuples in the middle of a name

That makes sense about Q1, I just got confused about what it was asking me to parse vs understanding the parser wrongly

its a 4th year undergraduate class

also, do you think my reasoning for Q2 was right?

also anyone please feel free to call me out on being bad

leftist heap
Feb 28, 2013

Fun Shoe

Notorious b.s.d. posted:

janky is the norm for small languages

i'm thinking of erlang here

i dunno, clojure made a lot of strides in the past 2-3 years and it's probably smaller than haskell. i mean, it helps that it runs on java, but there just seems to be more consolidation and momentum behind poo poo like cider, nrepl, lein, etc. than similar tools in the haskell world. those things are pretty slick these days. the intellij plugin for clojure is really, really good now too.

Notorious b.s.d.
Jan 25, 2003

by Reene
you named the difference for yourself

clojure and scala and so on could lean on java packaging and build mechanisms as long as they needed. you can happily build clojure with maven, and i believe lein uses ivy2 from java-land for all its dependency-related activities

clojure also cheated on ide support. SLIME supported clojure basically from day one, because it was sufficiently lisp-like to support a port of swank, the SLIME server-side

haskell and erlang have to do all this stuff from scratch

gonadic io
Feb 16, 2011

>>=

VikingofRock posted:

That was a really good article, thanks. I think I understand it much better now.

I've been thinking about making a CoC Haskell thread for a while now, to help with little questions like this. Would other people here have an interest in that? I don't really have a ton of experience writing practical Haskell so it feels a little weird for me to make the thread, but I'd definitely be willing to put in the time to make/maintain the OP if no one else wants to.

there was a functional programming one before but it fell into archives as there just wasn't enough activity. i mean the only haskell that comes up in this thread is monthly valeyard's courseworks, weekly monad jokes and then the very occasional discussion like we had today, usually sparked by something that valeyard asks. feel free to make it i guess, i'd certainly be happy to answer questions in it.

rrrrrrrrrrrt posted:

kinda unrelated but is it just me or is the tooling around haskell pretty immature given how long the language has been around and how popular it is (relative to other small languages that is).

it's not just you. i think part of it is its academic background. there's quite a few IDEs like leksah, an eclipse plugin and FP complete's web based one but none have really caught on.

i myself just use sublime text, was reasonably happy using notepad++ and would use emacs if i could be bothered to learn it. honestly getting access to sublime's ctrl+b to build and run was an improvement over my previous workflow ("ghc Main.hs && Main.exe" in a command prompt) so perhaps i'm not the best person to ask about this!

e:

Valeyard posted:

also, do you think my reasoning for Q2 was right?

yep, as long as there's no missing part of the parser. basically if there were two parsers that started the same (for example records "Foo {fbar = bar, fbaz = baz}" vs non-record ADTs "Foo bar baz") then it's important to backtrack. luckily in the example given, non-record ADTs aren't represented and so there isn't an ambiguity between them and records, and you don't need "try".

i initially got this question wrong as i assumed that you'd just accidentally not included part of the parser and that there was supposed to be a non-record ADT parser as part of it (which is presumably why the "try" was originally put in there in the first place)

gonadic io fucked around with this message at 22:46 on Apr 28, 2015

leftist heap
Feb 28, 2013

Fun Shoe

Notorious b.s.d. posted:

you named the difference for yourself

clojure and scala and so on could lean on java packaging and build mechanisms as long as they needed. you can happily build clojure with maven, and i believe lein uses ivy2 from java-land for all its dependency-related activities

clojure also cheated on ide support. SLIME supported clojure basically from day one, because it was sufficiently lisp-like to support a port of swank, the SLIME server-side

haskell and erlang have to do all this stuff from scratch

clojure totally ditched SLIME long ago tho. cider and nrepl were built from scratch and matured really quickly.

i mean, immaturity of the tools is one thing, but there also seems to be no real momentum behind any one toolset or even a small subset of them or any desire to consolidate while the communities around other languages are very gung ho around tooling. i just get the impression that the community at large doesn't really give a gently caress so it makes me wonder what sort of workflow most people have.

Arcsech
Aug 5, 2008

rrrrrrrrrrrt posted:

kinda unrelated but is it just me or is the tooling around haskell pretty immature given how long the language has been around and how popular it is (relative to other small languages that is).

seems like emacs is the standard choice for editor/ide, which is fine. haskell-mode itself is pretty good, but once you start looking for more (autocompletion, import suggestions, type info etc.) it gets pretty janky. ghc-mod seems like the most mature and useful choice but it's pretty janky, doesn't currently work with GHC 7.10 and/or cabal 1.18+ (which is whatever, 7.10 just came out but cabal 1.20 has been out for a year now and it's pretty pushy about upgrading) and is maintained by like, one guy who is in school and has no time to devote to it. beyond that is poo poo that's even older, even less active, or more immature.

cabal itself also seems kinda janky. it has sandboxes which seem to work OK for the most part but the one time I tried to hack on a relatively non trivial it kinda blew up in ways that i'm too stupid and lazy to figure out.

so what gives? do srs haskellers just not give a poo poo about bells and whistles? welp, I've got my syntax highlighting and i'm good to go!

you are definitely right. honestly the one thing i really wanted when trying haskell was to be able to hover over something and have my editor tell me its type, but all the existing solutions for this are incredibly finnicky about ghc-mod/cabal/whatever versions and never have up-to-date instructions about how to get it all set up right

also cabal shits itself more often than it works ime, especially the dependency resolver. i dunno whether thats cabal's fault or package authors loving up their dependency specfications but its just another thing that ended up driving me away from haskell

gonadic io
Feb 16, 2011

>>=
p.s. speaking of terrible people who are programmers, a friend just reminded me that this exists:

Luigi Thirty
Apr 30, 2006

Emergency confection port.

it's linq

it's reflection

it's linq and reflection

missing fields from joins in select statements? cryptic exceptions that don't tell you anything? Microsoft has got it all

leftist heap
Feb 28, 2013

Fun Shoe

gonadic io posted:


it's not just you. i think part of it is its academic background. there's quite a few IDEs like leksah, an eclipse plugin and FP complete's web based one but none have really caught on.

i myself just use sublime text, was reasonably happy using notepad++ and would use emacs if i could be bothered to learn it. honestly getting access to sublime's ctrl+b to build and run was an improvement over my previous workflow ("ghc Main.hs && Main.exe" in a command prompt) so perhaps i'm not the best person to ask about this!

sick.

tbh emacs+haskell-mode+ghc-mod is a pretty good setup when it works. i'm mostly pissy because it's currently kind of fragile wrt ghc/cabal versioning and wasted a bunch of time loving around with it this weekend. when you dig into ghc-mod seems needlessly complex but i don't really know enough to know that for sure. i wanted to have a go at hacking the codebase a little but i kinda just spun around in circles and wrapping your head around a new, even mildly complex haskell codebase is a lot of work for someone as dumb and lazy as myself.

Bloody
Mar 3, 2013

someone rename this thread "haskell is terrible" please

kitten emergency
Jan 13, 2008

get meow this wack-ass crystal prison

Bloody posted:

someone rename this thread "haskell is terrible" please

Notorious b.s.d.
Jan 25, 2003

by Reene

gonadic io posted:

p.s. speaking of terrible people who are programmers, a friend just reminded me that this exists:


his website is pretty great

http://www.pjreddie.com/

see also, the original breathtaking resume

http://www.pjreddie.com/static/Redmon%20Resume.pdf

kitten emergency
Jan 13, 2008

get meow this wack-ass crystal prison
Haskell seems like a great way to feel smart when you take something easy and make it really hard and obtuse


... like my dick

Luigi Thirty
Apr 30, 2006

Emergency confection port.

i do things at work that involve long lists of numbers and occasionally records constructed from these lists of numbers should i learn a haskell

no

bobbilljim
May 29, 2013

this christmas feels like the very first christmas to me
:shittydog::shittydog::shittydog:

Luigi Thirty posted:

should i learn a haskell

no

ft, fy

unless you want to of course

Bloody
Mar 3, 2013

bobbilljim posted:


unless you want to of course

in which case your desires are incorrect

Adbot
ADBOT LOVES YOU

triple sulk
Sep 17, 2014



Bloody posted:

someone rename this thread "haskell is terrible" please

  • Locked thread