The AI code for my little soccer game basically works like this: There is a function that derives facts that describe the current situation on the pitch:
deriveFacts :: GameState -> [Fact]
... where the facts look kind of like this:
data Fact =
FactCanIntercept ObjId ObjId
| FactBestPosition Team Spot Spot
| FactKickOff
| FactBallCarrier ObjId
| FactBestShootingVector Velocity3
| FactBestPassingVector Velocity3
| ...
... and there are rules that look uniformly like this:
rule_shoot facts = do
FactBallCarrier ballCarrier <- checkBallCarrier facts
FactBestShootingVector goalVector <- checkBestShootingVector facts
return [message (ballCarrier, shoot goalVector)]
And then there is a rule engine that runs all the rules and gathers up the resulting messages.
That's fine so far and works quite nicely. What's kind of annoying, though: In this approach, I need an "accessor" function like this for every Fact:
checkBestShootingVector :: [Fact] -> Maybe Fact
checkBestShootingVector facts =
listToMaybe [e | e#(FactBestShootingVector {}) <- facts]
This approach leads to a lot of ugly boilerplate code. My question: Is there an elegant solution that removes the need for creating these accessor functions by hand?
You could refactor most of your Fact data as a record object
data FactRec = FR {
canIntercept :: [(ObjId,ObjId)], -- use lists for things you previously had multiple times
factBestPosition :: [(Team,Spot,Spot)], -- not sure about this one, maybe two entries not one list
kickOff :: Bool,
ballCarrier :: ObjID,
factBestShootingVector :: Velocity3,
factBestPassingVector :: Velocity3,
.....
}
Which gives you bulti-in accessor functions
if kickOff fr then something else somethingelse
So you wouldn't need to write all the check functions, but instead do
rule_shoot facts = message (ballCarrier facts, shoot $ goalVector facts)
If there are facts that genuinely might or might not be there, they could be of type Maybe something, and if there are facts that can be there an arbitrary number of times, they can be lists.
Related
I got a problem with thinking recursively in Haskell.
I am trying to build a survey application where questions conditionally lead to new questions based on the user's answers.
I got:
- Questions - a list of questions
- QuestionPaths - a list of question paths of questions which lead to new questions
- Answers a list of user's answers
You can think of QuestionPaths as a list of tuples where:
type QuestionPath = (QuestionId, AnswerChoice, NextQuestionId)
Basically this would read: If user answers a question QuestionId with an answer AnswerChoice, ask him NextQuestionId next.
I have attempted to model this problem domain with multiway trees (nodes can have multiple children):
data YesNo = Yes | No
data AnswerChoice = Skip
| Boolean YesNo
| ChooseOne [Text]
type Condition = AnswerChoice
data QuestionTree = QuestionNode {
question :: Question
, condition :: Condition
, userAnswer :: Maybe AnswerChoice
, children :: QuestionForest
}
type QuestionForest = [QuestionTree]
Unfortunately, I am clueless now on how to write algorithms that compose trees like this.
I basically need these kinds of functions for composition and traversal:
-- Constructs the tree from seed data
constructTree :: Questions -> QuestionPaths -> Answers -> QuestionTree
-- | Inserts answer to question in the tree
answerQuestion :: Question -> AnswerChoice
-- | Fetches the next unanswered question by traversing the tree.
getNextUnanswered :: QuestionTree -> Question
Can you please help me understand what would be the best way to construct and traverse a tree such as this?
What I'd do in such a case, is to store the answers in a separate data structure - not to insert them in the questions tree; put the answers in a separate list/Set, or in a file or database, and let the questions tree be immutable.
In order to keep track of which questions remain to be asked, you can "consume" the tree - keep your program state pointing to the next question, throwing away the questions already answered (letting the garbage collector reclaim them).
I'd design the tree like this:
data AllowedAnswers = YesOrNo {
ifUserAnsweredYes :: QuestionTree,
ifUserAnsweredNo :: QuestionTree
}
| Choices [(Text, QuestionTree)]
data QuestionTree = Question {
description :: Text
, allowedAnswers :: AllowedAnswers
, ifUserSkipsThisQuestion :: QuestionTree
}
| EndOfQuestions
Notice several things:
You don't have to worry about multiple possible paths leading to the same question - you can place the same QuestionTree node in multiple places, and it will be shared (Haskell won't create multiple copies of it)
This design has no place to hold the user's answers - they are stored elsewhere (i.e. a list somewhere, or a file) - no need to mutate the question tree.
As the user answers questions, just move your "pointer" to the next QuestionTree, depending on what the user answered.
As for "how to construct this tree from the (QuestionId, AnswerChoice, NextQuestionId) list" - I think I'd first convert it into a map: ```Map QuestionId [(AnswerChoice, Maybe QuestionId)], then I'd construct the tree by, starting with the ID of the first question, and fetching its immediate children from the Map, build the subtrees.
Example (for a very simplified case where the only possible answers are "yes" or "no", with no skipping allowed):
buildTree questionMap questionId = case Map.lookup questionId questionMap of
Nothing -> EndOfQuestions
Just (description, [("yes", nextQuestionIdIfYes), ("no", nextQuestionIdIfNo)]) ->
Question { description = description
, allowedAnswers = YesOrNo {
ifUserAnsweredYes = buildTree questionMap nextQuestionIdIfYes
, ifUserAnsweredNo = buildTree questionMap nextQuestionIdIfNo
}
, ifUserSkipsThisQuestion = EndOfQuestions
}
If you are wondering "why not just use the Map directly?" - yes, you could (and often it will be the right solution), but consider:
The QuestionTree structure expresses the programmer's intention more idiomatically than a Map of Id -> Thing
It is structurally guaranteed to have a child QuestionTree whenever pertinent - no need to do Map.lookup, which will return a Maybe, which you must verify that contains a Just (even when you know there is going to be a next question, even if it is EndOfQuestions)
I find myself running up against the same pattern in my designs where I start with a type with a few data constructors, eventually want to be able to type against those data constructors and thus split them into their own types, just to then have to increase the verbosity of other parts of the program by needing to use Either or another tagged-union for situations where I still need to represent multiple of these types (namely collections).
I am hoping someone can point me to a better way of accomplishing what I'm trying to do. Let me start with a simple example. I am modeling a testing system, where you can have nested test suites which eventually end in tests. So, something like this:
data Node =
Test { source::string }
Suite { title::string, children::[Node] }
So, pretty simple so far, essentially a fancy Tree/Leaf declaration. However, I quickly realize that I want to be able to make functions that take Tests specifically. As such, I'll now split it up as so:
data Test = Test { source::string }
data Suite = Suite { title::string, children::[Either Test Suite] }
Alternatively I might roll a "custom" Either (especially if the example is more complicated and has more than 2 options), say something like:
data Node =
fromTest Test
fromSuite Suite
So, already its pretty unfortunate that just to be able to have a Suite that can have a combination of Suites or Tests I end up with a weird overhead Either class (whether it be with an actual Either or a custom one). If I use existential type classes, I could get away with making both Test and Suite derive "Node_" and then have Suite own a List of said Nodes. Coproducts would allow something similar, where I'd essentially do the same Either strategy without the verbosity of the tags.
Allow me to expand now with a more complex example. The results of the tests can be either Skipped (the test was disabled), Success, Failure, or Omitted (the test or suite could not be run due to a previous failure). Again, I originally started with something like this:
data Result = Success | Omitted | Failure | Skipped
data ResultTree =
Tree { children::[ResultTree], result::Result } |
Leaf Result
But I quickly realized I wanted to be able to write functions that took specific results, and more importantly, have the type itself enforce the ownership properties: A successful suite must only own Success or Skipped children, Failure's children can be anything, Omitted can only own Omitted, etc. So now I end up with something like this:
data Success = Success { children::[Either Success Skipped] }
data Failure = Failure { children::[AnyResult] }
data Omitted = Omitted { children::[Omitted] }
data Skipped = Skipped { children::[Skipped] }
data AnyResult =
fromSuccess Success |
fromFailure Failure |
fromOmitted Omitted |
fromSkipped Skipped
Again, I now have these weird "Wrapper" types like AnyResult, but, I get type enforcement of something that used to only be enforced from runtime operation. Is there a better strategy to this that doesn't involve turning on features like existential type classes?
The first thing that came to my mind reading your sentence: "I quickly realized I wanted to be able to write functions that took specific results" is Refinement Types.
They allow to take only some values from a type as input, and make those constraints compile-time check/error.
There is this video from a talk at HaskellX 2018, that introduces LiquidHaskell, which allows the use of Refinement Types in Haskell:
https://skillsmatter.com/skillscasts/11068-keynote-looking-forward-to-niki-vazou-s-keynote-at-haskellx-2018
You have to decorate your haskell function signature, and have LiquidHaskell installed:
f :: Int -> i : Int {i | i < 3} -> Int would be a function which could only accept as second parameter an Int with a value < 3, checked at compile time.
You might as well put constraints on your Result type.
I think what you may be looking for is GADTs with DataKinds. This lets you refine the types of each constructor in a data type to a particular set of possible values. For example:
data TestType = Test | Suite
data Node (t :: TestType) where
TestNode :: { source :: String } -> Node 'Test
SuiteNode :: { title :: String, children :: [SomeNode] } -> Node 'Suite
data SomeNode where
SomeNode :: Node t -> SomeNode
Then when a function operates only on tests, it can take a Node 'Test; on suites, a Node 'Suite; and on either, a polymorphic Node a. When pattern-matching on a Node a, each case branch gets access to an equality constraint:
useNode :: Node a -> Foo
useNode node = case node of
TestNode source -> {- here it’s known that (a ~ 'Test) -}
SuiteNode title children -> {- here, (a ~ 'Suite) -}
Indeed if you took a concrete Node 'Test, the SuiteNode branch would be disallowed by the compiler, since it can’t ever match.
SomeNode is an existential that wraps a Node of an unknown type; you can add extra class constraints to this if you want.
You can do a similar thing with Result:
data ResultType = Success | Omitted | Failure | Skipped
data Result (t :: ResultType) where
SuccessResult
:: [Either (Result 'Success) (Result 'Skipped)]
-> Result 'Success
FailureResult
:: [SomeResult]
-> Result 'Failure
OmittedResult
:: [Result 'Omitted]
-> Result 'Omitted
SkippedResult
:: [Result 'Skipped]
-> Result 'Skipped
data SomeResult where
SomeResult :: Result t -> SomeResult
Of course I assume in your actual code there’s more information in these types; as it is, they don’t represent much. When you have a dynamic computation such as running a test that may produce different kinds of result, you can return it wrapped in SomeResult.
In order to work with dynamic results, you may need to prove to the compiler that two types are equal; for that, I direct you to Data.Type.Equality, which provides a type a :~: b which is inhabited by a single constructor Refl when the two types a and b are equal; you can pattern-match on this to inform the typechecker about type equalities, or use the various combinators to carry out more complicated proofs.
Also useful in conjunction with GADTs (and ExistentialTypes, less generally) is RankNTypes, which basically enables you to pass polymorphic functions as arguments to other functions; this is necessary if you want to consume an existential generically:
consumeResult :: SomeResult -> (forall t. Result t -> r) -> r
consumeResult (SomeResult res) k = k res
This is an example of continuation-passing style (CPS), where k is the continuation.
As a final note, these extensions are widely used and largely uncontroversial; you needn’t be wary of opting in to (most) type system extensions when they let you express what you mean more directly.
I'm learning Haskell by writing an OSC musical sequencer to use it with SuperCollider. But because I'd like to make fairly complex stuff with it, it will work like a programming language where you can declare variables and define functions so you can write music in an algorithmic way. The grammar is unusual in that we're coding sequences and sometimes a bar will reference the last bar (something like "play that last chord again but a fifth above").
I don't feel satisfied with my own explanation, but that's the best I can without getting too technical.
Anyway, what I'm coding now is the parser for that language, stateless so far, but now I need some way to implement a growing list of the declared variables and alikes using a dictionary in the [("key","value")] fashion, so I can add new values as I go parsing bar by bar.
I know this involves monads, which I don't really understand yet, but I need something meaningful enough to start toying with them or else I find the raw theory a bit too raw.
So what would be a clean and simple way to start?
Thanks and sorry if the question was too long.
Edit on how the thing works:
we input a string to the main parsing function, say
"afunction(3) ; anotherone(1) + [3,2,1]"
we identify closures first, then kinds of chars (letters, nums, etc) and group them together, so we get a list like:
[("word","afunction"),("parenth","(3)"),("space"," "),("semicolon",";"),("space"," "),("word","anotherone"),("parenth","(1)"),("space"," "),("opadd","+"),("space"," "),("bracket","[3,2,1]")]
then we use a function that tags all those tuples with the indices of the original string they occupy, like:
[("word","afunction",(0,8)),("parenth","(3)",(9,11)),("space"," ",(12,13)) ...]
then cut it in a list of bars, which in my language are separated using a semicolon, and then in notes, using commas.
And now I'm at the stage where those functions should be executed sequentially, but because some of them are reading or modifying previously declared values, I need to keep track of that change. For example, let's say the function f(x) moves the pitch of the last note by x semitones, so
f(9), -- from an original base value of 0 (say that's an A440) we go to 9
f(-2), -- 9-2 = 7, so a fifth from A
f(-3); -- 9-2-3, a minor third down from the last value.
etc
But sometimes it can get a bit more complicated than that, don't make me explain how cause I could bore you to death.
Adding an item to a list
You can make a new list that contains one more item than an existing list with the : constructor.
("key", "value") : existing
Where existing is a list you've already made
Keeping track of changing state
You can keep track of changing state between functions by passing the state from each function to the next. This is all the State monad is doing. State s a is a value of type a that depends on (and changes) a state s.
{- ┌---- type of the state
v v-- type of the value -}
data State s a = State { runState :: s -> (a, s) }
{- ^ ^ ^ ^
a function ---|--┘ | |
that takes a state ---┘ | |
and returns | |
a value that depends on the state ---┘ |
and a new state ------┘ -}
The bind operation >>= for State takes a value that depends on (and changes) the state and a function to compute another value that depends on (and changes) the state and combines them to make a new value that depends on (and changes) the state.
m >>= k = State $ \s ->
let ~(a, s') = runState m s
in runState (k a) s'
I'm new to Haskell and I like the programming approach of it a lot!
I've been running into this problem for the past 2 days, and no matter what I try, it refuses to work. I think I am confusing something about the nature of Haskell.
Here is my code (that doesn't work):
data Part = Part {partName :: String, events :: [Event]}
class Event e where
getChildren :: e -> [e]
This is for a music application. Event can be a NoteEvent, a DecrescendoEvent, a VolumeEvent, a KeyEvent, or anything that would "happen" in a piece of music.
A NoteEvent would have no children while a DecrescendoEvent would have child events that it would gradually reduce the volume of.
What am I doing wrong?
The problem you're having is that a sequence like [a] can only contain one type. There are two ways to deal with this.
1) Combine all your events into a single algebraic datatype, which might look something like this:
data Event = NoteEvent {note :: Int; duration :: Int}
| DecrescendoEvent {getChildren :: [Event]}
| VolumeEvent {change :: Double, getChildren :: [Event]}
...and so on. Now you can work with data of type [Event]. You can include the children like this:
2) Wrap the Event type in some sort of "wrapper" type, and create collections of that type. See http://www.haskell.org/haskellwiki/Heterogenous_collections for more information on this.
I'm sorry this problem description is so abstract: its for my job, and for commercial confidentiality reasons I can't give the real-world problem, just an abstraction.
I've got an application that receives messages containing key-value pairs. The keys are from a defined set of keywords, and each keyword has a fixed data type. So if "Foo" is an Integer and "Bar" is a date you might get a message like:
Foo: 234
Bar: 24 September 2011
A message may have any subset of keys in it. The number of keys is fairly large (several dozen). But lets stick with Foo and Bar for now.
Obviously there is a record like this corresponding to the messages:
data MyRecord {
foo :: Maybe Integer
bar :: Maybe UTCTime
-- ... and so on for several dozen fields.
}
The record uses "Maybe" types because that field may not have been received yet.
I also have many derived values that I need to compute from the current values (if they exist). For instance I want to have
baz :: MyRecord -> Maybe String
baz r = do -- Maybe monad
f <- foo r
b <- bar r
return $ show f ++ " " ++ show b
Some of these functions are slow, so I don't want to repeat them unnecessarily. I could recompute baz for each new message and memo it in the original structure, but if a message leaves the foo and bar fields unchanged then that is wasted CPU time. Conversely I could recompute baz every time I want it, but again that would waste CPU time if the underlying arguments have not changed since last time.
What I want is some kind of smart memoisation or push-based recomputation that only recomputes baz when the arguments change. I could detect this manually by noting that baz depends only on foo and bar, and so only recomputing it on messages that change those values, but for complicated functions that is error-prone.
An added wrinkle is that some of these functions may have multiple strategies. For instance you might have a value that can be computed from either Foo or Bar using 'mplus'.
Does anyone know of an existing solution to this? If not, how should I go about it?
I'll assume that you have one "state" record and these message all involve updating it as well as setting it. So if Foo is 12, it may later be 23, and therefore the output of baz would change. If any of this is not the case, then the answer becomes pretty trivial.
Let's start with the "core" of baz -- a function not on a record, but the values you want.
baz :: Int -> Int -> String
Now let's transform it:
data Cached a b = Cached (Maybe (a,b)) (a -> b)
getCached :: Eq a => Cached a b -> a -> (b,Cached a b)
getCached c#(Cached (Just (arg,res)) f) x | x == arg = (res,c)
getCached (Cached _ f) x = let ans = f x in (ans,Cached (Just (x,ans) f)
bazC :: Cached (Int,Int) String
bazC = Cached Nothing (uncurry baz)
Now whenever you would use a normal function, you use a cache-transformed function instead, substituting the resulting cache-transformed function back into your record. This is essentially a manual memotable of size one.
For the basic case you describe, this should be fine.
A fancier and more generalized solution involving a dynamic graph of dependencies goes under the name "incremental computation" but I've seen research papers for it more than serious production implementations. You can take a look at these for starters, and follow the reference trail forward:
http://www.carlssonia.org/ogi/Adaptive/
http://www.andres-loeh.de/Incrementalization/paper_final.pdf
Incremental computation is actually also very related to functional reactive programming, so you can take a look at conal's papers on that, or play with Heinrich Apfelmus' reactive-banana library: http://www.haskell.org/haskellwiki/Reactive-banana
In imperative languages, take a look at trellis in python: http://pypi.python.org/pypi/Trellis or Cells in lisp: http://common-lisp.net/project/cells/
You can build a stateful graph that corresponds to computations you need to do. When new values appear you push these into the graph and recompute, updating the graph until you reach the outputs. (Or you can store the value at the input and recompute on demand.) This is a very stateful solution but it works.
Are you perhaps creating market data, like yield curves, from live inputs of rates etc.?
What I want is some kind of smart memoisation or push-based recomputation that only recomputes baz when the arguments change.
It sounds to me like you want a variable that is sort of immutable, but allows a one-time mutation from "nothing computed yet" to "computed". Well, you're in luck: this is exactly what lazy evaluation gives you! So my proposed solution is quite simple: just extend your record with fields for each of the things you want to compute. Here's an example of such a thing, where the CPU-intensive task we're doing is breaking some encryption scheme:
data Foo = Foo
{ ciphertext :: String
, plaintext :: String
}
-- a smart constructor for Foo's
foo c = Foo { ciphertext = c, plaintext = crack c }
The point here is that calls to foo have expenses like this:
If you never ask for the plaintext of the result, it's cheap.
On the first call to plaintext, the CPU churns a long time.
On subsequent calls to plaintext, the previously computed answer is returned immediately.