Reputation: 90
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?
Upvotes: 0
Views: 121
Reputation: 55059
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.
Upvotes: 4