Ambiguous type variables

I need help with an "ambiguous type variables" error. My problem domain is backtracking search to construct musical phrases by choosing notes that fulfill as many simultaneous criteria as possible. At the beginning, I always know that I need to choose N notes, and they will be chosen in a particular order, one at a time. I don't need to worry about cycles, therefore. There is a way of calculating a "goodness" score, given a series of the first M notes (where M ranges from 2 to N). I'm looking for the solution with the best score. Because my problem may be too large to do a complete search, I think it would be great to be able to do a combination of breadth and depth searching... sort of like a chess program that searches X moves ahead but not all the way to the end of the game. So I start with 1 note and do a complete search on all partial solutions with X notes looking for the best score (dealing with ties somehow, not sure yet how), then take the first note from the best solution, then do a complete search on all partial solutions with 2 to X+1 notes, and so forth until X=N. I have in mind many possible ways of representing phrases and "moves," so I wanted to implement my basic algorithm in a class. I need three data types: - "the data" : a representation of a solution with from 1 to N choices applied - "a choice" : a representation of a choice of note at a particular point in the phrase - "memo" : a way of tracking the best partial solution(s) found during this phase of the search Here's my code so far In the following the type variable "d" is "the data", "c" is "a choice" and "memo" is a memo. The error is Ambiguous type variables 'd0', 'c0' in the constraint: (Bt d0 c0 memo) arising from a use of 'newMemo' class Bt d c memo | d -> c, d -> memo where -- a solution state is checked against the best solutions stored in -- the memo, and possibly replaces or augments the list of best -- solutions. updateMemo :: memo -> d -> memo newMemo :: memo pickBest :: Int -> memo -> d isSolution :: d -> Bool isSolution x = stateSize x == solutionSize x -- number of choices applied so far stateSize :: d -> Int -- note that data of type 'd' includes an indication of what the -- final solution size is, something put there when d is initialized solutionSize :: d -> Int enumerateChoices :: d -> [c] -- choices available at this point in the -- construction of the state -- compute a goodness score scoreState :: d -> Double applyChoice :: d -> c -> d -- note that this is only partially implemented. Never mind that -- it's not complete or correct, I'm still trying to understand -- where my error arises. -- -- What is will eventually do: completely searches N levels deep -- before picking best score, then takes best partial solution, -- backs up N-1 levels and does another complete search, -- etc. finally displays solution with best score. limBacktrack :: Int -> d -> memo limBacktrack n d = limBacktrack' n newMemo d limBacktrack' :: Int -> memo -> d -> memo limBacktrack' nGoal memo d | stateSize d == nGoal = updateMemo memo d | otherwise = foldl g memo (enumerateChoices d) where -- g :: memo -> choice -> memo g memo choice = limBacktrack' nGoal memo (applyChoice d choice) The error is Ambiguous type variables 'd0', 'c0' in the constraint: (Bt d0 c0 memo) arising from a use of 'newMemo'

On Mon, Mar 17, 2014 at 12:14:31PM -0700, Dennis Raddle wrote:
The error is
Ambiguous type variables 'd0', 'c0' in the constraint: (Bt d0 c0 memo) arising from a use of 'newMemo'
class Bt d c memo | d -> c, d -> memo where
newMemo :: memo
This is because given a use of 'newMemo', the compiler will be able to infer the type 'memo' from the context in which it is used, but there is no way for it to infer the types d and c. Hence they are ambiguous. There could be overlapping instances like instance Bt Int Int Char ... instance Bt Bool String Char ... so knowing memo=Char does not tell us what d and c are. (Note the compiler still refuses to make a choice even if there is only one matching instance in scope, because new instances could always be added in another module.) I can think of several possible solutions: 1. Add some functional dependencies memo -> d, memo -> c. This would "solve" the error though it is probably not what you want. 2. Add some 'dummy' arguments to newMemo (and other functions with a similar problem), like newMemo :: Proxy d -> memo However, this is a bit annoying to call since it requires giving a Proxy argument with a type signature. 3. Make Bt a record rather than a type class. This might actually be your best bet. You have to manually pass around Bt records, but you get to fully specify the types involved. -Brent

On Tue, Mar 18, 2014 at 2:14 AM, Dennis Raddle
class Bt d c memo | d -> c, d -> memo where
Could you also say something about the instances you intend to implement for this typeclass? If there's only 1, which the statement of the problem suggests as much, you can dispense of the typeclass entirely and just work with plain functions! Could be that you want something working first and generalize / polymorphize later. -- Kim-Ee

