How should I model a type-safe index in Purescript? - indexing

In my application, I'd like to index sets of objects in a type-safe way using a structure similar to a relational database index. For example, I might want to index a set of User objects based on age and name:
import Data.Map as M
import Data.Set as S
type AgeNameIndex = M.Map Int (M.Map String (S.Set User))
Furthermore, I'd like to do operations like union and difference on indexes efficiently, e.g.:
let a = M.singleton 42 $ M.singleton "Bob" $ S.singleton $ User { ... }
b = M.singleton 42 $ M.singleton "Tim" $ S.singleton $ User { ... }
c = union a b -- contains both Bob and Tim
I've tried to model this as follows:
module Concelo.Index
( index
, union
, subtract
, lastValue
, subIndex ) where
import Prelude (($), (>>>), flip, Unit, unit, class Ord)
import Control.Monad ((>>=))
import Data.Map as M
import Data.Set as S
import Data.Maybe (Maybe(Nothing, Just), fromMaybe)
import Data.Tuple (Tuple(Tuple))
import Data.Foldable (foldl)
import Data.Monoid (mempty)
class Index index key value subindex where
isEmpty :: index -> Boolean
union :: index -> index -> index
subtract :: index -> index -> index
lastValue :: index -> Maybe value
subIndex :: key -> index -> subindex
instance mapIndex :: (Index subindex subkey value subsubindex) =>
Index (M.Map key subindex) key value subindex where
isEmpty = M.isEmpty
union small large =
foldl (m (Tuple k v) -> M.alter (combine v) k m) large (M.toList small)
where
combine v = case _ of
Just v' -> Just $ union v v'
Nothing -> Just v
subtract small large =
foldl (m (Tuple k v) -> M.alter (minus v) k m) large (M.toList small)
where
minus v = (_ >>= v' ->
let subindex = subtract v v' in
if isEmpty subindex then Nothing else Just subindex)
lastValue m = M.findMax m >>= (_.value >>> lastValue)
subIndex k m = fromMaybe mempty $ M.lookup k m
instance setIndex :: (Ord value) => Index (S.Set value) Unit value Unit where
isEmpty = S.isEmpty
union = S.union
subtract = flip S.difference
lastValue s = Nothing -- todo: S.findMax
subIndex _ _ = unit
index f = foldl (acc v -> union (f v) acc) mempty
However, the Purescript compiler doesn't like that:
Compiling Concelo.Index
Error found:
in module Concelo.Index
at /home/dicej/p/pssync/src/Concelo/Index.purs line 24, column 1 - line 44, column 49
No type class instance was found for
Concelo.Index.Index subindex0
t1
t2
t3
The instance head contains unknown type variables. Consider adding a type annotation.
in value declaration mapIndex
where subindex0 is a rigid type variable
t1 is an unknown type
t2 is an unknown type
t3 is an unknown type
See https://github.com/purescript/purescript/wiki/Error-Code-NoInstanceFound for more information,
or to contribute content related to this error.
My understanding of this message is that I haven't properly stated that map values in the mapIndex instance are themselves Index instances, but I don't know how to fix that. Where might I add a type annotation to make this compile? Or am I even on the right track given what I'm trying to do?

This is almost certainly because PureScript currently lacks functional dependencies (or type families) which makes this kind of information un-inferrable. There's a writeup of the issue here: https://github.com/purescript/purescript/issues/1580 - it is something we want to support.
There was a discussion about a case very similar to this today as it happens: https://github.com/purescript/purescript/issues/2235
Essentially, the problem here is that the functions of the class do not use all of the type variables, which means there's no way to propagate the information to the constraint for looking up a suitable instance.
I don't really have a suggestion for how to do what you're after here with things as they are, aside from avoiding the class and implementing it with specific types in mind.

Related

Match inside match - ocaml raises syntax error

