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

>>=
Is this thread a monad?

Adbot
ADBOT LOVES YOU

gonadic io
Feb 16, 2011

>>=

rrrrrrrrrrrt posted:

Does someone want to take a stab at explaining the ((->) a) instances for type classes like Functor and Monad 'cause I don't really get them still.

Short answer: Don't use them.

Long answer:

For functor, fmap is (.). I've not yet found a case where this is useful per say, but it's a thing.

Due to (subject to a slight renaming of the variables)
code:
fmap :: (b -> c) -> f b -> f c
-- replace f with ((->) a)
fmap :: (b -> c) -> ((->) a b) -> ((->) a c)
-- make (->) infix
fmap :: (b -> c) -> (a -> b) -> (a -> c)         -- exactly the type of (.)
For monoids (this one is actually slightly useful), the instance is:
code:
instance Monoid b => Monoid (a -> b) where
    (<>) :: (a -> b) -> (a -> b) -> a -> b
    f <> g = \a -> f a <> g a
I've used this when defining custom Ord instances using Down (which reverses Ord instances). For example, I had a solution type where I was maximising the value, then if there were two solutions with equal value I wanted the one with the lowest weight to win.

code:
data Solution = Solution {value :: Int, weight :: Int}
    deriving (Eq, Show)
instance Ord Solution where
    compare = comparing value <> comparing (Down . weight)
Basically it saves you a few characters and that's it.

As with the monad instance, I'm not entirely sure - let's work out the types now (again, subject to the renaming):
code:
class Monad m where
    return :: b -> m b
    (>>=)  :: m b -> (b -> m c) -> m c
    join   :: m (m b) -> m b

-- replace m with ((->) a)
instance Monad ((->) a) where
    return :: b -> ((->) a) b
    (>>=)  :: ((->) a) b -> (b -> ((->) a) c) -> ((->) a) c
    join   :: ((->) a) (((->) a) b) -> ((->) a) b

-- make (->) infix and remove unneeded brackets
instance Monad ((->) a) where
    return :: b -> a -> b
    (>>=)  :: (a -> b) -> (b -> a -> c) -> a -> c
    join   :: (a -> a -> b) -> a -> b

-- let's guess the implementations based on the fact that we only have one thing
-- of any given type
instance Monad ((->) a) where
    return b = \a -> b             -- return = const
    f >>= g  = \a -> g (f a) a     -- not really sure how this'd be useful
    join f   = \a -> f a a         -- duplicate an argument for a function
Bear in mind that ((->) a) is the Reader monad, i.e. the "context" is that all values in the monad have access to a value of type a.

In short, I've used (<>) and join for functions, and only to save a few characters in common use cases.

One concrete use for join is, using Debug.Trace.traceShow (which bypasses the type system to print a value):
code:
traceShow      :: Show a => a -> b -> b
join traceShow :: Show a => a -> a
I.E. print a value as it passes through your code.

