Haskell multiply Int and real number

前端 未结 1 1557
离开以前
离开以前 2021-01-06 04:23

I have

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

and

val :: Int

and I would like to do

r         


        
1条回答
  •  旧时难觅i
    2021-01-06 04:42

    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

    0 讨论(0)
提交回复
热议问题