Does anyone know why this function raises the syntax error? I haven't provided my written side functions, since they are probably not that relevant here, since it's revolving around proper syntax.
I tried deleting the brackets that raised the error (which I think.. should be there?), only to then raise another syntax error one line lower, at the begining of the row with the line "|".
type 'a grid = 'a Array.t Array.t
type problem = { initial_grid : int option grid }
type available = { loc : int * int; possible : int list }
type state = { problem : problem; current_grid : int option grid; available = available list }
let branch_state (state : state) : (state * state) option =
if prazni_kvadratki state.current_grid = [] then
None
else
let lst = prazni_kvadratki state.current_grid in
let loc = List.hd lst in
let st1_grid = copy_grid state.current_grid in
let st2_grid = copy_grid state.current_grid in
match razpolozljive state.current_grid loc with
| x :: xs -> (vstavi_vrednost st1_grid loc (Some x);
let st1 = {problem = state.problem; current_grid = st1_grid} in
match xs with
| [y] -> (vstavi_vrednost st2_grid loc (Some y);
let st2 = {
problem = state.problem;
current_grid = st2_grid
}) (* this is where it shows me a syntax error*)
| y :: ys -> let st2 = {
problem = state.problem;
current_grid = copy_grid state.current_grid;
available = {loc = loc; possible = xs}
})
Some (st1, st2)
On around the 5th last line or so you have let with no matching in. The let expression always must have an in.
The basic rule for nested match is that you should use parentheses or begin/end around the inner one:
match x with
| [] -> 0
| [_] ->
begin
match y with
| [] -> 1
| _ -> 2
end
| _ -> 3
Otherwise the final cases of the outer match look like they belong to the inner one. I don't think this is your problem here because you have no outer cases after the inner match.
Syntax issues
You have a few syntax issues.
type state = { problem : problem; current_grid : int option grid; available = available list }
You likely meant to have:
type state = { problem : problem; current_grid : int option grid; available : available list }
However, given how you construct values later in your program where you provide a value for the available field in one case but not in the other, you may want a variant type that allows your state type to be constructed with or without this value, with distinct behavior when not constructed with this value. This might look like:
type state =
| With_available of { problem : problem;
current_grid : int option grid;
available : available list }
| Without_available of { problem : problem;
current_grid : int option grid }
The other syntax issue is missing an in to go with a let which brings us to:
Scoping issues
There are clearly some miunderstandings here for you in regards to how scope works with let bindings in OCaml.
Aside from a definition at the topmost level of a program, all let bindings are local bindings. That is, they apply to a single expression that trails an in keyword.
Consider this toplevel session.
# let x = 5;;
val x : int = 5
# let y =
let x = 42 in
x + 3;;
val y : int = 45
# x;;
- : int = 5
#
Here the x bound with let x = 42 in x + 3 is only in scope for the duration of the expression x + 3. Once we're done with that expression, that binding for x is gone. In the outer scope, x is still bound to 5.
In both cases in your match you bind names st1 and st2, which would have to be local bindings, but then you try to use them in an outer scope, where they don't exist.
If you want st1 and st2, you'd need to bind them in a similar way to a and b in the below simple example.
# let (a, b) = match [1; 2; 3] with
| [x] -> (x, x)
| x :: y :: _ -> (x, y)
| _ -> (1, 1)
in
a + b;;
- : int = 3
#
Pattern-matching
Please also note that the pattern-matching you're shown is not exhaustive. It does not handle an empty list. If you consider it impossible that an empty list will be a result, you still have to either handle it anyway or use a different data structure than a list which can by definition be empty.
You've shown pattern-matching of the basic pattern:
match some_list with
| x :: xs ->
match xs with
| [y] -> ...
| y :: xs -> ...
We can actually match against the two possibilities you've show in one level of match.
match some_list with
| x :: [y] -> ...
| x :: y :: ys -> ...
If you still need to address y :: ys as xs in the second case, we can readily bind that name with the as keyword.
match some_list with
| x :: [y] -> ...
| x :: (y :: ys as xs) -> ...

How do I solve this ambiguous type variable error in Haskell?

