Haskell multiply Int and real number

丶灬走出姿态 提交于 2019-12-19 03:44:28

问题


I have

coefficient :: ???????
coefficient = 1.0

and

val :: Int

and I would like to do

result :: ???????
result val coefficient = val * coefficient

What type signatures and conversion functions do I need to do to make this work? What must I do on top of that if I want to have ability to generalize val to any kind of Num?

This:

coefficient = 1.0

val :: Int
val = 3

result :: Num a => a
result = coefficient * (fromIntegral val)

gives me this compiler warning:

Could not deduce (a ~ Double)
from the context (Num a)
  bound by the type signature for result :: Num a => a
  at Move.hs:17:1-41
  `a' is a rigid type variable bound by
      the type signature for result :: Num a => a at Move.hs:17:1
In the first argument of `(*)', namely `coefficient'
In the expression: coefficient * (fromIntegral val)
In an equation for `result':
    result = coefficient * (fromIntegral val)

I know thats not what I asked originally, I made some mistakes when sanitizing my code.

Now with a type for coefficient:

coefficient :: Num a => a
coefficient = 1.0

val :: Int
val = 3

result :: Num a => a
result = coefficient * (fromIntegral val)

the resulting error:

Could not deduce (Fractional a) arising from the literal `1.0'
from the context (Num a)
  bound by the type signature for coefficient :: Num a => a
  at Move.hs:12:1-17
Possible fix:
  add (Fractional a) to the context of
    the type signature for coefficient :: Num a => a
In the expression: 1.0
In an equation for `coefficient': coefficient = 1.0

回答1:


There is a function, fromIntegral, which will convert an integral number to any other numeric type. So you can do:

result :: (Integral n, Num m) => n -> m -> m
result val coefficient = fromIntegral val * coefficient

Or, in point-free style:

result = (*) . fromIntegral

Update about updated question(@Drew)

Consider this code:

coefficient :: (Num a) => a
coefficient = 1.0

This is invalid on it's own, as follows. Because 1.0 is a literal for a fractional number (not a whole integer), then GHC can only encode it as any type which is capable of representing fractional numbers (forall a. Fractional a => a). However, you have specified that it must be valid for any numeric type (forall a. Num a => a). Some numeric types (e.g. Integer) cannot represent fractional values, and are not instances of Fractional (rightly so), so this cannot typecheck. You can fix this as follows:

coefficient :: (Fractional a) => a
coefficient = 2.0

Here GHC can infer the type, and coefficient works fine. It is important to note, that Fractional is a subclass of Num, so everything that is a Fractional must also be a Num. If we look at the function in the first part of my answer, coefficient is only required to be a Num type (as we only use it with (*)), so we can use this definition of coefficient in place of that parameter. Your problem occurs for exactly the same reason.

result :: (Num a) => a
result = coefficient * fromIntegral val

Again, the result of this function must be of the same type as coefficient. As coefficient cannot be any Num type, but only a fractional type, we need to change this to:

result :: (Fractional a) => a
result = coefficient * fromIntegral val

And then that should typecheck. @singpolyma is right that your original error was partly to do with the monomorphism restriction, but you just needed to make the type signatures slightly more specific. If you want it to work with (Num a) => a, then coefficient must be a whole number (e.g. 1).

Update about GHCi (@Marcin)

For using this in GHCi, I would suggest letting GHCi infer the type. If in this case you type (in GHCi):

let result val coefficient = fromIntegral val * coefficient

Then GHCi will correctly infer the type of the result. You can ask GHCi what type it thinks something is using the ':t' command:

Prelude> :t result
result :: (Integral a1, Num a) => a1 -> a -> a

If you must have an explicit type signature you can do:

let result = (\val coefficient -> fromIntegral val * coefficient) :: (Integral a, Num b) => a -> b -> b

To try and have an explicit type, but GHCi will make this monomorphic:

Prelude> :t result
result :: Integer -> Integer -> Integer

Which we don't want (this is because the type annotation refers to the value of the lambda expression, not the declaration of result). I don't know how to get the explicit type to work here either, so maybe someone more knowledgeable than us can answer :P



来源:https://stackoverflow.com/questions/13358657/haskell-multiply-int-and-real-number

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!