e: and let's just not talk about the function `fmap fmap fmap', also known as (.:) or (.).(.) or the boobs operator (which I have used more than the other mentioned functions here put together. I'll leave it as an exercise to figure out its type and what it does)

gonadic io fucked around with this message at 22:05 on May 8, 2015

gonadic io
Feb 16, 2011

>>=

sarehu posted:

Category theory is generally a waste of time if you are trying to get better at functional programming

ftfy

gonadic io
Feb 16, 2011

>>=
Yeah, gloss for sure. It's so handy when doing exactly this kind of simple interactive 2D display that you want. I'm working in F# and I can't find anything like it, I really don't want to have to go all the way to UE4 :(

gonadic io
Feb 16, 2011

>>=
I know it doesn't directly answer your question, but System.Environment.getArgs will give you that list of strings.

As for why it's not there by default. No idea, historical reasons probably, and it'd be nontrivial to overload to change it now.

edit:
I'd probably do it like one of these two examples, depending on how fancy I was feeling at the time:
code:
mainWithTwoArgs :: String -> String -> IO ()
printUsage :: IO ()

main = do
    args <- getArgs
    case args of
        [a1, a2] -> mainWithTwoArgs a1 a2
        _        -> printUsage

{-# LANGUAGE LambdaCase #-}
advancedMain = getArgs >>= \case
    [a1, a2] -> mainWithTwoArgs a1 a2
    _        -> printUsage

gonadic io fucked around with this message at 17:21 on Jun 3, 2015

gonadic io
Feb 16, 2011

>>=
I've got to say, I've really been loving F# lately. Having access to all of C#'s libraries and documentation, access to visual studio (although F# power tools and github integration is required, and resharper recommended). The only things I miss about Haskell tend to be more little-picture in nature: record ADTs with multiple constructors, hackage's ability to search for type signatures, 'where' blocks. My biggest complaint by far is the single-pass compiling which means that you can't really have forward references but you do kind of get used to it after a while.

gonadic io
Feb 16, 2011

>>=
That is the problem yeah, but not quite the right explanation - types and values are in different namespaces. The two can never be confused as there's never a place in the syntax which could accept either a type name or a value name (at least without wacky extensions).


Dominoes, the rules are that:

Values:
- Start with uppercase = constructor for a datatype (have to be defined with 'data' or 'newtype', and after the '=').
- Start with lowercase = normal value that you define with 'where', 'let', or is a top-level function in a module.

Types:
- Start with uppercase = an actual definite (called concrete) type, defined with 'data', 'newtype' or 'type', before the '='.
- Start with lowercase = a type variable, can turn out to be any concrete type (or you can constrain it using typeclasses and '=>').

e: I ran some similar code and got the error "Not in scope: data constructor 'Butt'". Can you see now why it gives that error? You can't define new data constructors on the fly in 'where' or 'let' blocks (but you CAN pattern match on existing ones there which is why it's not a syntax error).

gonadic io fucked around with this message at 07:49 on Jun 21, 2015

gonadic io
Feb 16, 2011

>>=
There are three exponentiation operators:
- (^) raises a number to a non-negative integer power (and is defined in terms of multiplication).
- (^^) raises a float to an integer power.
- (**) raises a float to a float power.

And by 'float' here I mean an instance of the Fractional typeclass which could be float, double, ratio, etc etc and by 'integer' I mean any instance of the Integral typeclass which includes int, integer, uints (called Word in haskell), etc.

edit: The best way to have diagnosed this on your own is to search hoogle for (^). Then you see that (^)'s second argument requires a member of Integral. What's that you ask? Just click on it to see its definition, what methods it defines, and a list of instances (crucially, which float is not in). Although from then I guess you're stuck unless you start searching through the docs for the other exponentiation functions.

gonadic io fucked around with this message at 08:48 on Jun 21, 2015

gonadic io
Feb 16, 2011

>>=
The bit operators are .|., .&., xor, compliment, shift, rotate, and more.

The logical operators are &&, ||, and not.

Not ideal I guess but it's not exactly a language designed for bit-janitoring.

gonadic io
Feb 16, 2011

>>=
Also Boolean is a valid instance for Bits so you can do all the logical operators to it. Even if things like shift won't make a lot of sense.

gonadic io
Feb 16, 2011

>>=
Also given that Data.Bits.(.&.) and (.|.) for Bools are defined as (&&) and (||) respectively they will short circuit.

gonadic io
Feb 16, 2011

>>=

Bognar posted:

I read that 3 times over wondering why Haskell had a Boobs operator.

(.).(.) is real, and occasionally useful.

gonadic io
Feb 16, 2011

>>=

VikingofRock posted:

I had never seen that operator before, but after sitting down with a pen and paper and figuring out what it does, that's really useful! I'll have to remember that.

It usually gets named (.:). Honestly I don't use it so much now, as I'm trying to cut back a little on how pointfree my code is.

P.S.: it can also be defined, a little more generally, as 'fmap fmap fmap'.

gonadic io
Feb 16, 2011

>>=

VikingofRock posted:

Is this mostly out of readability concerns?

Yes. It's not worth obscuring the code just to save 3-4 characters. I mean at one point I was using (.::), (.:::) etc and it was just impossible to work out what was going on.

VikingofRock posted:

Another question I've been pondering: does pointfree style affect performance through memoization? This article seems to indicate that it does, but I'm not sure I fully understand what it's saying.

Automatic momoization is extremly unintuitive and finicky in haskell. If you need something to memoise, either store it in an explicit list and pass it around, or you have to do the same kind of test as in that post. Or you could just use a library like memo that does it explicitly behind the scenes.

gonadic io
Feb 16, 2011

>>=
Well it depends on which language that you're talking about - F# and Scala can do both objects just fine, literally every functional language that I know has a function which executes a series of side-effecting commands.

I personally am not a huge fan of using Haskell for problems which I'm working out on the fly, as changing a pure program into one that uses mutation tends to require a fair bit of refactoring (either adding another argument to your stack of functions or threading a monad everywhere). If you know ahead of time that you'll need it, or don't anticipate needing to at all then there's no problem.

Hell, I've written plenty of shell scripts in haskell trivially enough.

gonadic io
Feb 16, 2011

>>=

fart simpson posted:

Embedded stuff?

Does this count?

gonadic io
Feb 16, 2011

>>=
Doing lexically scoped type signatures like that is pretty useful (see the great video http://matthew.brecknell.net/post/hole-driven-haskell/) but, at least in Haskell, requires an extension ScopedTypeVariables and as far as I can tell from a cursory Google isn't supported in elm.

gonadic io
Feb 16, 2011

>>=

QuantumNinja posted:

Lenses could work.

Then you'd have 5(?) problems. Lenses have 5 type param these days right?

gonadic io
Feb 16, 2011

>>=
I don't know about the structure of the code as a whole, but I'd probably clean it up to be like this:

code:
getGraphFromFile :: String -> [[Int]]
getGraphFromFile text = map snd result
  where ([numVertices]:edges) = map (map read . words) (lines text)
        empties = replicate [] numVertices
        explicitIndex = zip [0..] empties
        addEdge value index acc = (fst . (!! index) $ acc,
                                    (:) value . snd . (!! index) $ acc)
        result = foldr (\(first:(second:_)) acc ->
                        sortBy (comparing fst) .
                        nubBy ((==) `on` fst) .
                        (:) (addEdge first second acc) .
                        (:) (addEdge second first acc)
                        $ acc) explicitIndex edges
but honestly that giant lambda in a fold, as well as the use of (!!), is a huge red flag. I recommend using Data.Map instead of [(Int, Int)] as your main data structure and seeing if that's nicer.

gonadic io
Feb 16, 2011

>>=
I disagree with your last point - you "banging your head" was you learning Haskell, and you seeing QuantumNinja's solution without having come up with your own wouldn't be nearly as helpful.

It'd, of course, be entirely different if you just needed a solution and didn't care how it worked. In that case I'd recommend that you use Data.Graph instead of reimplementing it.

gonadic io
Feb 16, 2011

>>=
If we're being pedantic, then getGraphFromFile is a bad name and it should be called getGraphFromString. No files are involved at this stage. :colbert:

gonadic io fucked around with this message at 08:42 on Mar 14, 2016

gonadic io
Feb 16, 2011

>>=
If you don't want to learn a whole new set of keyboard bindings, both atom and sublime text 3 have hlint packages.

gonadic io
Feb 16, 2011

>>=
Foldl' sum will be faster than any of those, and using arrays more so too.

E: if that's ghci then unless you've changed it, it won't have been optimised either

gonadic io
Feb 16, 2011

>>=

xtal posted:

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

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

gonadic io
Feb 16, 2011

>>=

xtal posted:

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

How is this different from normal? :v:

gonadic io
Feb 16, 2011

>>=

the talent deficit posted:

i wrote an interpreter for a dumb programming language i invented

Including coursework, I've written a compiler, a physics engine, a program to generate a depth map from stereoscopic images, and then a bunch of algo stuff and puzzles.

Never done any web/networking stuff myself in it.

Adbot
ADBOT LOVES YOU

gonadic io
Feb 16, 2011

>>=
Your pattern matching is mostly fine, although honestly given that the chunksOf 2 is hard-coded to be 2 I recommend getting it to just return a pair. Lists with statically-known lengths are a code smell.

In terms of your problem it's pretty difficult to know exactly where the problem is, could you post a smaller snippet that still demonstrates the bug please?

Also the Debug.Trace module is handy for this kind of thing, although you might have to be careful that you don't fully evaluate the entire tree when printing at each step, or you'll just move your problem to there.

  • Locked thread