I couldn't find an answer to my question among several ambiguous type variable error questions.
I'm currently trying to get this code I found to work. (https://gist.github.com/kirelagin/3886243)
My code:
import Control.Arrow
import Data.List
import qualified Data.Map as M
import Data.Function
main = do
putStrLn "Start test"
let foo = "Hello World"
let freqTest = freqList foo
putStrLn "Frequentie list"
print freqTest
putStrLn "Done.."
let treeTest = buildTree freqTest
putStrLn "Huffman Tree"
print treeTest
putStrLn "Done.."
let codeMaphTest = buildCodemap treeTest
putStrLn "Codemap ding"
-- print codeMaphTest
putStrLn "Done.."
--This typeclass is supposed to make life _a bit_ easier.
class Eq a => Bits a where
zer :: a
one :: a
instance Bits Int where
zer = 0
one = 1
instance Bits Bool where
zer = False
one = True
-- Codemap is generated from a Huffman tree. It is used for fast encoding.
type Codemap a = M.Map Char [a]
-- Huffman tree is a simple binary tree. Each leaf contains a Char and its weight.
-- Fork (node with children) also has weight = sum of weights of its children.
data HTree = Leaf Char Int
| Fork HTree HTree Int
deriving (Show)
weight :: HTree -> Int
weight (Leaf _ w) = w
weight (Fork _ _ w) = w
-- The only useful operation on Huffman trees is merging, that is we take
-- two trees and make them children of a new Fork-node.
merge t1 t2 = Fork t1 t2 (weight t1 + weight t2)
-- `freqList` is an utility function. It takes a string and produces a list
-- of pairs (character, number of occurences of this character in the string).
freqList :: String -> [(Char, Int)]
freqList = M.toList . M.fromListWith (+) . map (flip (,) 1)
-- `buildTree` builds a Huffman tree from a list of character frequencies
-- (obtained, for example, from `freqList` or elsewhere).
-- It sorts the list in ascending order by frequency, turns each (char, freq) pair
-- into a one-leaf tree and keeps merging two trees with the smallest frequencies
-- until only one tree is remaining.
buildTree :: [(Char, Int)] -> HTree
buildTree = bld . map (uncurry Leaf) . sortBy (compare `on` snd)
where bld (t:[]) = t
bld (a:b:cs) = bld $ insertBy (compare `on` weight) (merge a b) cs
-- The next function traverses a Huffman tree to obtain a list of codes for
-- all characters and converts this list into a `Map`.
buildCodemap :: Bits a => HTree -> Codemap a
buildCodemap = M.fromList . buildCodelist
where buildCodelist (Leaf c w) = [(c, [])]
buildCodelist (Fork l r w) = map (addBit zer) (buildCodelist l) ++ map (addBit one) (buildCodelist r)
where addBit b = second (b :)
-- Simple functions to get a Huffman tree or a `Codemap` from a `String`.
stringTree :: String -> HTree
stringTree = buildTree . freqList
stringCodemap :: Bits a => String -> Codemap a
stringCodemap = buildCodemap . stringTree
-- Time to do the real encoding and decoding!
-- Encoding function just represents each character of a string by corresponding
-- sequence of `Bit`s.
encode :: Bits a => Codemap a -> String -> [a]
encode m = concat . map (m M.!)
encode' :: Bits a => HTree -> String -> [a]
encode' t = encode $ buildCodemap t
-- Decoding is a little trickier. We have to traverse the tree until
-- we reach a leaf which means we've just finished reading a sequence
-- of `Bit`s corresponding to a single character.
-- We keep doing this to process the whole list of `Bit`s.
decode :: Bits a => HTree -> [a] -> String
decode tree = dcd tree
where dcd (Leaf c _) [] = [c]
dcd (Leaf c _) bs = c : dcd tree bs
dcd (Fork l r _) (b:bs) = dcd (if b == zer then l else r) bs
Output:
huffmancompress.hs:17:24: error:
* Ambiguous type variable `a0' arising from a use of `buildCodemap'
prevents the constraint `(Bits a0)' from being solved.
Relevant bindings include
codeMaphTest :: Codemap a0 (bound at huffmancompress.hs:17:9)
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Bits Bool -- Defined at huffmancompress.hs:35:10
instance Bits Int -- Defined at huffmancompress.hs:31:10
* In the expression: buildCodemap treeTest
In an equation for `codeMaphTest':
codeMaphTest = buildCodemap treeTest
In the expression:
do putStrLn "Start test"
let foo = "Hello World"
let freqTest = freqList foo
putStrLn "Frequentie list"
....
|
17 | let codeMaphTest = buildCodemap treeTest
| ^^^^^^^^^^^^^^^^^^^^^
I've tried serveral things I found on the internet but nothing worth mentioning to be honest.
Maybe any of you guys can help me out!
On line 17, where the error points you:
let codeMaphTest = buildCodemap treeTest
What type is codeMaphTest? Should it be Codemap Int? Or Codemap String? Or, perhaps, Codemap Bool? The function buildCodemap can return any type, as long as it has an instance of Bit. So what type should it be?
The compiler doesn't know. There is nowhere to glean this information from. It's ambiguous.
And this is exactly what the compiler is telling you: "ambiguous type variable".
One way to fix this is to provide a type annotation (exactly as the error message says, by the way):
let codeMaphTest :: Codemap Int = buildCodemap treeTest
Note that I chose Int just as an example, because I don't know which type you meant (I'm somewhat like the compiler in that respect). Please substitute your own type - the one you actually wanted there.
Your code is indeed ambiguous. buildCodemap treeTest has a polymorphic type Bits a => Codemap a, so it can be used as a Codemap Int, a Codemap Bool, or even as another type if you defines further instances of Bits.
This is not a problem, on its own, but later on you try to use this value (e.g., to print it), so we really need to pick a concrete type a.
You could pick a at the definition point:
let codeMaphTest :: Codemap Int
codeMaphTest = buildCodemap treeTest
Or, alternatively, you could choose a later on, where you use it
print (codeMaphTest :: Codemap Int)

