Programming General

Making something useful edition. Let's talk about our troubles and successes.

Attached: peppers.jpg (640x480, 638.76K)

Other urls found in this thread:

Wrote a fantasy name generator in Haskell, nothing special and more like babbys first program but Haskell is a very pretty language I just recently dug into. I always avoided it because it was so different but it's actually fun to write in and it's also very fast when compiled. I have the feeling I'll do a lot more in Haskell in the future.

I'm always shy about posting code in these types of threads because you could google search it and find my identity by my github repo.
Meh I want clients to see my hobby projects.
H = red; true ), ( H = red -> R = english; true ), % The jaguar is the pet of the Spanish family. ( R = spanish -> P = jaguar; true ), ( P = jaguar -> R = spanish; true ), % The Japanese lives to the right of the snail keeper % (for this predicate's purposes: the Japanese is *not* the snail keeper) ( R = japanese -> not P = snail; true ), ( P = snail -> not R = japanese; true ), % The snail keeper lives to the left of the blue house ( P = snail -> not H = blue; true ), ( H = blue -> not P = snail; true ).I finally sat down and thought through that manual page. result::- pred house(house::out) is, H, P)) :- race(R), color(H), pet(P), R = english H = red, R = spanish P = jaguar, not (R = japanese, P = snail), not (P = snail, H = blue).does exactly the same thing.

Post it and I'll critique it.

How many of you make programs with/for actual utility, instead of just pointless programming """challenges""" and fizzbuzz-tier scripts?

Attached: 516e318c6584b026e5cfbe70b9fb9ce9b03171a1d21a85813ebff8f83935be32.jpg (488x506, 33.18K)

I wrote a Rust macro that allows you to do cascading function calls:
macro_rules! cascade { ($e:expr) => { $e }; ($e:expr => $( ..$f:ident( $($arg:expr),* ) )*) => {{ #[allow(unused_mut)] let mut e = $e; $( e.$f( $($arg),* ) );*; e }};}fn main() { let mut a = cascade!(String::new() => ..push('a')..push('b') ..extend(std::iter::once('c')) ); println!("{}", a); println!("{}", cascade!(&mut a => ..clear()..insert(0, 'x') ..push_str(&format!("{}z", 'y')) ));}

Attached: steve klabnik smug.jpg (460x460, 28.24K)

reminds me of asking girls on IRC if they're fat and ugly.
cause, what attractive woman would waste time with geek stuff?
we don't need NEETs projecting their personal anxieties in every single programming thread.

so which is it?
1. a neat thing you'll never, ever use because I'd have to copy it into every project and readers have to know about it and in the end it's more work than gain
2. something you put into cargo and that people may actually use
3. something you'll actually use in real projects, despite the costs
You can recreate most of Clojure's features in Common Lisp, but #1 invariably applies. Likewise for a lot of Forth cuteness. An example of #2 in another language is

I'm just playing around with macros.
What costs?

Look at you. Pathetic. You are a full blown cuck. A little good goy afraid of doing anything that might upset his masters, and then coming on here looking for validation. No, little Jimmy, sorry for being the bearer of bad news, but you lost your manhood after being a corporate slave for so long. There's zero testosterone running through your veins now. They own you through and through.

Too bad.

Directed to


What am I larping as, genius?

Again, go back to whatever shithole you came from.
as a generic insult is retarded, no matter what r/4chan told you were the buzzwords you had to use to fit in here, you low IQ mongoloid.
I bet you're the same retard who replies to every post with a response consisting solely of
lines, just because you happen to miss upvotes so fucking much.

You are LARPing as a programmer. Prove me wrong by posting code.

no u
unbased btw. Post code or GTFO btw.

There are more posts about NEET anxiety than there are about programming, in this programming thread.
Why don't you go start a thread? "hey, p-p-people that say they program. aren't they all l-larpers? are they fa-faking it?"

Yeah, these threads reek of /g/ honestly.
Just look at this shit
It's almost like people get into these obscure languages to look like hipsters or something, and not because of any actual practical value.
I never bothered to look into Rust, but I can't fathom that blob of incomprehensible crap could ever be useful in the real world.
That shit doesn't look any different than early 2000s uncommented regex filled perl code. Weren't we supposed to go away from write-only languages? I just can't fathom that the programming revolution that's supposed to bring the next age of computing looks like that. I'll stick with C++ thank you.
Anyway, I wanted to write a program to efficiently sample bad blocks and mark the neighboring areas as bad too so I could get some use out of a couple used hard drives I bought with bad blocks, because badblocks was taking too much time and also it'd be wise to avoid the areas neighboring the bad blocks too.
Didn't get too far unfortunately.
Ddrescue includes some kinda sorta similar stuff in theory but in practice was buggy and didn't work (except in previous versions which lacked other functionality I needed, don't remember what exactly).

#include #include #include /* For O_RDWR */#include /* For open(), creat() */int main(){ const std::string device_path = "/dev/sda"; const unsigned int block_size = 5000000; //4096; const unsigned int initial_n_blocks_skips = 1000; //about 40 megabytes int device_fd = open(device_path.c_str(), O_RDONLY); char *buffer = new char [block_size]; //Get the file's length long int length_in_bytes = lseek(device_fd, 0, SEEK_END); lseek(device_fd, 0, SEEK_SET); //Now that we have a buffer and the device, we need to read a block every n uintmax_t current_byte_offset; for(current_byte_offset = 0; current_byte_offset < length_in_bytes; current_byte_offset += block_size * initial_n_blocks_skips) { std::cout

wew, lad.
why'd you stop working on it?



Yeah, well I wouldn't call it an accomplishment. It's just a small script I didn't even finish.
I'm no Chad but thanks for the compliment.
I like to keep it simple.
Didn't have the motivation I guess.

Nice, how many years did it take your speech therapist to teach you how to repeat other people's words?
Anybody can make claims on here. Can you prove it though?

woah, the #1 most shameful reason.
mom: did you make anything?
you: oh yes. Here it is, a blank piece of paper.
mom: ... it's blank.
you: I was going to draw "I love you mom!" with the whole family and hearts and stuff, but I got bored.
mom: ...
you: keep the paper!
mom: ...
you: I love you, mom!

It's just some lines of code bro. If you want to project your daddy issues onto it then that's on you, but don't pretend that has anything to do with me.

do you have anything to do with this massive faggot that complained about "these threads" and hipsters who don't create "any practical value"?

I like how the OP asks something innocent, the first two replies are equally innocent and then it just turns into tech and everyone flies into an autistic rage and calls each other faggot, lmao shit board, as always

Yes. The practical value created by these lines is getting me 20 minutes closer to my goal of mapping those bad blocks.
What practical value does your incomprehensible cascading function bullshit create? Masturbating your oversized clitoris? Well, it works from that point of view I guess.

I like how you're complaining about a pile of shit as you squat over it and contribute to the pile, yourself.
c'mon, programming general.
if a mod makes this circular so it doesn't hit the bump limit like the last one, we can pretend these posts never happened anyway.
dear NEET anxiety posters: is what it looks like. Even a trivial program takes non-trivial time to do well. It certainly takes much longer to program than it takes to dream about stuff you could program, even stuff you're entirely capable of doing, or have even done (very similar to) before. So if you're a programmer who doesn't just do it for a paycheck and never elsewise, you'll grow a todo list that you can never complete. That's why you suffer from NEET anxiety. Just accept it, and occasionally write something to completion and publish it.

you open /dev/sda and seek twice.
Jesus dude, don't brag about how hard it was for you to find section 2 of the manpages.

I'm not bragging. Again, you're projecting. Just because you do everything to call attention to yourself and feed your fragile ego doesn't mean everybody else does.

Just because you have massive self esteem issues and feel like a failure if you aren't constantly attention whoring with faggotry doesn't mean everybody else does.

I don't really care what language you use. But if you can fit your entire "program" into an Zig Forums post then you're not doing meaningful programming.

It often seems that /v/ has more in-depth programmers than Zig Forums has and it makes me sad. They're experimenting with developing all kinds of game engines features and shit from scratch, meanwhile most of Zig Forums projects are not much more complex than "imported a library and made some calls to it".

Attached: 5nie6vn0.png (529x350, 87.31K)

well you're definitely autistic, user.

and you're just a drooling moron. back to
this should only take you about 60 more minutes:
1. instead of opening /dev/sda, open an argument to the program.
2. instead of doing nothing with the opened file, repeatedly read the file into your buffer and print output (and skip ahead) whenever read returns an error. 'man 2 read'.
3. if you find no errors, print something to that effect to standard error. Put any other output like a complaint about arguments in standard error. your program should print either nothing or else some formatted about your blocks.
congratulations. You now have a functional piece of some gerry-riggable "use this disk except for these bad blocks" program.

reminder to favor composition over inheritance

while y'all niggaz is defending your (anonymous) reputations instead of talking about programming, Xah just admits he doesn't know how strictly typed languages work.
Zig Forums, it is time to
meditate on

Autism doesn't exist. It's just a made up syndrome invented by the jews to lump high IQ white men with literal brain damaged retards (most of which are probably getting it from vaccines anyway).
I might do that after I get the program working. Before, why bother? I'll be re-compiling often anyways.
If I didn't know I had to read from the disk, why would I bother to calculate current_byte_offset in the first place? How could I possibly know I could somehow find bad blocks by opening a block device if I didn't know I had to read from it?
Well, no, if you read my post again, the reason I began that program was to get something that works better than either badblocks or dd_rescue, both of which are very slow and offer no safety margin.
The way I planned to do it was to test every block every X range of blocks. Then make blacklist of Y blocks over and under these confirmed faulty blocks.
Then make a second pass where I wouldn't have to read those likely faulty blocks, which would be much faster than just testing everything (because trying to read bad blocks takes seconds, unlike normal blocks which can be read in miliseconds). Then a third pass, and so on. And I was thinking of representing the map in memory using a bitset, which would simplify the logic, and allow me flexibility to reload an old list for a certain block size and convert it to a new block size, as long as both are integer multiples of each other. I realize I could implement it so it only loaded part of the list and then as it scanned the surface it saved to a new file and loaded parts of the input file separately, or even use an sqlite db or something, but as I said, I like to keep it simple and a bit vector would take only like a meg of memory for each tb of hard drive. I published that thing mainly to get some suggestions on ways to implement that kind of stuff, not to brag about anything.

Well I don't know man you do you. To me a program is anything that makes up an executable file.
The only meaningful thing about that snippet of code -at least for me- is whether I get it to work or not and whether I had a bit of fun writing it
Maybe they enjoy programming videogames more than Zig Forums enjoys programming Zig Forums things. What sounds more fun, programming a flight simulator or fixing glibc so the DNS solver will still work with static linking? Besides, there are all kinds of games, on the other hand, what Zig Forums stuff has came in the last 10 years? Maybe the suckless stuff, other than that, not much. Maybe Zig Forums stuff is just harder or doesn't motivate people as much as vidya does. Even if you hate Unix and C, you gotta admit not much has changed in your favor either.
For example?

so i += x instead of ++ in your loop, and some math in your output. Otherwise the loop is the same.
you can keep it simple by producing readable block information and punting on what you're going to do with that information. You could use a separate program for your other passes.

There isn't any ++ in my loop.
All the passes would share the same underlying logic, so I could probably use only one loop for every one of them by adding a condition to check if the block was already blacklisted. Except with a halved initial_n_blocks_skips.

yes, I'm still talking about the loop you should write, that reads blocks and reports on failures.

I'm hammering away but so far the compiler hasn't yelled hard enough against me.

Well, like I said, that's kind of sad.

Why do you have to work on someone else's autistic library? There's all kinds of interesting non-videogame software you could work on. Like your own video/music player, or an image viewer, or a web server, or a painting program, experiment with a new internet data concept to replace http/html/CSS/JS, make your own language, make a new linux distribution, some kind of realtime collaboration tool for something, train your own neural network to do something, a tool for manipulating metadata from image files, a desktop client for browsing Zig Forums...

Just because something is already possible in some form doesn't mean you can't do it better, in fact almost all things have the potential to be done better, or in an alternate way that makes it more powerful in another context. Whenever I use any piece of software there's almost guaranteed something that I don't like about it, whether it's design or clumsiness or lack of features or lagginess or whatever, the idea of making my own version of that software becomes interesting. And there's some things that just do not even exist in the form that I want them. Maybe it's a side effect of me being kind of interested in everything and thus running into more things I want, but I still can't imagine that most people don't care about making things like that.

A bunch of garbage that makes everything more awkward and ugly and slow than it was before. It's getting EASIER to make something good because the competition is getting worse.

You should study up on propositional logic. You'll learn what that stuff means

Retard detected. You should NOT be using lseek to find the size. Not only are you messing around with the file offset pointlessly in doing so, you are also locking the inode during ech of the calls to lseek. It also means that you need to context switch into the kernel twice, one for each lseek. The correct way to find the size of a block device is using ioctl with the BLKGETSIZE64 request.

it's user
time to point and laugh at Go

Attached: generics.jpeg (1072x1529, 158.05K)

I like php

Fuck your neurotic faggotry. If a macro reduces the amount of code one has to type it's good.

every point and laugh at the nomaintainer

I extended it: macro_rules! cascade { (@0($e:ident)) => { $e }; (@0($e:ident) |$i:pat| $ex:block $($tail:tt)*) => { cascade!(@3($e ({ let $i = $e; $ex })) $($tail)*) }; (@0($e:ident) &|$i:pat| $ex:block $($tail:tt)*) => { cascade!(@3($e ({ let $i = &$e; $ex })) $($tail)*) }; (@0($e:ident) &mut |$i:pat| $ex:block $($tail:tt)*) => { cascade!(@3($e ({ let $i = &mut $e; $ex })) $($tail)*) }; (@0($e:ident) .. $($tail:tt)*) => { cascade!(@1($e ($e.)) $($tail)*) }; (@1($e:ident ($($stmt:tt)*)) $f:tt $($tail:tt)*) => { cascade!(@2($e ($($stmt)*$f)) $($tail)*) }; (@2($e:ident ($($stmt:tt)*)) => $($tail:tt)*) => { cascade!(@3(e ($($stmt)*)) => $($tail)*) }; (@2($e:ident ($($stmt:tt)*)) = $b:block $($tail:tt)*) => { cascade!(@3($e ($($stmt)* = $b)) $($tail)*) }; (@2($e:ident ($($stmt:tt)*)) :: $($tail:tt)*) => { cascade!(@2($e ($($stmt)*::)) $($tail)*) }; (@2($e:ident ($($stmt:tt)*)) ($($arg:expr),*) $($tail:tt)*) => { cascade!(@3($e ($($stmt)*($($arg),*))) $($tail)*) }; (@3($e:ident ($($stmt:tt)*)) ? $($tail:tt)*) => {{ cascade!(@3($e ($($stmt)*?)) $($tail)*) }}; (@3($e:ident ($($stmt:tt)*)) .$f:ident $($tail:tt)*) => {{ cascade!(@2($e ($($stmt)*.$f)) $($tail)*) }}; (@3($e:ident ($($stmt:tt)*)) => $($tail:tt)*) => {{ #[allow(unused_mut)] let mut e = $($stmt)*; cascade!(@0(e) $($tail)*) }}; (@3($e:ident ($($stmt:tt)*)) $($tail:tt)*) => {{ $($stmt)*; cascade!(@0($e) $($tail)*) }}; ($e:expr) => { $e }; ($e:expr => $($tail:tt)*) => {{ #[allow(unused_mut)] let mut e = $e; cascade!(@0(e) $($tail)*) }};}fn main() -> Result { use std::ops::Mul; let e = cascade!((Vec::new(), 0) => ..0 = { vec!(b'1') } &mut |(v, _)| { v.insert(0, b'0'); } &|v| { println!("{:?}", v); } ..0 => ..push(b'2')..push(b'3') |v| { String::from_utf8(v)? } => ..parse::()?.mul(2) => ); println!("{}", e); Ok(())}

Attached: steve klabnik smug 2.png (554x786, 137.04K)

This is his wife, you caused a seizure. I have your information and have called the police to report the assault.

Attached: cnile.jpg (400x400, 29.1K)

quoting some guy from 2002:
I used to hack a lot of Lisp; I don't miss the macro facility.

The Lisp macro facility was generally used for two purposes:
(1) as a kind of programmer-driven inlining tool; and
(2) to extend the "syntax" of the language to support things like Lisp's loop syntax.

(1) is something you can take or leave - I'm personally quite happy with just writing ordinary funtions etc. and adding pragmas if I feel the compiler isn't quite up to the task (Haskell, in the GHC flavour, now has programmable rewrite-rules as an experimental feature - it's not at all clear yet whether this is a good idea or not).

(2) is a problem, because you can no longer look at code and assume you know what is function application and what isn't - I found myself constantly referring to the CLtL bible... This sort of thing put me right off the whole macro idea.

It's not a big problem in practice. You can make a similar argument that you don't know what a function will do until you look at it's documentation / implementation.
Also don't be so quick to dismiss the power of overloading lambda. Functions aren't the only thing that can take input and give output.

This is true, but languages tend to have a lot of subtle guarantees that you might not feel the lack of until you write in something like Forth, where any single word could take over interpretation and radically change the meaning of the entire rest of the program.
There's always a burden of "you have to know what a program's words mean to know what it's saying" but language manage that burden very differently. A function in most languages won't affect control flow, you'll know at what times it runs, it can't introduce new variables or reference (non-global) variables that aren't referenced by its parameters, its parameters are evaluated before they are passed to the function. Macros can violate all of that. There is also programmer custom. Programmers know that global state is bad and use it sparingly, so you have even more information in practice on what a function is probably doing. When programmers are using macros though, they're more willing to go hog-wild with it.
Here's a complete Forth program: : rotchar ( c -- c' ) dup [char] a [ char m 1+ ] literal within 13 and over [char] A [ char M 1+ ] literal within 13 and + over [char] n [ char z 1+ ] literal within -13 and + over [char] N [ char Z 1+ ] literal within -13 and + + ; : rot13 ( c-addr u -- ) bounds do i c@ rotchar i c! loop ; source 2dup rot13 glcr pe olrIt has this output:fbhepr 2qhc ebg13 type cr bye

It probably would make it easier to port the program to Windows.
Locking it from what exactly? Other threads? Other processes?
Not a big deal. I can take an extra milisecond or two. The program is going to run for like an hour anyway.

You look jewish. Considering that, it doesn't surprise me the main way you promote your language is by implying people aren't qualified to criticize it ("LARPing", "NEET anxiety", emphasizing how well paid you are, what kind of university you went to, etc.) rather than addressing the criticisms themselves. You seem to be one of the few jews who figured out how to effectively use imageboards for marketing purposes too, learning how to use the buzzwords to your advantage without it sounding too forced ("LARPing", "NEET", "Cniles", "guise").
So, for instance, posting in a thread about politics means I'm LARPing as a politician? Or even playing a soccer match means I'm LARPing as a soccer player? How about cooking, do you do cooking? Do it mean you are LARPing as a cook? The way the word was originally used (besides the playing with medieval swords stuff) was to ridicule people who were claiming to be somebody who they weren't. For example, claiming to be a policeman, or in the army, or a physicist, or yes, even a programmer. But doing something that one of these people do does not mean claiming to be somebody who does it professionally. Just like because somebody posts on Zig Forums doesn't mean they are LARPing as military, or because somebody posts on Zig Forums doesn't mean they are LARPing as politicians.

But of course you already know that, just as you are probably very well aware of how jews like to always twist the meaning of words to their advantage, given that you are one yourself.

pick one, LARPer


Bullshit. Rust macros are basically pure functions that take an AST and produce an AST at compile time.

Nice try twisting my words again, Moshe. I didn't call you out for using the word LARP. I called you out for twisting its meaning. I'm wise to your tricks, your shitty shilling tactics won't work on me anymore. Time to go back to kike subversion academy.

Where is your code, LARPer?

What code?

Snakes and Ladders game. CLI only, I haven't worked out how to do a GUI in Haskell yet.
import Data.Arrayimport qualified Data.Map as Mimport System.Randomimport Text.Read (readMaybe)import Control.Monad.Writerimport Control.Monad.Statetype BoardEntry = (Position, SquareData)type SquareData = (SquareType, Destination, Description)type Position = Intdata SquareType = Snake | Ladder deriving (Show, Read)type Destination = Inttype Description = String-- monad type for managing game statetype StateWriter a = StateT Game (Writer [String]) a-- make sure a position is validisValidPos :: Position -> BoolisValidPos n = n >= 1 && n BoolisValidEntry (pos, (t, dest, _)) = isValidPos pos && isValidPos dest && case t of Snake -> dest < pos Ladder -> dest > pos-- list of snakes and ladders (todo: read from file)boardList :: [BoardEntry]boardList = [( 1, (Ladder, 38, "Bravery")) ,( 4, (Ladder, 14, "Strength")) ,( 9, (Ladder, 31, "Discipline")) ,(16, (Snake, 6, "Dishonesty")) ,(21, (Ladder, 42, "Determination")) ,(28, (Ladder, 84, "Faith")) ,(36, (Ladder, 44, "Courage")) ,(47, (Snake, 26, "Greed")) ,(49, (Snake, 11, "Lust")) ,(51, (Ladder, 67, "Perseverance")) ,(56, (Snake, 53, "Envy")) ,(62, (Snake, 19, "Gluttony")) ,(64, (Snake, 60, "Sloth")) ,(71, (Ladder, 91, "Patience")) ,(88, (Ladder, 100, "Dedication")) ,(87, (Snake, 24, "Faggotry")) ,(93, (Snake, 73, "Cruelty")) ,(95, (Snake, 75, "Wrath")) ,(98, (Snake, 78, "Impatience")) ]-- game boardboard = M.fromList $ filter isValidEntry boardListtype PlayerID = Inttype PlayerArray = Array Int Position-- game statedata Game = Game { generator :: StdGen, -- random number generator state nPlayers :: Int, -- number of players players :: PlayerArray, -- player positions on the board turn :: PlayerID -- whose turn it is } deriving (Read, Show)-- roll diceroll :: StateWriter Introll = do g (d, g{generator=gen})-- calculate new positionnewPos :: Position -> Int -> Maybe PositionnewPos pos n = let pos' = pos + n in if pos' StringcurrentName g = "Player " ++ show ((turn g) + 1)-- calculate next player IDnextPlayer :: Game -> IntnextPlayer g = ((turn g) + 1) `rem` nPlayers g-- determine whether the current player has won the gamewon :: Game -> Boolwon g = if (getPosition g == 100) then True else False-- roll event using State monadrollEvent :: StateWriter ()rollEvent = do d

---- impure UI code---- main programmain :: IO ()main = do putStrLn "Welcome to Snakes and Ladders!" gen do q do let (g', log) = runWriter (execStateT rollEvent g) mapM_ putStrLn log if won g' then putStrLn $ name ++ " won the game!" else do putStr "\n" mainloop $ g'{turn=nextPlayer g'} _ -> do mainloop g

what are good books or tutorials for haskell?

learn you a haskell

are you dumb?
Who cares what the macro does? The point is what the code does. If the AST you produce can do all kinds of shit that a normal function call can't, then you have to keep that in mind.
Rust is already better than Lisp though by requiring macros to wear a scarlet letter M.

no u?
So how do you know what a function does?


oh great that'll really help me when I'm reading normal code that doesn't do this.

If a function invokes UB anything could happen.
What is even your point anymore? You've clearly been BTFO multiple times already. It's time to stop.

oh yeah am deebly goncerned all the time
code hard to read because it might invoke UB and the compiler might be written by aliens who woudl take "anything could happen" seriously and try to do something in sudo instead of let the machine do what it will, which is much less "anything" in practice
this is a very serious readability problem.
actually when you think about it there are no readability differences at all between anyone's code, because of UB!
thank you user. you've BTFO'd me so hard, I am now retarded.


i made a text adventure builder

Attached: text gaem.png (677x618, 64.89K)

fun game, but getting all your IO in your game logic? Even if you do that with level 99 type bullshit, what's the point? It's just stylized imperative code. Contrast:- module snakes.:- interface.:- import_module array.:- type square ---> ladder(int, string) ; snake(int, string).:- type game == array(int).:- type roll_result ---> victory ; overshot(int) % gotta roll int to win ; moved_to(int) ; trap(int, square). % int: square you hit % init(PlayerCount) = Game:- func init(int::in) = (game::array_uo) is det. % play(Who, NextPlayer, Roll, Result, !G):- pred play(int, int, int, roll_result, game, game).:- mode play(in, out, in, out, array_di, array_uo) is det.:- implementation.:- import_module int.:- func board_size = int.board_size = 100.init(Players) = array.init(Players, 0).play(Who, Next, Roll, Result, !P) :- Next = (Who + 1) rem size(!.P), lookup(!.P, Who, Position), ( Roll + Position = board_size -> Result = victory ; Roll + Position >= board_size -> Result = overshot(Roll + Position - board_size) ; board(Roll + Position, Square) -> Result = trap(Roll + Position, Square), (Square = ladder(To, _); Square = snake(To, _)), set(Who, To, !P) ; Result = moved_to(Roll + Position), set(Who, Roll + Position, !P) ).:- pred board(int::in, square::out) is semidet.board(1, ladder(38, "Bravery")).board(4, ladder(14, "Strength")).board(9, ladder(31, "Discipline")).board(16, snake(6, "Dishonesty")).board(21, ladder(42, "Determination")).board(28, ladder(84, "Faith")).board(36, ladder(44, "Courage")).board(47, snake(26, "Greed")).board(49, snake(11, "Lust")).board(51, ladder(67, "Perseverance")).board(56, snake(53, "Envy")).board(62, snake(19, "Gluttony")).board(64, snake(60, "Sloth")).board(71, ladder(91, "Patience")).board(88, ladder(100, "Dedication")).board(87, snake(24, "Faggotry")).board(93, snake(73, "Cruelty")).board(95, snake(75, "Wrath")).board(98, snake(78, "Impatience")).

and the interactive game::- module playsnakes.:- interface.:- import_module io.:- pred main(io::di, io::uo) is det.:- implementation.:- import_module list, string, exception, int, array.:- use_module snakes.main(!IO) :- io.command_line_arguments(Args, !IO), ( Args = [NStr], to_int(NStr, N), N > 0 -> io.format("Welcome to Snakes and Ladders, with %d players.\n", [i(N)], !IO), game(0, snakes.init(N), !IO) ; io.progname_base("playsnakes", Program, !IO), io.format(io.stderr_stream, "usage: %s \n", [s(Program)], !IO), io.set_exit_status(1, !IO) ).:- pred game(int::in,, io::di, io::uo) is, !.G, !IO) :- Prompt = format("\nPlayer %d's turn. What is the roll? ", [i(Player)]), prompt(Prompt, Roll, !IO),, Next, Roll, Result, !G), ( Result = snakes.victory, io.format("Player %d has won!\n", [i(Player)], !IO) ; Result = snakes.overshot(N), io.format("ouch. That's too high. You'll win on a %d roll.\n", [i(N)], !IO), game(Next, !.G, !IO) ; Result = snakes.moved_to(N), io.format("Player %d moves to square %d\n", [i(Player), i(N)], !IO), game(Next, !.G, !IO) ; Result = snakes.trap(N1, snakes.snake(N2, Name)), io.format("Player %d moves to %d--and then is swallowed by the snake of ""%s""!\n", [i(Player), i(N1), s(Name)], !IO), io.format("The snake shits Player %d out onto square %d\n", [i(Player), i(N2)], !IO), game(Next, !.G, !IO) ; Result = snakes.trap(N1, snakes.ladder(N2, Name)), io.format("Player %d moves to square %d, and climbs the ladder of ""%s"" to square %d.\n", [i(Player), i(N1), s(Name), i(N2)], !IO), game(Next, !.G, !IO) ).:- pred prompt(string::in, int::out, io::di, io::uo) is det.prompt(Prompt, N, !IO) :- io.write_string(Prompt, !IO), io.read_line_as_string(Result, !IO), ( Result = ok(Line), Chomped = chomp(Line), ( to_int(Chomped, N0) -> N = N0 ; io.format("%s is not a number.\n", [s(Chomped)], !IO), prompt(Prompt, N, !IO) ) ; (Result = eof; Result = error(_)), throw(software_error("read error")) ).

minor bug:$ ./playsnakes 2Welcome to Snakes and Ladders, with 2 players.Player 0's turn. What is the roll? 88Player 0 moves to square 88, and climbs the ladder of "Dedication" to square 100.Player 1's turn. What is the roll? 1Player 1 moves to square 1, and climbs the ladder of "Bravery" to square 38.Player 0's turn. What is the roll? 1ouch. That's too high. You'll win on a 1 roll.

There is no IO occurring in the game logic, but I see your point. The game was written primarily as an exercise to combine the State and Writer monads. There are better ways to structure the program, I agree.

{-# LANGUAGE LambdaCase #-}{-# LANGUAGE FlexibleContexts #-}{-# LANGUAGE GADTs #-}{-# LANGUAGE TemplateHaskell #-}import Control.Monad.Freerimport Control.Monad.Freer.THimport Data.Map ((!?), fromList)import Safeimport System.Randomdata Transport = Snake | Ladderdata Game r where End :: Int -> Game () Move :: Int -> Int -> Game Int Roll :: Game IntmakeEffect ''Gameturn old = roll >>= move oldboard = fromList [ ( 1 :: Int, (Ladder, 38 :: Int, "Bravery")) , ( 4, (Ladder, 14, "Strength")) , ( 9, (Ladder, 31, "Discipline")) , (16, (Snake, 6, "Dishonesty")) , (21, (Ladder, 42, "Determination")) , (28, (Ladder, 84, "Faith")) , (36, (Ladder, 44, "Courage")) , (47, (Snake, 26, "Greed")) , (49, (Snake, 11, "Lust")) , (51, (Ladder, 67, "Perseverance")) , (56, (Snake, 53, "Envy")) , (62, (Snake, 19, "Gluttony")) , (64, (Snake, 60, "Sloth")) , (71, (Ladder, 91, "Patience")) , (88, (Ladder, 100, "Dedication")) , (87, (Snake, 24, "Faggotry")) , (93, (Snake, 73, "Cruelty")) , (95, (Snake, 75, "Wrath")) , (98, (Snake, 78, "Impatience")) ]runSnakesAndLadders = runM . interpretM (\case End n -> putStrLn $ "Player " show n " won the game!" Move old n -> let pos = old + n in case board !? pos of Just (Ladder, to, name) -> do putStrLn $ "You climbed the " name " ladder to " show to pure to Just (Snake, to, name) -> do putStrLn $ "You slid down the " name " snake to " show to pure to Nothing -> if pos do n >= \case Just x | 1 readPlayersmain = do putStrLn "Welcome to Snakes and Ladders!" putStrLn "How many players? [1-6]" players turn x >>= \z -> if z == 100 then end n else acc $ z : y) go (zip [1..] ps) []Here's a version that uses freer monads. Took me a while to figure out how to get multiple players working and ending the game as soon as one person wins. I end up using foldr to build up another list of position which gets passed into the actual acc. The benefit to my approach is that you could create a similar game by making an interpreter to use instead of runSnakesAndLadders.

The best book for Haskell is
The worst book is the one mentioned. That one teaches so many bad practices and spends so much time on features that are discouraged in the Haskell community. Ironically we used that book in my PL class I had last semester. It was annoying spending so much time on pointless parts of the language and not getting to anything interesting.


runSnakesAndLadders has all your actual game logic, and it's interwoven with I/O exactly like the other Haskell solution. What's the point of being able to use something else instead of that? What would anyone even be benefitting from anymore? "oh goody, I can design my own completely incompatible game but I can reuse this table of snakes and ladders"?
The flexibility that you actually want is
1. the interface. After we get a working game on the terminal, let's write a graphical frontend without reimplementing the entire fucking game
2. the players. After we get interactive input from a human, let's make some AI players and add them to games without reimplementing all the fucking game logic. Hey, wouldn't it be nice if the AI players could run their own simulations of the game in their heads, using the exact same code that the game is using?

I swear, Haskell's such a shit language that it impairs its adherents' ability to think. It's like alcohol. You don't have any spare braincells after you write something like this:{-# LANGUAGE LambdaCase #-}{-# LANGUAGE FlexibleContexts #-}{-# LANGUAGE GADTs #-}{-# LANGUAGE TemplateHaskell #-}import Control.Monad.Freerimport Control.Monad.Freer.THimport Data.Map ((!?), fromList)import Safeimport Game r where End :: Int -> Game () Move :: Int -> Int -> Game Int Roll :: Game IntmakeEffect ''Game

>the other one's not really interleaving I/O
it retains all the practical disadvantages of interleaved I/O. it is a chimera: making decisions about game logic and about game presentation at the same time, instead of separately. Just imagine you have two devs on this project, and one wants to experiment on more entertaining game logic, and the other one wants to experiment with a graphical UI and internationalization. Have fun with all the unnecessary merge conflicts after you both get done with that!
add a single rule to the game:
- players roll twice and pick the result they want to use.
now you've got room for
1. greedy AI: always picks the higher roll
2. random AI
3. opportunistic AI: picks higher roll unless the lower roll lands it on an immediately beneficial snake/ladder
4. statistician AI: is willing to pick a lower roll if that'll give it another *chance* at rolling onto a beneficial snake/ladder
5. 14-dimensional chess AI: will deliberately land on *bad* squares if it reckons this is the shorter path to victory.
wow. one rule. such AI. this is the power of not blowing my brains out with Haskell.

You're really overthinking this. The point of the program was never to build a 4D extensible snakes and ladders game engine, with plugins for AI and blackjack and hookers. The point of the program was a vehicle for teaching myself the monad transformer library - how to compose monads. The game itself was secondary.

Pretty much Haskell in a nutshell.


If you can't afford it, then just pirate it.

Yes, that was the point. I can define how rolling, moving, and ending the game should work. I'm not saying it
s the best way to implement this program, but was just a way I wanted to try.
Yes, this is due to the nature of the problem.
You can do this by writing a different interpreter.d
My game is only AI players. If you mean you want the ability to have print messages to be disabled, then we could add another freer monad for how printing to the terminal should work. To keep it simple I didn't do this.
What's your problem with GADTs?

How about you implement this program and show how its done if you think you can elegantly separate the IO from the game logic?

Haskell is no where close to your gay fantasies.

I'm going to assume you are being sarcastic.

learn to read. "rewrite the entire program" is not how code reuse works.
Great. Then add a human player. Do something you didn't specifically anticipate wanting to do.
Also your game has no AI players.
If someone makes a fork out of thin, easily-shattered glass, my problem with the result isn't "a problem with glass". Haskell could be used to write reasonable code. It has all of ML hidden in it, like a beautiful skeleton trapped within a 600lb woman, but Haskellers find it more satisfying to produce bad code.
already did. The game logic and the I/O are in separate modules, and separate files.
not in the slightest.

{-# LANGUAGE LambdaCase #-}{-# LANGUAGE FlexibleContexts #-}{-# LANGUAGE GADTs #-}{-# LANGUAGE TemplateHaskell #-}import Control.Monad.Freerimport Control.Monad.Freer.THimport Data.Functorimport Data.Map ((!?), fromList)import Safeimport System.Randomdata Transport = SnakeT | LadderTdata Game r where End :: Int -> Game () Ladder :: Int -> String -> Game () Move :: Int -> Game () Overshoot :: Int -> Int -> Game () Roll :: Game Int Snake :: Int -> String -> Game ()makeEffect ''Gamedata Printer r where Output :: String -> Printer ()makeEffect ''Printerboard = fromList [ ( 1, (LadderT, 38, "Bravery")) , ( 4, (LadderT, 14, "Strength")) , ( 9, (LadderT, 31, "Discipline")) , (16, (SnakeT, 6, "Dishonesty")) , (21, (LadderT, 42, "Determination")) , (28, (LadderT, 84, "Faith")) , (36, (LadderT, 44, "Courage")) , (47, (SnakeT, 26, "Greed")) , (49, (SnakeT, 11, "Lust")) , (51, (LadderT, 67, "Perseverance")) , (56, (SnakeT, 53, "Envy")) , (62, (SnakeT, 19, "Gluttony")) , (64, (SnakeT, 60, "Sloth")) , (71, (LadderT, 91, "Patience")) , (88, (LadderT, 100, "Dedication")) , (87, (SnakeT, 24, "Faggotry")) , (93, (SnakeT, 73, "Cruelty")) , (95, (SnakeT, 75, "Wrath")) , (98, (SnakeT, 78, "Impatience")) ]runGame = runM . interpretM (\case End n -> putStrLn $ "Player " show n " won the game!" Ladder to name -> putStrLn $ "You climbed the " name " ladder to " show to Move to -> putStrLn $ "You moved to position " show to Overshoot from to -> do putStrLn $ "You must roll " show (100 - to) " to win the game" putStrLn $ "You stayed in position " show from Roll -> do n putStrLn $ "You slid down the " name " snake to " show to)readPlayers = readMay getLine >>= \case Just x | 1 readPlayersturn from = do pos ladder to name $> to Just (SnakeT, to, name) -> snake to name $> to Nothing -> if pos pos else overshoot from pos $> frommain = do putStrLn "Welcome to Snakes and Ladders!" putStrLn "How many players? [1-6]" players turn x >>= \z -> if z == 100 then end n else acc $ z : y) go (zip [1..] ps) []Okay, based off your feedback I've factored out the game logic from my interpreter into how a turn is played. Thanks for the pointers.
Well your survey of laziness' usage in Haskell is incomplete and misguided. Saying you understand it in the end is not accurate.

gross, dude.
suppose you want to log all game events. If you'd used normal type constructors like LadderT for this, just with parameters, then all you'd have to do is derive Show and then dump the events to a file. This is the sort of accidental benefit that I'd expect from a program in an FP lang that of course is focused on data rather than procedural steps. Of course the game engine runs on data. What do you think this is, Python? You think someone writing a program in an FP lang would have to add logging by mocking an existing OOP object, having it do the logging, and then having it reinvoke methods on the existing object? That would be absurd.
autism confirmed. You can't detect mockery.

haskell is a (bad) meme
it's only use is writing dense, cryptic code to farm upboats from reddit

There are 88 replies and literally 10 of them contain code.
I love browsing Zig Forums

a lot of the more recent posts are at least about code.
no thanks to you
fug, or me
wait, OK, here:main(!IO) :- ( if all [N] (numbers(N) => N < 10) then io.write_string("all numbers are < 10\n", !IO) else io.write_string("there's a number >= 10!\n", !IO) ).

Attached: 664.jpg (558x614, 17.67K)

real-world instances where an X with this kind of defense was any good:

Pastebin downloader script given a username. r8
#!/bin/bash[ -z "$1" ] && echo "Usage: pastedl username" && exitIFS=$'\n'# Find authorauthor="$1"string="$(curl -s"$author" | sed s/""/"\n,,,"/g | sed s/"'\| "/"\n"/g | grep -i ",,,$author")"AUTHOR="${string:3}"# Find max page numberstring="$(curl -s"$author" | sed s/"


Attached: rio.PNG (1405x864, 808.65K)

Not technology or programming related

What language/library has the best GUI/window abilities?
I'm talking it's as easy as printf to get something display in a window.

Rebol, RED:
probably Tcl.

I mean, the previous thread had an anime girl reading from a programming book, which is more interesting than a picture of green, or whatever that is.

What's the point in programming? All I've achieved is having some chink fork my projects on github. That's literally it.
Seems like a much bigger waste of time than even shitposting.