Polyvarian generalized amount

This answer demonstrates a multivariate function that summarizes its arguments:

class SumRes r where sumOf :: Integer -> r instance SumRes Integer where sumOf = id instance (Integral a, SumRes r) => SumRes (a -> r) where sumOf x = sumOf . (x +) . toInteger 

I created a generalized version of this function for all Num members:

 class (Num n) => MySumType nr where mySum :: n -> r instance (Num n) => MySumType nn where mySum x = x instance (Num n, MySumType nr) => MySumType n (n->r) where mySum x = mySum . (x +) 

However, this only works with calls like mySum (1::Int) (3::Int) (2::Int) :: Int . Without a type specifier for arguments, I get this error:

There is no instance for (MySumType n0 Float) resulting from the use of `mySum '

Possible fix: add an instance declaration for (MySumType n0 Float)

In expression: mySum 1.0 :: Float

In the equation for `it ': it = mySum 1.0 :: Float

What causes this problem and how can I fix it? I suspect this is due to the type of integer literals Num a => a . Also, is there an equivalent function above that doesn't rely on extensions? The ones that were used above are several classes of parameter types and flexible instances.

+6
source share
1 answer

I have not seen a convincing use case for multivarian functions in haskell, but so far this has not been solved using a list or a similar data structure. Therefore, if you think that you have one beyond the limits of novelty, the reason I played with them, I would be interested to know what it is. There are enough examples below, some of which I should have thought when writing the comment, that I canceled my expression.

 {-# language MultiParamTypeClasses #-} {-# language FlexibleInstances #-} {-# language TypeFamilies #-} {-# language IncoherentInstances #-} class (Num n) => MySumType nr where mySum :: n -> r instance (Num n, m~n) => MySumType nm where mySum x = x instance (Num n, MySumType nr, n~m) => MySumType n (m->r) where mySum x = mySum . (x +) 

Then after uploading the file to ghci:

 > mySum 1 2 4 5 6 7 :: Int 25 > mySum 1.1 2 4.6 5 6.9 7 :: Double 26.6 

Type inference can also be your friend in some cases, allowing you to discard the final type annotation, as in the following far-fetched case:

 > replicate (mySum 1 2 3 4) 6 [6,6,6,6,6,6,6,6,6,6] 

Regarding

Also, is there an equivalent function above that doesn't rely on extensions?

I think you're out of luck. I would like to point out that if you have no reason to leave the GHC or stay with Haskell98 or Haskell2010, you will not harm you or cause compatibility problems, as most people seem to be in GHC anyway.

Edit: additional explanation

Let's start by explaining the difference between simpler instances. I will add postfix 2 to some of the implementation names that I have provided.

 instance (Num n) => MySumType nn where mySum x = x 

If you combine this with a class declaration:

 class (Num n) => MySumType nr where mySum :: n -> r 

mySum has a signature like mySum :: (Num n) => n -> n . That n -> n says function 1 arity, which takes type n , creates n and n has class Num.

When using this mySum I must indicate what I give it and what it produces.

 mySum 1 :: Int mySum (1 :: Int) 

both will give errors only when specifying the type of input and output, will it give the result:

 mySum (1 :: Int) :: Int ^ ^ | specify output type specify input type 

gives the result (1 in this case). This is because you provided an instance for n -> n , but you can add an instance for n -> m later, for example Int -> Double , as shown below:

 instance MySumType Int Double where mySum x = 2 * fromIntegral x > mySum (1::Int) :: Int 1 > mySum (1::Int) :: Double 2.0 

All of these instances correspond to a very narrow range of all possible types of arity functions.

Now consider the modified version

 instance (Num n, m~n) => MySumType nm where mySum x = x 

mySum here has a signature of type mySum :: (Num n, m~n) => n -> m signature of this type for all 1 arity functions that take type n and produce type m , where n has class Num and m is equal to n . Note that this started by matching all 1 functions with arity, n -> m , any n for any m , and then placing contests on it.

Now you can do:

 > mySum2 (1::Int) 1 > mySum2 1 :: Int 1 

Once input is specified, the output is also indicated. Other explanations 1 , 2 .

This does not stop us from specific, more specific instances, such as Int -> Double , as before:

 instance MySumType Int Double where mySum x = 2 * fromIntegral x > mySum2 1 :: Int 1 > mySum2 1 :: Double 1.0 > mySum2 (1 :: Int) :: Double 2.0 

Only the last mySum2 disables the Int -> Double instance. This is an IncoherentInstances property, and I think I will leave it with another stackoverflow question to answer the role that IncoherentInstances plays.

+5
source

Source: https://habr.com/ru/post/943993/


All Articles