Getting syntax error in ocaml

I am trying to make a module that would allow to create a table in ocaml. It would do a query called project to limit the table's values. However on the last line of the definition of the function chooser I am getting syntax error.
module type TABLE =
sig
type database
type table
val create_table: string list * string list* (string list) list -> table
val printTable : table -> string
val listToString : string list -> string
val project : string list * table -> table
val chooser : string list * string list-> string list
end;;
module UsingTable : TABLE =
struct
type table = (string list * string list* (string list) list)
type database = table list
let create_table (a,b,c) = (a,b,c)
let chooser inputList = (
for i = 0 to (List.length trueFalseList-1) do
if List.nth trueFalseList i = "True"
then
(List.nth inputList i)::ans
done
List.rev ans;;)
let project (conditions, aTable)= (
let rec innerProc tmp= function
n,[],v->List.rev tmp
|n,cH::cT,v-> if List.mem cH conditions
then innerProc (["True"]::tmp) (n,cT,v)
else innerProc (["False"]::tmp) (n,cT,v)
in
let trueFalseList = innerProc [] aTable
let rec finalListCreator = match aTable with
n,[],[]->n,[],[]
|n,cH::cT,[]->n,chooser cH ::finalListCreator cT,[]
|n,c,h::t -> n,c,chooser h ::finalListCreator t
)
let rec listToString aList = match aList with
[] -> ""
| h::t -> "\t"^h^"\t"^listToString t
let rec printTable aTable = match aTable with
[],[],[] -> ""
| [],[],vH::vT -> "\n"^(listToString vH)^printTable ([],[],vT)
| [],cH::cT,v -> "\t"^cH^"\t"^printTable([],cT, v)
| n, c , v-> "\n"^(List.hd n)^"\n\n"^printTable([],c, v)
end;;
let atable =UsingTable.create_table (["Student"], ["Id";"Name";"Gender";"Course"],
[["001";"Jim";"M";"AlgoDS"];
["002";"Linnea";"F";"Databases"];
["003";"Anna";"F";"C#"];
["004";"Abby";"F";"C#"];
["005";"Arthur";"M";"JavaScript"]]);;
print_string (UsingTable.printTable atable) ;;
These lines have at least two syntax problems:
let chooser inputList = (
for i = 0 to (List.length trueFalseList-1) do
if List.nth trueFalseList i = "True"
then
(List.nth inputList i)::ans
done
List.rev ans;;)
First, the for .. done is one expression, and List.rev ans is another expression. You need a semicolon (;) between them.
Second, you should use ;; only when you want the input up to that point to be processed. But here if you process the input at the ;; you are missing a right parenthesis.
In my opinion, you should be entering ;; only at the toplevel. The best way to think of this token is as an instruction to the toplevel. It's not part of normal OCaml syntax.
These are only the first two errors. There are quite a few other errors in the code. It might be good to add one function at a time to the module so you can concentrate on a few problems at a time.
Update
The environment you're using is a little bit extra complicated because it has an Evaluate button that asks to evaluate what you've typed so far. This makes the ;; token much less useful.
It would be a good discipline to use this environment without using the ;; token at all. Just click the Evaluate button when you want an evaluation.
The main trick is if you want to evaluate a statement (a unit-valued expression in OCaml) at the outer level, like say Printf.printf "hello world\n". The usual idiom to avoid putting ;; before this is to make it into a declaration like so:
let () = Printf.printf "hello world\n"
That is the one non-obvious idiom that people use when writing source code (where the ;; almost never appears in my experience).

