Live data from Hacker News

Thinking in Types

robots.thoughtbot.com

81–90 of 124 posts

Re: Thinking in Types

#81

Earlier quoted context omitted.

> law-abiding implementations Are you referring to category laws?

Lots of typeclasses have associated "laws" that well-behaved instances are expected to abide by.

But these are not enforceable by the type system (at least in Haskell), kind of supporting my point that types alone are rarely sufficient :)

Re: Thinking in Types

#82
post #81

Earlier quoted context omitted.

Lots of typeclasses have associated "laws" that well-behaved instances are expected to abide by.

But these are not enforceable by the type system (at least in Haskell), kind of supporting my point that types alone are rarely sufficient :)

I don't think anyone believes that types are sufficient outside, at least outside of a dependently typed language (at which point you'll have more diversity of opinion).

Re: Thinking in Types

#83
post #40

Earlier quoted context omitted.

Haskell is used in the NYTimes special features group that deploys 60+/yr web apps. http://www.infoq.com/presentations/haskell-newsroom-nyt tldw: - RoR shop, too slow and can't afford to scale simply by spinning up more AWS instances. - Haskell type system results in fewer bugs, less downtime than RoR. - Haskell's Conduit library is great for information flow (e.g. scanning Twitter firehose for breaking stories). - S…

It's worth pointing out that the presenter's first language was Haskell and he's been coding in it for over a decade. LYAH won't get you from apples to expert in weeks, much less months; more likely years. Consider me skeptical -- needing to build the latest and greatest of Haskell [7.8] from source on a modern Linux distro (CentOS binary with antiquated libgmp.so.3 dependency, seriously?) is a gigantic PITA compared…

Why do you need to build the latest and greatest? Building the very latest gcc/clang is also going to be a PITA. In either case, there's a perfectly servicable binary distribution and the stuff packaged in my OS's repo is still plenty usable.

Re: Thinking in Types

#84

I'm not sure that this works in more general cases, though. If I have a more general game with more objects of more types in it, adding each type to the render function is going to get old. In object oriented programming, I'd just call render() on each entry in the list of game objects. But this approach is going to lead me to: - render each entry in the list of Foo objects - render each entry in the list of Bar obje…

Sure it does. In object oriented languages, you still have to write all of the same code, you just group it by what data it affects. In (strongly typed) FP, you're writing the same code, but now it's grouped by functionality, rather than by data type.

Re: Thinking in Types

#85
post #31

