I'm trying to write a function in SML that given a list of variables, it returns a list of tuples of every possible boolean assignment.
Essentially, I want the code to do this:
fun allAssignments ["p", "q"] =
[[("p", True), ("q", True) ]
[("p", True), ("q", False)]
[("p", False), ("q", True) ]
[("p", False), ("q", False)]]
However, I wrote this function and although it makes sense to me, I keep getting tycon mismatch errors and I can't rectify it:
fun allAssignments nil = [[]]
| allAssignments (x::xs) = [(x, true)::allAssignments xs] # [(x, false)::allAssignments xs]
Could anyone help point me in the right direction? Thanks!
Per your example, allAssignments needs to have the type string list -> (string * bool) list list (or potentially 'a list -> ('a * bool) list list or ''a list -> (''a * bool) list list, but I'll just stick with string for simplicity; the implementation is the same either way).
So, allAssignments xs must have the type (string * bool) list list, and (x, true) must have the type string * bool. But then (x, true) :: allAssignments xs is a type mismatch, because :: expects its second argument to be a list whose elements have the same type as its first argument, whereas in your case the second argument is a list whose elements are lists (which the first argument is not).
If we imagine a version of Standard ML that didn't actually check types, your version of allAssignments would give the following results:
allAssignments [] → [[]]
allAssignments ["q"] → [[("q", true), []], [("q", false), []]]
allAssignments ["p", "q"] → [[("p", true), [("q", true), []], [("q", false), []]], [("p", false), [("q", true), []], [("q", false), []]]]
As you can see, it doesn't really work out. One problem is that the assignments of "q" are nested in more levels of lists than the assignments of "p" (hence the type error). Another problem is that ("p", true) and ("p", false) each appear only once, whereas ("q", true) and ("q", false) each appear twice.
To fix this, you need to actually "open up" allAssignments xs and prepend (x, true) to each of the individual lists that it contains, and then the same for (x, false).
Here's one way, using map:
fun allAssignments nil = [nil]
| allAssignments (x::xs) =
(map (fn assignments => (x, true) :: assignments) (allAssignments xs))
# (map (fn assignments => (x, false) :: assignments) (allAssignments xs))
though I should mention that this implementation is not at all optimal; both the computation time and the memory usage can be reduced significantly, especially if you don't care about the order in which the assignments are returned.
I have a list here that has the following structure:
list = [((1,1),[("A", 1), ("D", 4), ("E", 5)]), ((2,2),[("B", 2)]), ((3,3),[("C",3)])]
I want to output a list that has the following structure (aka summing the values of each of the second values of each sublist so for example (1+4+5) = 10
[((1,1),10), ((2,2),2), ((3,3),3))]
I am not sure how to get that structure by using map or even filter and the closest I have gotten is:
map snd (concat (map snd list))
which produces [1,4,5,2,3]
How would I achieve this structure?
First, write out the types:
have :: [((Int,Int), [(String,Int)])]
have = [ ((1,1),[("A", 1), ("D", 4), ("E", 5)]), ... ]
want :: [((Int,Int), Int)]
Evidently, the (Int,Int) isn't really relevant here, nor is the String. So our conversion function can be
give :: [(a, [(b, Int)])] -> [(a, Int)]
Furthermore, the a is just passed as-is, so the interesting bit is going to be [(b, Int)] -> Int. For this, you first need to throw away the bs
Prelude> map snd [("A", 1), ("D", 4), ("E", 5)]
[1,4,5]
and sum the result (composition!)
Prelude> sum . map snd $ [("A", 1), ("D", 4), ("E", 5)]
10
So sum . map snd is the function you'll need to apply to every RHS in the list of outer tuples.
How do you actually use it on only the RHS? Well, one way is to write a lambda
\(x,y) -> (x, f y)
...but actually there's a standard combinator for this, called second
second :: (b -> c) -> (d,b) -> (d,c)
(operating on the snd element of a tuple, applying a function† to it, putting it back in the tuple).
Prelude Control.Arrow> second (sum . map snd) (346, [("A", 1), ("D", 4), ("E", 5)])
(346,10)
All that's left to do is mapping that whole thing over the outer list:
Prelude Control.Arrow> map (second $ sum . map snd) [((1,1),[("A", 1), ("D", 4), ("E", 5)]), ((2,2),[("B", 2)]), ((3,3),[("C",3)])]
[((1,1),10),((2,2),2),((3,3),3)]
Or as a definition
give :: Num c => [(a, [(b, c)])] -> [(a, c)]
give = map . second $ sum . map snd
†If you look in the docs you'll find that second is actually more general than that: it can work not only with functions, but general arrows ~>, i.e. second :: Arrow (~>) => (b ~> c) -> ((d,b)~>(d,c)). If that's confusing to you, don't worry... in most applications, the arrow will just be the normal function one.
If you don't mind the map you could use list comprehension here:
list = [((1,1),[("A",1),("D",4),("E",5)]),((2,2),[("B",2)]),((3,3),[("C",3)])]
[(fst x, sum [snd y | y <- (snd x) ]) | x <- list]
returns
[((1,1),10),((2,2),2),((3,3),3)]
New to Haskell, and trying to construct an [[(Int, Int)]] where each element is its corresponding grid position, constructed from another board [[a]]. Therefore a square [[a]] of side length 3 would create
[[(0, 0), (1, 0), (2, 0)]
,[(0, 1), (1, 1), (2, 1)]
,[(0, 2), (1, 2), (2, 2)]]
(eventually I'll be iterating over this with a map (map ...) into a function of type [[a]] -> (Int, Int) -> b to create a [[b]], so if I'm missing something massively easier, let me know!)
In Python I might do something like:
[[(x,y) for (x,_) in enumerate(board[y])] for (y,_) in enumerate(board)]
That is to say, I'd use the enumerate builtin to construct (index, element) tuples and throw away the element.
I know in Haskell I can do:
[[(x,y) | x <- [0..length (board!!y)-1]] | y <- [0..length board-1]]
but those sorts of constructions in Python (for foo in range(len(bar))) are a bit of an anti-pattern and heavily discouraged. Is that true in Haskell, as well?
If I were to write the Haskell like I'd write the Python, I'd do:
[[(x,y) | (x,_) <- zip [0..] (board!!y)] | (y,_) <- zip [0..] board]
Is that frowned upon?
Your final "write it like Python" suggestion is almost good, but you are unnecessarily throwing away the rows of the board, and then re-creating them with (!!). Writing it like this instead would be perfectly fine:
board :: [[Char]]
board = ["abc", "def", "ghi"]
board' :: [[(Int, Int)]]
board' = [[(x, y) | (x, _) <- zip [0..] row]
| (y, row) <- zip [0..] board]
Well usually the (!!) :: [a] -> Int -> a is not really a nice operator: it requires O(k) time to access the k-th element. For your small example that is of course not really an issue, but it can turn some algorithms from O(n) into O(n2).
Usually in Haskell, one aims to avoid it by writing clever algorithms that can iterate through the list, instead of obtaining a (random) index.
In Python you can rewrite your:
[[(x,y) for (x,_) in enumerate(board[y])] for (y,_) in enumerate(board)]
into:
[[(x,y) for (x,_) in enumerate(by)] for (y,by) in enumerate(board)]
and the equivalent in Haskell would be:
[ [ (x,y) | (x,_) <- zip [0..] by ] | (y,by) <- zip [0..] board ]
Or we can make the code cleaner by first introducing an enumerate :: (Enum a, Num a) => [b] -> [(a, b)] function in Haskell:
enumerate :: (Enum a, Num a) => [b] -> [(a, b)]
enumerate = zip [0..]
and then write:
[ [ (x,y) | (x,_) <- enumerate by ] | (y,by) <- enumerate board ]
Your aside seems to suggest you might be interested in the following function, sometimes called mapWithIndex (e.g., in containers) and sometimes called imap (in lens).
mapWithIndex :: (Int -> a -> b) -> [a] -> [b]
mapWithIndex f = go 0
where
go !_i [] = []
go i (x : xs) = f i x : go (i + 1) xs
So mapWithIndex (\i -> mapWithIndex (\j y -> (i,j,y))) will take a list of lists and annotate each element with its position. Of course, rather than annotating, you can perform an arbitrary calculation.
I have another question regarding generating lists of stuff from various sources.
UPDATED: Simplified the example
I have a list of variables
["a", "b", "c"]
and bool values
[False, True].
Now I want to have a list with all subsequences of the variables list crossed with the values list so for each entry the list of subsequences of the variables has, a set of pairs with each of the possible values.
For the lists above I'd get this (complete list for this scenario). As the empty list won't pair with the other list too well, I don't care whether it is part of the result list or not (can be added later easily).
[
[],
[("a", False)],
[("a", True)],
[("b", False)],
[("b", True)],
[("c", False)],
[("c", True)],
[("a", False), ("b", False)],
[("a", False), ("b", True)],
[("a", True), ("b", False)],
[("a", True), ("b", True)],
[("a", False), ("c", False)],
[("a", False), ("c", True)],
[("a", True), ("c", False)],
[("a", True), ("c", True)],
[("b", False), ("c", False)],
[("b", False), ("c", True)],
[("b", True), ("c", False)],
[("b", True), ("c", True)],
[("a", False), ("b", False), ("c", False)],
[("a", False), ("b", False), ("c", True)],
[("a", False), ("b", True), ("c", False)],
[("a", False), ("b", True), ("c", True)],
[("a", True), ("b", False), ("c", False)],
[("a", True), ("b", False), ("c", True)],
[("a", True), ("b", True), ("c", False)],
[("a", True), ("b", True), ("c", True)],
]
If it was permutations only, a call to permutations combined with a comprehension would suffice, but I have no idea how to get the list for the subseqences easily.
I could do with using the "call to permutations + comprehension"-approach on the lists with different sizes but that doesn't sound very elegant.
Is there a straightfoward solution to that?
import Control.Monad (forM)
import Data.List (subsequences)
solution :: [a] -> [b] -> [[(a, b)]]
solution variables values = do
sequence <- subsequences variables
forM sequence $ \variable -> do
value <- values
return (variable, value)
Proof that it works:
>>> mapM_ print $ solution ["a", "b", "c"] [False, True]
[]
[("a",False)]
[("a",True)]
[("b",False)]
[("b",True)]
[("a",False),("b",False)]
[("a",False),("b",True)]
[("a",True),("b",False)]
[("a",True),("b",True)]
[("c",False)]
[("c",True)]
[("a",False),("c",False)]
[("a",False),("c",True)]
[("a",True),("c",False)]
[("a",True),("c",True)]
[("b",False),("c",False)]
[("b",False),("c",True)]
[("b",True),("c",False)]
[("b",True),("c",True)]
[("a",False),("b",False),("c",False)]
[("a",False),("b",False),("c",True)]
[("a",False),("b",True),("c",False)]
[("a",False),("b",True),("c",True)]
[("a",True),("b",False),("c",False)]
[("a",True),("b",False),("c",True)]
[("a",True),("b",True),("c",False)]
[("a",True),("b",True),("c",True)]
solution :: [a] -> [b] -> [[(a, b)]]
solution variables values = do
as <- subsequences variables
bs <- forM as $ const values
zip as bs
And to demonstrate that it works:
Data.List Control.Monad Prelude> :{
Data.List Control.Monad Prelude| let solution :: [a] -> [b] -> [[(a, b)]]
Data.List Control.Monad Prelude| solution variables values = do
Data.List Control.Monad Prelude| as <- subsequences variables
Data.List Control.Monad Prelude| bs <- forM as $ const values
Data.List Control.Monad Prelude| return $ zip as bs
Data.List Control.Monad Prelude| :}
Data.List Control.Monad Prelude> solution [ "a", "b", "c" ] [ False, True ]
[[],[("a",False)],[("a",True)],[("b",False)],[("b",True)],[("a",False),("b",False)],[("a",False),("b",True)],[("a",True),("b",False)],[("a",True),("b",True)],[("c",False)],[("c",True)],[("a",False),("c",False)],[("a",False),("c",True)],[("a",True),("c",False)],[("a",True),("c",True)],[("b",False),("c",False)],[("b",False),("c",True)],[("b",True),("c",False)],[("b",True),("c",True)],[("a",False),("b",False),("c",False)],[("a",False),("b",False),("c",True)],[("a",False),("b",True),("c",False)],[("a",False),("b",True),("c",True)],[("a",True),("b",False),("c",False)],[("a",True),("b",False),("c",True)],[("a",True),("b",True),("c",False)],[("a",True),("b",True),("c",True)]]
Data.List Control.Monad Prelude> forM_ it print
[]
[("a",False)]
[("a",True)]
[("b",False)]
[("b",True)]
[("a",False),("b",False)]
[("a",False),("b",True)]
[("a",True),("b",False)]
[("a",True),("b",True)]
[("c",False)]
[("c",True)]
[("a",False),("c",False)]
[("a",False),("c",True)]
[("a",True),("c",False)]
[("a",True),("c",True)]
[("b",False),("c",False)]
[("b",False),("c",True)]
[("b",True),("c",False)]
[("b",True),("c",True)]
[("a",False),("b",False),("c",False)]
[("a",False),("b",False),("c",True)]
[("a",False),("b",True),("c",False)]
[("a",False),("b",True),("c",True)]
[("a",True),("b",False),("c",False)]
[("a",True),("b",False),("c",True)]
[("a",True),("b",True),("c",False)]
[("a",True),("b",True),("c",True)]
An easy solution to generate all subsequences of a given list (without thinking about performance) is:
subs :: [a] -> [[a]]
subs [] = [[]]
subs (x:xs) = subs xs ++ map (x:) (subs xs)
Actually there is no need to use monads here. The following might be a bit intimidating at first, but I will explain afterwards. Note: Mapping and folding helps the compiler make code faster.
solution :: [a] -> [b] -> [[(a, b)]]
solution variables values = foldr (<*>) [[]]
$ map (\variable -> id : map (\value -> (:) (variable, value) ) values)
$ variables
It needs Control.Applicative.
The idea is to have picking the subsequence and assigning all possible values as a single process. The function (\value -> (:) (variable, value) ) :: b -> [(a,b)]->[(a,b)] takes one value, makes a pair with a variable and produces a function appending this pair to a list of variable-value-pairs.
By mapping this over the list of all values, we get a list of functions map (\value -> (:) (variable, value) ) values :: [[(a,b)]->[(a,b)]]. The outer list brackets are for nondeterminism and the inner for the list of bindings.
We add a further option: Not assigning a value. This is done by id :: [(a,b)]->[(a,b)], which is added to the list of possibilities.
The next lambda-abstraction-and-map construction takes the different variables into account: We want to have a list of possible changes for every variable.
map (\variable -> (id : map (\value -> (:) (variable, value) ) values)) variables
has type [[[(a,b)]->[(a,b)]]] where the outer-most list is for variables that are to be bound, the middle layer for nondeterminism and the inner list for variables already bound.
Then comes the big finally: Folding! The fold works on the outer-most list layer (for every variable do something) and this level of list-ness disappears. The (<*>) combines all the nondeterminism, which was the middle layer of lists before and is the outer layer of the result. The inner layer is unaffected. The starting value of the fold is [[]]::[[(a,b)]].
If you get used to the Alternative interface for nondeterminism you might prefer
solution :: Alternative f => [a] -> f b -> f[(a, b)]
solution variables values = foldr (<*>) (pure [])
$ map (\variable -> pure id <|> pure (\value -> (:) (variable, value)) <*> values)
$ variables
because now the list operations (:) and map are for the list of variables while everything concerning nondeterminism is handled by the applicative/ alternative interface.