ocaml constructing module (super beginner)

I'm new to module programming using ocaml. I made a dictionary module such as
module type DICT =
sig
type key
type 'a dict
...
val lookup : 'a dict -> key -> 'a option
...
end
module DictList : DICT with type key = string =
struct
type key = string
type 'a dict = (key * 'a) list
...
**let rec lookup d k =
match d with
| [] as dict -> None
| (key, value)::tl as dict -> if( key = k ) then (key, value)
else lookup tl k**
...
end
lookup d k searches the key k in the dictionary d. If the key is found, it returns the item, otherwise, it returns None. However, I got a error which says
Error: This expression has type 'a * 'b
but an expression was expected of type 'c list
at lookup function.
What is the problem and how can I fix it?
You have two problems here (and none of them give the error you claim you're getting).
1st problem: your lookup function doesn't have consistent type
One branch returns None so the type should be 'a option.
Another branch returns (key, value) so the type should be 'a * 'b.
How to fix? Change (key, value) to Some (key, value).
Unfortunately, there is also
2nd problem: your lookup function does not correspond to its definition in module type.
If you look at your definition of DICT, you'll see that lookup is 'a dict -> key -> 'a option.
Now, in your definition of DictList module key is string, so lookup should be 'a dict -> string -> 'a option, where a is the type of values you are storing in your dictionary. It means that you cannot return Some (key, value), as then lookup will have signature 'a dict -> string -> (string * 'a) option. Return just Some value.
So, your definition should look like
module DictList : DICT with type key = string =
struct
type key = string
type 'a dict = (key * 'a) list
let rec lookup d k =
match d with
| [] -> None
| (key, value)::tl -> if (key = k) then Some value else lookup tl k
end
All branches of the match expression in lookup should have the same type - which corresponds to the return type of lookup: 'a option. So the "found" case should return Some value instead of (key, value).

Make Test.QuickCheck.Batch use a default type for testing list functions

I am testing a function called extractions that operates over any list.
extractions :: [a] -> [(a,[a])]
extractions [] = []
extractions l = extract l []
where extract [] _ = []
extract (x:xs) prev = (x, prev++xs) : extract xs (x : prev)
I want to test it, for example, with
import Test.QuickCheck.Batch
prop_len l = length l == length (extractions l)
main = runTests "extractions" defOpt [run prop_len]
But this won't compile; I have to supply a type either for run or prop_len, because QuickCheck can't generate [a], it has to generate something concrete. So I chose Int:
main = runTests "extractions" defOpt [r prop_len]
where r = run :: ([Int] -> Bool) -> TestOptions -> IO TestResult
Is there any way to get QuickCheck to choose a for me instead of having it specified in the type of run?
The quickcheck manual says "no":
Properties must have monomorphic types. `Polymorphic' properties, such as the one above, must be restricted to a particular type to be used for testing. It is convenient to do so by stating the types of one or more arguments in a
where types = (x1 :: t1, x2 :: t2, ...)
clause...