On Mon, Mar 17, 2014 at 1:28 PM, Kim-Ee Yeoh
On Tue, Mar 18, 2014 at 2:14 AM, Dennis Raddle
wrote: class Bt d c memo | d -> c, d -> memo where
Could you also say something about the instances you intend to implement for this typeclass?
If there's only 1, which the statement of the problem suggests as much, you can dispense of the typeclass entirely and just work with plain functions!
Could be that you want something working first and generalize / polymorphize later.
I don't know yet how I want to represent the solution being searched for; i.e. I don't know how I want to represent musical structures, and I need the freedom to try different ones without rewriting my code. I also wanted to implement a few toy problems to do testing on my algorithm. But, you are absolutely right that I am generalizing too quickly. I worked on a toy problem today and had several insights. I noticed that some problems have specifics that don't fit the same mold. -Dennis

I have another question, speaking of optimizing too soon. My data
structures will be things like rows of musical notes, implementable easily
as lists of lists. But I will often need to do things like replace one
element in a list. Should I use Array's? As I see it, lists get me certain
simplicity, and many operations using the natural syntax will be concise.
But then I'll have to do searches or random access and replacement.
What criteria does one use to make decisions like this? Do the easiest one
first and optimize later? I'm not even sure which is easiest as I don't
think there is a list element replacement function in the libraries.
On Mon, Mar 17, 2014 at 3:56 PM, Dennis Raddle
On Mon, Mar 17, 2014 at 1:28 PM, Kim-Ee Yeoh
wrote: On Tue, Mar 18, 2014 at 2:14 AM, Dennis Raddle
wrote: class Bt d c memo | d -> c, d -> memo where
Could you also say something about the instances you intend to implement for this typeclass?
If there's only 1, which the statement of the problem suggests as much, you can dispense of the typeclass entirely and just work with plain functions!
Could be that you want something working first and generalize / polymorphize later.
I don't know yet how I want to represent the solution being searched for; i.e. I don't know how I want to represent musical structures, and I need the freedom to try different ones without rewriting my code. I also wanted to implement a few toy problems to do testing on my algorithm.
But, you are absolutely right that I am generalizing too quickly. I worked on a toy problem today and had several insights. I noticed that some problems have specifics that don't fit the same mold. -Dennis

On Wed, Mar 19, 2014 at 8:47 AM, Dennis Raddle
Do the easiest one first and optimize later?
Yes. Fwiw, iterating in the zone doesn't even feel like iterating.
I'm not even sure which is easiest as I don't think there is a list element replacement function in the libraries.
It's a one-liner. -- Kim-Ee

You might try Data.Sequence. Its update/take/drop/index etc all have nice
performance and you can use Foldable.toList to convert it to a list
whenever you feel a pressing need to use list pattern matching without
sacrificing much performance.
On Tue, Mar 18, 2014 at 9:47 PM, Dennis Raddle
I have another question, speaking of optimizing too soon. My data structures will be things like rows of musical notes, implementable easily as lists of lists. But I will often need to do things like replace one element in a list. Should I use Array's? As I see it, lists get me certain simplicity, and many operations using the natural syntax will be concise. But then I'll have to do searches or random access and replacement.
What criteria does one use to make decisions like this? Do the easiest one first and optimize later? I'm not even sure which is easiest as I don't think there is a list element replacement function in the libraries.
On Mon, Mar 17, 2014 at 3:56 PM, Dennis Raddle
wrote: On Mon, Mar 17, 2014 at 1:28 PM, Kim-Ee Yeoh
wrote: On Tue, Mar 18, 2014 at 2:14 AM, Dennis Raddle
wrote: class Bt d c memo | d -> c, d -> memo where
Could you also say something about the instances you intend to implement for this typeclass?
If there's only 1, which the statement of the problem suggests as much, you can dispense of the typeclass entirely and just work with plain functions!
Could be that you want something working first and generalize / polymorphize later.
I don't know yet how I want to represent the solution being searched for; i.e. I don't know how I want to represent musical structures, and I need the freedom to try different ones without rewriting my code. I also wanted to implement a few toy problems to do testing on my algorithm.
But, you are absolutely right that I am generalizing too quickly. I worked on a toy problem today and had several insights. I noticed that some problems have specifics that don't fit the same mold. -Dennis
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (4)
-
Brent Yorgey
-
David McBride
-
Dennis Raddle
-
Kim-Ee Yeoh