> If we’re careful in our module exports, a change like this can be done in a backward-compatible way. Such an approach is outlined here ( http://www.yesodweb.com/blog/2011/10/settings-types ). The problem with this import solution is that almost nobody actually does it! Nearly every module you will ever import exposes most of the constructors of the ADTs they define - because Haskell encourages it - it's much simple…

Haskell's module system is kind of weak. Something like an ML variants, with interfaces being defined separately from implementations, is much nicer.

Re: Thinking in Types

#86
post #2

Seeing so much stuff about Haskell lately, but there seems to be a curious dearth of actual software written in it, if it's so great. How is it that janky hacked together languages like JS and PHP have huge numbers of projects built with them, while a supposedly superior language like Haskell is mostly academic? If it really makes you that much faster, where are the apps?

Honestly, it seems to me like if you don't understand category theory and type theory well, using Haskell will be either hard or impossible. That's what people who are into Haskell are into, and they seem to be a relatively rare breed. (I have a lot of trouble understanding these subjects, though I continue to try. I still don't know what the hell a monad really is.)

Do you want to know "what a monad is" in math or Haskell?

In programming, a monad is a particular design pattern, which is exposed in a particular interface (appropriately called Monad) in Haskell. The design pattern supports a certain way of combining things. The fact that so many disparate things support this interface (State, IO, Software Transactional Memory, Readers, Writers, Continuations...) means that all of the code we write that generically talks to that interface can talk about any of those things, and that's pretty powerful. The fact that one of those things is, in a certain sense, voodoo (IO) shouldn't lead you to think they all are - Monad is just an interface for combining things according to certain patterns.

Re: Thinking in Types

#87

I'm not sure that this works in more general cases, though. If I have a more general game with more objects of more types in it, adding each type to the render function is going to get old. In object oriented programming, I'd just call render() on each entry in the list of game objects. But this approach is going to lead me to: - render each entry in the list of Foo objects - render each entry in the list of Bar obje…

This approach seems to be what people new to Haskell gennerally go to first (probably because it is the natural solution given the type system). However, as much as we Haskellers hate to admit it, there are design patterns in Haskell that can offer more maintainable solutions that what the language naively presents.

In this case, a common pattern is to copy the OO concept of casting. For example, instead of having:

    class Render a where 
    render :: a -> IO()
we could have:

    class Renderable a where
    toRender a -> Render
along with:

    data Render = ...
    render :: Render -> IO()
    render r = ...
This leads to some noise with needing to put a bunch of toRender functions in a short amount of code, but this problem does not get worse as complexity increases.

Re: Thinking in Types

#88

I'm not sure that this works in more general cases, though. If I have a more general game with more objects of more types in it, adding each type to the render function is going to get old. In object oriented programming, I'd just call render() on each entry in the list of game objects. But this approach is going to lead me to: - render each entry in the list of Foo objects - render each entry in the list of Bar obje…

My preferred way to approach this, in Haskell specifically, is to use records as a naïve encoding of objects or interfaces. For example, expanding on the functionality a little bit:

    data GameEntity = GameEntity
        { render      :: IO ()
        , getPosition :: Point
        , setPosition :: Point -> GameEntity
        }

    makeBall :: Point -> GameEntity
    makeBall pos = GameEntity { render      = myRender
                              , getPosition = pos
                              , setPosition = mySetPos
                              }
        where myRender = {- draw the ball somehow -}
              mySetPos newPos = makeBall newPos
    
    {- and similar for makePlayer -}
That means that the rendering code will look like

    renderAll :: [GameEntity] -> IO ()
    renderAll allEntities = mapM_ render allEntities

    main = do
      pl = makePlayer 1 (0, 5.0)
      p2 = makePlayer 2 (10.0, 5.0)
      b  = makeBall (5.0, 5.0)
      {- ... -}
      renderAll [p1, p2, b] -- type-checks correctly now
What I've done is used a record type to encode the interface that it's supposed to expose, while hiding exactly what the particular implementations of the interface are. It's also nicely extensible; if I wanted to add in some other kind of entity—say, a turtle—all I'd need to do is add a function like

    makeTurtle :: Point -> ShellColor -> TurtleDisposition -> GameEntity
and nothing else need be changed.

Re: Thinking in Types

#89
post #7

I'm getting tired of reading: > This is why we hear that Haskell reprise if it compiles, it works. If this were true then functions would not need bodies, you would just define their signatures and move on with life. The truth is that even with its superb type system, Haskell still needs to run your code. Your code might be statically correct but its runtime is up to you. I would prefer it if people rephrased this cl…

And you know what I am tired of reading, Cedric Buest? You trolling every programming language discussion with fake names and sock puppets relating your fake made up experiences with functional programming. Do you have no dignity?

You know you're not covering your tracks very well when there are full-fledged watch accounts named after you which are trying to keep your uninformed opinion in check lol

Re: Thinking in Types

#90
post #31

> If we’re careful in our module exports, a change like this can be done in a backward-compatible way. Such an approach is outlined here ( http://www.yesodweb.com/blog/2011/10/settings-types ). The problem with this import solution is that almost nobody actually does it! Nearly every module you will ever import exposes most of the constructors of the ADTs they define - because Haskell encourages it - it's much simple…

You could also pattern-match over them with View Patterns[^1], i.e. export an alternate ADT that is the 'acceptable' view on the data and a function that takes the encapsulated implementation and turns it to the alternate representation—but I have literally never seen this done, save in the documents describing the motivations for View Patterns.

[^1]: https://ghc.haskell.org/trac/ghc/wiki/ViewPatterns

Post reply on HN