Alright, So I'm new to Haskell and I want to write a program where I take two lists and find the similarity (number of common items/number of items) between them.
This is What I have so far:
fun2 :: [Int]->[Int]->Float
fun2 [] xs2 = 0
fun2 xs1 xs2 = if head xs1 == head xs2 then (1/length xs2) + fun2 tail xs1 xs2
else if head xs1 /= head xs2 then fun2 xs1 tail xs2
else fun2 tail xs1 xs2
main = fun2 [1,2,3,4] [3,4,5,6]
So let me explain what I'm trying to do, I defined my function to take two lists of integers and output a float (the similarity percentage). then I write my function, the base case is when the first list is empty, while the function will compare each element of the first list with each element of the second one, and if it finds a match it will add 1 then divide by the size to get the percentage.
However, when I run this code I get a lot of errors:
main.hs:4:45: error:
• Couldn't match expected type ‘Float’ with actual type ‘Int’
• In the expression: (1 / length xs2) + fun2 tail xs1 xs2
In the expression:
if head xs1 == head xs2 then
(1 / length xs2) + fun2 tail xs1 xs2
else
if head xs1 /= head xs2 then
fun2 xs1 tail xs2
else
fun2 tail xs1 xs2
In an equation for ‘fun2’:
fun2 xs1 xs2
= if head xs1 == head xs2 then
(1 / length xs2) + fun2 tail xs1 xs2
else
if head xs1 /= head xs2 then
fun2 xs1 tail xs2
else
fun2 tail xs1 xs2
main.hs:4:62: error:
• Couldn't match expected type ‘[Int] -> Int’
with actual type ‘Float’
• The function ‘fun2’ is applied to three arguments,
but its type ‘[Int] -> [Int] -> Float’ has only two
In the second argument of ‘(+)’, namely ‘fun2 tail xs1 xs2’
In the expression: (1 / length xs2) + fun2 tail xs1 xs2
main.hs:4:67: error:
• Couldn't match expected type ‘[Int]’
with actual type ‘[a0] -> [a0]’
• Probable cause: ‘tail’ is applied to too few arguments
In the first argument of ‘fun2’, namely ‘tail’
In the second argument of ‘(+)’, namely ‘fun2 tail xs1 xs2’
In the expression: (1 / length xs2) + fun2 tail xs1 xs2
main.hs:5:39: error:
• Couldn't match expected type ‘[Int] -> Float’
with actual type ‘Float’
• The function ‘fun2’ is applied to three arguments,
but its type ‘[Int] -> [Int] -> Float’ has only two
In the expression: fun2 xs1 tail xs2
In the expression:
if head xs1 /= head xs2 then
fun2 xs1 tail xs2
else
fun2 tail xs1 xs2
main.hs:5:48: error:
• Couldn't match expected type ‘[Int]’
with actual type ‘[a1] -> [a1]’
• Probable cause: ‘tail’ is applied to too few arguments
In the second argument of ‘fun2’, namely ‘tail’
In the expression: fun2 xs1 tail xs2
In the expression:
if head xs1 /= head xs2 then
fun2 xs1 tail xs2
else
fun2 tail xs1 xs2
main.hs:6:10: error:
• Couldn't match expected type ‘[Int] -> Float’
with actual type ‘Float’
• The function ‘fun2’ is applied to three arguments,
but its type ‘[Int] -> [Int] -> Float’ has only two
In the expression: fun2 tail xs1 xs2
In the expression:
if head xs1 /= head xs2 then
fun2 xs1 tail xs2
else
fun2 tail xs1 xs2
main.hs:6:15: error:
• Couldn't match expected type ‘[Int]’
with actual type ‘[a2] -> [a2]’
• Probable cause: ‘tail’ is applied to too few arguments
In the first argument of ‘fun2’, namely ‘tail’
In the expression: fun2 tail xs1 xs2
In the expression:
if head xs1 /= head xs2 then
fun2 xs1 tail xs2
else
fun2 tail xs1 xs2
main.hs:8:1: error:
• Couldn't match expected type ‘IO t0’ with actual type ‘Float’
• In the expression: main
When checking the type of the IO action ‘main’
So Could you please tell me what I'm doing wrong here?
main.hs:4:45: error:
• Couldn't match expected type ‘Float’ with actual type ‘Int’
• In the expression: (1 / length xs2) + fun2 tail xs1 xs2
…
length returns an Int.
For example, in GHCi:
> :type length
length :: Foldable t => t a -> Int
> :set -XTypeApplications
> :type length #[]
length #[] :: [a] -> Int
(Note that I write > to indicate the prompt. You can set your prompt to the same using :set prompt "> ", and :set prompt-cont "| " for multi-line input.)
While (/) works on types that are in the set Fractional:
> :type (/)
(/) :: Fractional a => a -> a -> a
> :info Fractional
class Num a => Fractional a where
(/) :: a -> a -> a
recip :: a -> a
fromRational :: Rational -> a
{-# MINIMAL fromRational, (recip | (/)) #-}
-- Defined in ‘GHC.Real’
instance forall a k (b :: k).
Fractional a =>
Fractional (Const a b)
-- Defined in ‘Data.Functor.Const’
instance Fractional Float -- Defined in ‘GHC.Float’
instance Fractional Double -- Defined in ‘GHC.Float’
Int is not in Fractional:
> :set -XFlexibleContexts
> () :: (Fractional Int) => ()
<interactive>:…:1: error:
• No instance for (Fractional Int)
arising from an expression type signature
• In the expression: () :: (Fractional Int) => ()
In an equation for ‘it’: it = () :: (Fractional Int) => ()
So you need to convert the result of length from an Int to a Float with fromIntegral. This function can return any type that is in Num, and note in the output of :info Fractional above that class Num a => Fractional a means that Fractional is a subset of Num.
> :type fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
> fromIntegral (length "abc") :: Float
3.0
In other words, you can write 1 / fromIntegral (length xs2) instead. Note the parentheses! That leads us to the next several error messages:
main.hs:4:62: error:
• Couldn't match expected type ‘[Int] -> Int’
with actual type ‘Float’
• The function ‘fun2’ is applied to three arguments,
but its type ‘[Int] -> [Int] -> Float’ has only two
In the second argument of ‘(+)’, namely ‘fun2 tail xs1 xs2’
…
When you write fun2 tail xs1 xs2, that means “apply fun2 to three arguments: tail, xs1, and xs2”. You wanted to pass the result of tail xs1 as a single argument, so you need parentheses to group them together, i.e., fun2 (tail xs1) xs2. This is also the cause of the next error:
main.hs:4:67: error:
• Couldn't match expected type ‘[Int]’
with actual type ‘[a0] -> [a0]’
• Probable cause: ‘tail’ is applied to too few arguments
In the first argument of ‘fun2’, namely ‘tail’
In the second argument of ‘(+)’, namely ‘fun2 tail xs1 xs2’
…
tail is a function of type [a] -> [a], but you are passing it as the first argument of fun2, whose first parameter is a value of type [Int]. The same error message repeats due to the same mistake in the other calls of fun2.
For example, the next expression should read fun2 xs1 (tail xs2). The next error also has the same root cause, and additionally gives you a good hint about how to solve it:
main.hs:6:10: error:
• Couldn't match expected type ‘[Int] -> Float’
with actual type ‘Float’
• The function ‘fun2’ is applied to three arguments,
but its type ‘[Int] -> [Int] -> Float’ has only two
In the expression: fun2 tail xs1 xs2
…
Finally, main must be an IO action, conventionally IO (). It may return a result of any type, that is, you may use IO t for any type t, and the result value will simply be discarded. However, you are currently passing a Float, the result of calling fun2, hence the mismatch:
main.hs:8:1: error:
• Couldn't match expected type ‘IO t0’ with actual type ‘Float’
• In the expression: main
When checking the type of the IO action ‘main’
The solution is to use an IO action such as print (fun2 [1,2,3,4] [3,4,5,6]), which is equivalent to putStrLn (show (fun2 [1,2,3,4] [3,4,5,6])), both of which will convert a Float to a String using the debug-dump class Show, and return an IO action which will print the result to standard output when main is executed.
GHC’s error messages aren’t always perfect, but all of these error messages fortunately contained enough information to solve your problem. You just need more practice reading them and understanding what they’re saying and how to proceed.
Related
I got a problem that needs to turn a list of tuples into a flattened list for example:
[(1,2), (3,4), (5,6)] can be turned into [1,2,3,4,5,6]
I have tried to write a function like this:
fun helper2(nil,b) = []
| helper2(a,nil) = []
| helper2(a::l1,b::l2) =l1::l2
fun flatten2 [] = []
| flatten2 ((a,b)::tl) = helper2(a,b)
It shows:
val flatten2 = fn : ('a list * 'a list list) list -> 'a list list
And when I tried to run it using command flatten2[(1,2),(3,4),(5,6)];
It will give me the following error message:
stdIn:1.2-1.29 Error: operator and operand do not agree [overload conflict]
operator domain: ('Z list * 'Z list list) list
operand: ([int ty] * [int ty]) list
in expression:
flatten2 ((1,2) :: (3,4) :: (<exp>,<exp>) :: nil)
My questions are:
Why SML see the a and b values as lists, not just simply a and b
How can I revise my code so SML can see a and b as 'a and 'b not lists
How to make this code work the way it should be?
Thanks
First question: As to why the type comes out as ('a list * 'a list list) it's because type inference is looking at this part of the code:
| helper2(a::l1,b::l2) =l1::l2
^^
here
Keep in mind that the type of the "cons" (::) operator is 'a -> 'a list -> 'a list, it is gluing a single element onto a list of that same type of element. So SML has concluded that whatever l1 and l2 are, the relationship is that l2 is a list of whatever l1 is.
fun helper2(nil,b) = []
Says that a must be a list because nil has type 'a list. Therefore, l2 has to be a list of lists (of some type 'a).
Question 2 and 3: I'm not quite sure how to correct the code as it is written. I'd probably write something like this:
fun helper2 [] accum = List.rev accum
| helper2 ((a,b)::tl) accum = helper2 tl (b :: a :: accum);
fun flatten2 list = helper2 list [];
helper2 does all of the dirty work. If the input list is empty then we're all done and we can return the reversed accumulator that we've been building up. The second case is where we actually add things to the accumulator. We pattern match on the head and the tail of the list. This pattern match means that the input has type ('a * 'a) list (a list of tuples where both elements are the same type). In the head, we have a tuple and we name the first and second element a and b, respectively. We prepend a then b onto the accumulator and recursively call helper2 on the tail of the list. Eventually, we'll chew through all the elements in the list and then we'll be left with just the accumulator -- which, recall, has all the elements but in the reverse order. Calling List.rev reverses the accumulator and that's our answer.
And when I load and run it I get this:
- flatten2 [(1,2), (3,4), (5,6)];
val it = [1,2,3,4,5,6] : int list
Why SML see the a and b values as lists, not just simply a and b
Chris already answered this in-depth.
You're passing a as the first argument to helper2, which expects a list as its first argument. And you're passing b as the second argument to helper2, which uses its second argument, b::l2, also a list, as the tail of a list where a is the head. So b must be a list of those lists.
This doesn't make any sense, and is most likely a consequence of confusing syntax: You are passing in what you think of single elements a and b in flatten2, but when you deal with them in helper2 they're now lists where the heads are called a and b. Those are not the same a and b.
How can I revise my code so SML can see a and b as 'a and 'b not lists
You could ditch the helper function to begin with:
fun flatten2 [] = []
| flatten2 ((a,b)::pairs) = a :: b :: flatten2 pairs
The purpose of having a helper function is so that it can accumulate the result during recursion, because this version of flatten2 uses a lot of stack space. It can do this with an extra argument so that flatten2 doesn't need to mention it:
This is the version Chris made.
How to make this code work the way it should be?
You can make this code in a lot of ways. Two ways using explicit recursion were mentioned.
Here are some alternatives using higher-order functions:
(* Equivalent to my first version *)
fun flatten2 pairs =
foldr (fn ((a,b), acc) => a :: b :: acc) [] pairs
(* Equivalent to Chris'es version *)
fun flatten2 pairs =
rev (foldl (fn ((a,b), acc) => b :: a :: acc) [] pairs)
(* Yet another alternative *)
fun concatMap f xs =
List.concat (List.map f xs)
fun flatten2 pairs =
concatMap (fn (a,b) => [a,b]) pairs
Forgive my newness to OCaml, but I have a very simple function where I'm returning the intersection of two lists, but only when the element is in both lists at the same time. On the third line, I'm told "This expression has type 'a but an expression was expected of type 'a list", but isn't that a list I'm outputting?
let rec intersection (l1 : 'a list) (l2 : 'a list) : 'a list = match l1,l2 with
| [],[] -> [] (* empty lists *)
| [h1::t1], [h2::t2] -> (* non-empty lists *)
if h1 = h2 (* if both elements are the same *)
then h1 :: intersection(t1,t2) (* include in intersection response *)
else intersection(t1, t2) (* else ignore it and check the remaining elements *)
The expression a :: b is a list whose head is a and whose tail is b. So then the expression [a :: b] is a list of lists. Very likely your patterns should be h1 :: t1 and h2 :: t2.
It would be much easier to help if you post the entire function as #PieOhPah points out.
Update
There are at least two errors in your code. If I compile your code as given above I see this:
File "a1.ml", line 5, characters 13-15:
Error: This expression has type 'a but an expression was expected of type
'a list
The type variable 'a occurs inside 'a list
If I change your pattern from [h1 :: t1], [h2 :: t2] to h1 :: t1, h2 :: t2, I see this:
File "a2.ml", line 5, characters 31-38:
Error: This expression has type 'b * 'c
but an expression was expected of type 'a list
This second error happens because your recursive calls to intersection are passing tuples intersection (a, b). But intersection is defined in curried form, i.e., it takes separate arguments intersection a b. This is what #PieOhPah is pointing out.
If I make both changes I don't see any further type errors. There are other errors, but they aren't type errors.
I have a question about head, tail, init and last.
The following works in GHCi:
Prelude Data.List Data.Char> let n = [1..10] in (head n : tail n)
[1,2,3,4,5,6,7,8,9,10]
As expected, I get the whole list. So this should work for init and last too,
right?
Prelude Data.List Data.Char> let n = [1..10] in (init n : last n)
<interactive>:39:1:
Non type-variable argument in the constraint: Enum [[a]]
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall a. (Enum a, Enum [[a]], Num a, Num [[a]]) => [[a]]
If I look at the type signatures for the functions, then head and last
look the same -- they both return an element. Also init and tail look
the same, because they both return lists.
Prelude Data.List Data.Char> :info head
head :: [a] -> a -- Defined in ‘GHC.List’
Prelude Data.List Data.Char> :info tail
tail :: [a] -> [a] -- Defined in ‘GHC.List’
Prelude Data.List Data.Char> :info init
init :: [a] -> [a] -- Defined in ‘GHC.List’
Prelude Data.List Data.Char> :info last
last :: [a] -> a -- Defined in ‘GHC.List’
So what does Non type-variable argument in the constraint: Enum [[a]] mean?
If I do init n or last n without the construction of a new list, I get
[1..9] and 10.
Ahh snap, : takes an element and the rest like in x:xs, not a list and the last element, like in xs:x.
Prelude Data.List Data.Char> :info :
data [] a = ... | a : [a] >·-- Defined in ‘GHC.Types’
infixr 5 :
data [] a = ... | a : [a] >·-- Defined in ‘GHC.Types’
infixr 5 :
I still would like to know how you understand GHCi error messages and I have to wait 2 days to accept my own answer anyway.
Edit: I get that x and xs are only variable names chosen by convention, and (xs:_) would match the head but is unconventionally/confusingly named.
Edit 2: I upvoted and accepted Daniel Wagner's answer, because he explained the error message step by step. Really nice! Thank you!
It is true that head/last and tail/init have identical types. So if you had simply swapped out last for head and init for tail, you would have had no problem:
> let n = [1..10] in last n : init n
[10,1,2,3,4,5,6,7,8,9]
But you didn't. You did both that swap and another: you changed the order of arguments to :. It so happens that : doesn't take two arguments of the same type:
> :t (:)
(:) :: a -> [a] -> [a]
So this last swap is not okay! In fact, if you give n a slightly more specific type signature, ghci will give a better error:
> let n :: [Integer]; n = [1..10] in init n : last n
<interactive>:1:50:
Couldn't match type ‘Integer’ with ‘[[Integer]]’
Expected type: [[[Integer]]]
Actual type: [Integer]
In the first argument of ‘last’, namely ‘n’
In the second argument of ‘(:)’, namely ‘last n’
This error is still not 100% clear, but I think with a bit of puzzling you can see what it's complaining about: since init n :: [Integer], and (:) :: [Integer] -> [[Integer]] -> [[Integer]], it's expecting last n :: [[Integer]] and therefore n :: [[[Integer]]]. But you explicitly said n :: [Integer], a conflict.
Now, what about the error it actually gave you in your case? Well, the clue is in the type of [1..10]:
> :t [1..10]
[1..10] :: (Enum t, Num t) => [t]
Notice that [1..10] is polymorphic. Moreover, it is used twice in your expression, and so it can be given separate monomorphic types in the two uses. So [1..10] is instantiated with two different types in the sequel!
Now I think you can start to see where the error you got comes in. It's trying to find a type a for which:
Enum a -- this is needed to do the .. part of init [1..10]
Num a -- this is needed to do the 1 and 10 parts of init [1..10]
Enum [[a]] -- if init n :: a, then to have init n : last n be well-typed, we must have last n :: [a] and hence the second occurrence of n must have n :: [[a]]; then the Enum constraint is needed for the .. part of last [1..10]
Num [[a]] -- by similar reasoning, this is needed to do the 1 and 10 parts of last [1..10]
But these constraints together are hard to satisfy -- certainly there's no instance of Enum and Num for lists in scope in the Prelude or Data.List. So it complains.
In larger programs there is more type information (implicit and explicit) allowing the compiler to do a better job inferring types than in one-line snippets provided to GHCi. As a result, the errors you see in GHCi are not representative of what is typically observed when building a full program.
That said, it's no excuse for the awfulness that is the error you posted:
Prelude> let n = [1..10] in (init n : last n)
<interactive>:8:1:
Non type-variable argument in the constraint: Enum [[a]]
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall a. (Enum a, Enum [[a]], Num a, Num [[a]]) => [[a]]
So there is a lot of polymorphism involved in your own line. You have lists of Num a (Num a => [a]) where the type variable a must itself be alist since you've used : last n where last n :: [_] ~ a. So this, combined with the fact that .. in list comprehension implies an enum, is how we got to the horrible message.
Let's look at the simpler case where we've told GHCi our list is of type [Int]:
Prelude> let n = [1..10] :: [Int] in (init n : last n)
<interactive>:7:44:
Couldn't match type ‘Int’ with ‘[[Int]]’
Expected type: [[[Int]]]
Actual type: [Int]
In the first argument of ‘last’, namely ‘n’
In the second argument of ‘(:)’, namely ‘last n’
Ahh, much better. Column 44 is the n in last n. It says that last n :: Int. So the type of init n : when init n :: [Int] means our cons function type is (:) :: [Int] -> [[Int]] -> [[Int]]. But wait! [[Int]] needed for the argument of init n : does not match Int provided by last n!
I have to write a function to remove elements from a lazy list. Indexes of elements to be removed are in list xs.
I don't know where I should sort xs? When I try in this way I get "Error: This expression has type...".
type 'a llist = LNil | LCons of 'a * (unit -> 'a llist)
let rec remove xs ll =
let rec helper =
function
| (_, i, LNil) -> LNil
| (h::t, i, LCons(x, xf)) -> if h = i then helper (t, (i + 1), xf())
else LCons(x, fun() -> helper (h::t, (i + 1), xf()))
| ([], i, LCons(x, xf)) -> LCons(x, xf)
in helper (List.sort xs, 0, ll);;
List.sort from OCaml standard library has the following interface:
val sort : ('a -> 'a -> int) -> 'a list -> 'a list
That means, that it accepts a function and a list. The function should have type 'a -> 'a -> int, i.e., it takes two elements of arbitrary type 'a and returns a value of type int that defines the mutual order of the arguments. The second argument is a list of values, where each value has type 'a. A usual invocation of the sort function is:
List.sort compare [2;1;4;3]
So with this knowledge we can tackle with your program:
You invoke List.sort on xs this has two consequences:
type inference system concludes that xs is a function of type 'a -> 'a -> int.
The result of List.sort xs is a function of type 'a list -> 'a list. This is because, List.sort requires two arguments, but you provided only one.
(List.sort xs) is a function that takes a list & returns a list - as xs is supposed to be the function that sorts the element of the list; you miss to pass a list as arg.
...whereas a list is expected.
I'm trying to implement flatten : 'a list list -> 'a list list in SML.
I thought this should be relatively straight forward with higher order functions. My implementation is
val flatten = List.reduce (op #) []
However I'm getting a bizarre error message: "append.sml:1.6-1.36 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)". Thus when I try to flatten an int list list I get a type error:
:> flatten [[1,2],[3]];
stdIn:2.1-2.20 Error: operator and operand don't agree [literal]
operator domain: ?.X1 list list
operand: int list list
in expression:
flatten ((1 :: 2 :: nil) :: (3 :: nil) :: nil)
As the error message hints, you ran into the value restriction -- see here for an explanation. The solution is very simple: just "eta-expand" your definition, i.e., make the parameter explicit instead of relying on partial application:
fun flatten xs = List.reduce op# [] xs