Hacker Newsnew | past | comments | ask | show | jobs | submit | Martijn's commentslogin

You're in the wrong thread. :-)

But to answer your question anyway, this is the responsible line of code: https://github.com/marekdlugos/TakeMeAsIntern/blob/master/as...


Oh whoops good point. dunno how I managed that. astute connection made on your part, wow!


What is the correct thread? I am curious to what this comment is about now?



My Magic: the Gathering implementation uses a few GADTs. Interestingly they use GADTs in very different ways. Source code is here: https://github.com/MedeaMelana/Magic/blob/master/Magic/src/M...

Let me briefly highlight three of them:

1) Type Question models questions that the game might ask of players. Its constructors are tagged with the type of the answer to that question:

  data Question a where
    AskKeepHand :: Question Bool
    AskTarget   :: [EntityRef] -> Question EntityRef
    ...
This allows me to write cards that ask questions and later on plug in various interpreters of these questions (command line interface, JSON webserver, AI, test framework).

2) The ZoneRef datatype enumerates the various zones in a game of Magic (battlefield, hand, etc) but I've chosen to tag each ZoneRef constructor with a type that indicates what the type of a card is when you look up a reference to a card ("object" in Magic jargon):

  type ObjectRef ty = (ZoneRef ty, Id)
  lookupObject :: ObjectRef ty -> Magic (ObjectOfType ty)
Most functions that take object references as an argument like to constrain the type of the object referenced, and using a GADT allows them to do so. For example, dealing damage to an object (creature or planeswalker):

  data SimpleOneShotEffect = DamageObject Object (ObjectRef TyPermanent) Int ...
3) Type TargetList models zero or more targets a spell on the stack can target. Even though in essence it is just a list of targets, it is a GADT so that it can have a "return type" which is re-evaluated when one of more of the targets change (for example, by a card like Redirect or Reverberate).

Hope this helps!


What an interesting example. Not what I was expecting!

Can you think of an example of a bug that you avoided due to the extra type safety of gadts? Magic has some pretty complex rules so I imagine that writing exaustive test must be hard and that the extra static guarantees might be able to find something a dynamic checker wouldn't. (Its ok if you need some ingame jargon to explain that, I know the basic rules).


It's a combination of avoiding potential bugs and just modelling things differently altogether:

If I had to leave out the answer type of questions, I'd have to come up with an entirely different way of modelling answers. For example, I might have had to write a datatype like:

  data Answer = AnswerBool Bool | AnswerInt Int | ...
and then processing the answer (through pattern matching) would have to discard any answer it didn't like, which is awkward. Or I would have had to use a type class to keep everything type-safe which would have resulted in more complicated type signatures throughout the code.

For the TargetList, the current setup allows me to write functions that consume a target list of exactly the right size, for example:

  \(target1, target2) -> ...
rather than a normal list:

  \[target1, target2] -> ...
which in this case results in a pattern match exception if you pass it a list of any length other than 2.


If I remember correctly the automatically sorting through your pictures and picking the best is exactly what Google announced for Google+ at their last I/O keynote.


That's a cool feature, and not easy to implement. It generally ends up being a machine vision problem. (Google has both great talent and a lot more resource than a single-founder self-funded engineer like me.)


You don't really need to understand all these things in order to build "real" things with it. Just build something without caring too much whether an experienced Haskell programmer would find it elegant enough.

Most of the "clicks" I've had is when I'd already built something in a naive way (that worked perfectly) and someone showed me an alternative, more elegant way in which it could be written.


I wonder if this is also true if you are a foreigner visiting the US.

And I wonder if this also works for the Dutch police.


> I wonder if this is also true if you are a foreigner visiting the US.

It won't work on Customs and Immigration. When you're talking to them you're not "in the US" yet. After that, yes, the privilege against self-incrimination is granted to everyone in the United States, citizen or not.

> And I wonder if this also works for the Dutch police.

The privilege in question is considered an essential component of the Fifth Amendment to the US Constitution. Most other countries based on English common law have something similar. You'll have to look for parallel support within the Dutch legal system.


What company in Portugal do you work for?


That company was called Intervento, before they were acquired by EasyPhone and together became what is known nowadays as Altitude Software.

I live in Germany nowadays.


For some reason this reminds me of Quine Central[1]. :-)

[1] http://blog.sigfpe.com/2011/01/quine-central.html


Not really. There's a really nice paper by Graham Hutton, "A tutorial on the universality and expressiveness of fold" which goes into a bit more depth than OP does. Your question is answered directly in section 3.2, "The fusion property of fold". Basically, a sequence of multiple folds can be fused to a single fold.

See http://www.cs.nott.ac.uk/~gmh/fold.pdf


The article you linked proves the universality of fold, that I never doubted for one second.

What I was trying to say is that map is not universal, in that all function evaluations can be performed in parallel, because you can't use the result of the ith to compute the i+1th. In this respect map is in fact a restriction of fold.


Awesome - I had the same question. I was basically wondering how to inform the system of the opportunity to parallelize.

BTW, Hutton's book on Haskell is just so excellent.


> > boo :: Map Integer String -> String -> Integer

> This syntax is clean but it doesn't tell me anything that

> def boo(map: Map[Integer, String], key: String) : Integer

> doesn't tell me.

OP's point was not so much that the Haskell syntax is clean, but more that there is a huge difference between

Map Integer String -> String -> Integer

and

Map Integer String -> String -> IO Integer

The latter is allowed to do IO, while the former is not. There are very few languages that allow you to express this difference and have the compiler enforce it (Haskell being one of them). So "Map Integer String -> String -> Integer" tells you a lot more than "def boo(map: Map[Integer, String], key: String) : Integer" does.

For more information about what exactly types tell you, look up parametricity or read Philip Wadler's "Theorems for free".


"Haskell being one of them"

Also Fortran being one of them (you can mark functions and subroutines 'pure').


In Haskell variables are called variables because they potentially have a different value each time the function is called.

See also Variable (mathematics) [1] vs. Variable (computer science) [2].

[1] https://secure.wikimedia.org/wikipedia/en/wiki/Variable_%28m... [2] https://secure.wikimedia.org/wikipedia/en/wiki/Variable_%28c...


Consider applying for YC's Winter 2027 batch! Applications are open till November 2.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: