Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a standard Haskell function with type: (Floating a, RealFrac b) => a -> b?

I need to call floor() on a value, which is only constrained to be of class Floating, but floor() requires RealFrac.

How can I do this?

I'm perfectly willing to call abs() before calling floor(), but this alone seems insufficient to solve my constraint conflict. And coerce complains that the two representations cannot be assumed equivalent, which isn't surprising.

It seems what I need is a function with type signature:

(Floating a, RealFrac b) => a -> b

And it seems (to me) perfectly legitimate to give some augmented version of abs() this signature. Alas, a Hoogle search on the above type signature left me empty handed.

Any thoughts?

Thanks.
:)

like image 759
dbanas Avatar asked Jun 14 '19 13:06

dbanas


People also ask

What are types in Haskell?

In Haskell, every statement is considered as a mathematical expression and the category of this expression is called as a Type. You can say that "Type" is the data type of the expression used at compile time. To learn more about the Type, we will use the ":t" command.

What is Haskell integral?

Haskell has two integral types, namely Int and Integer . Int is the type of limited-precision integers; this means that there is a smallest integer of type Int , namely minBound , and a greatest integer of type Int , namely maxBound .

What is EQ Haskell?

The Eq class defines equality ( == ) and inequality ( /= ). All the basic datatypes exported by the Prelude are instances of Eq , and Eq may be derived for any datatype whose constituents are also instances of Eq . The Haskell Report defines no laws for Eq .

What is show in Haskell?

The shows functions return a function that prepends the output String to an existing String . This allows constant-time concatenation of results using function composition.


1 Answers

Consider the following instance of Floating:

import Control.Applicative

instance (Num a) => Num (e -> a) where
    (+) = liftA2 (+)
    (*) = liftA2 (*)
    (-) = liftA2 (-)
    abs = fmap abs
    signum = fmap signum
    negate = fmap negate
    fromInteger = pure . fromInteger

instance (Fractional a) => Fractional (e -> a) where
    fromRational = pure . fromRational
    recip = fmap recip
    (/) = liftA2 (/)

instance (Floating a) => Floating (e -> a) where
    pi = pure pi
    exp = fmap exp
    log = fmap log
    sin = fmap sin
    cos = fmap cos
    asin = fmap asin
    acos = fmap acos
    atan = fmap atan
    sinh = fmap sinh
    cosh = fmap cosh
    asinh = fmap asinh
    acosh = fmap acosh
    atanh = fmap atanh

Demo:

main :: IO ()
main = do
    print (sqrt sqrt 81)
    let f = sin^2 + cos^2
    print (f 42)

(This outputs 3.0000000000000004 and 1.0.)

This makes functions an instance of Floating, but the code generalizes to all types that are Monads or Applicatives.

Your hypothetical function would need to have the type

(Floating a, RealFrac b) => (e -> a) -> b

in this instance. We could set a and b to Double:

(e -> Double) -> Double

How do you implement that operation?

Remember that I said this generalizes to all Applicatives? We can replace e -> by IO in the above instances. Then the type you end up with gets even worse:

IO Double -> Double

The problem is that Floating can be anything that supports e.g. exp or sin operations (which could be purely symbolic operations e.g. on a syntax tree) while RealFrac must be a number (or something convertible to a number).

like image 50
melpomene Avatar answered Nov 15 '22 03:11

melpomene