Getting the value of type Integral a => [a] from the value of Integral a => ([a], [a], [a])

So, I play with this:

factors :: Integral a => a -> [a] factors n = filter (\d -> n `rem` d == 0) . takeWhile (\d -> d*d <= n) $ [ 1 .. ] abundants_perfects_deficients :: Integral a => ([a],[a],[a]) abundants_perfects_deficients = foldr switch ([],[],[]) [1..] where switch :: Integral a => a -> ([a],[a],[a]) -> ([a],[a],[a]) switch n (as,ps,ds) = let t = sum (factors n) in if t < n then (as,ps,n:ds) else if t == n then (as,n:ps,ds) else (n:as,ps,ds) 

And while I have abundants_perfects_deficients , I would prefer to have three values: abundants , perfects and deficients all of the type Integral a -> [a] .

One thing that doesn't work:

 abundants,perfects,deficients :: Integral a => [a] (abundants,perfects,deficients) = abundants_perfects_deficients 

Since this limits three to all, they must be the same a .

I tried to do something one by one, so they will not mutually limit, but this also did not work:

 perfects :: Integral a => [a] (_,perfects,_) = abundants_perfects_deficients 

Because the compiler could not figure out how to convert a value of type forall a. Integral a => ([a],[a],[a]) forall a. Integral a => ([a],[a],[a]) into type (t1, forall a. Integral a => [a], t2) .

Which seems complicated enough.

Now I know that I can implement them separately (just perfects = filter isPerfect [1..] ) or restrict them to the same type ( (abundants,perfects,deficients) = abundants_perfects_deficients works fine if abundants,perfects,deficients :: [Integer] ), but

  • I like to use general information to create all three
  • I want to not just be limited to Integer s

ideas?


Change Excitingly it works:

 abundants :: Integral a => [a] abundants = f as where as :: [Integer] (as,_,_) = abundants_perfects_deficients f :: Integral a => [Integer] -> [a] f = map fromInteger 

But this is not so:

 abundants_perfects_deficients' :: (Integral a,Integral p, Integral d) => ([a],[p],[d]) abundants_perfects_deficients' = (f as, f ps, f ds) where as,ps,ds :: [Integer] (as,ps,ds) = abundants_perfects_deficients f :: Integral a => [Integer] -> [a] f = map fromInteger abundants,perfects,deficients :: (Integral a) => [a] (abundants,perfects,deficients) = abundants_perfects_deficients' 

I have no idea why.

+6
source share
4 answers

This refers to what polymorphic types really mean, which is a little more complicated than how they first appear.

At this point, it is probably easier to switch modes of thinking and look at the quantifier as a form of lambda abstraction: Type ∀ a. [a] ∀ a. [a] , therefore, is a function that takes one type argument, and returns a list of things that type. Class restrictions, such as Integral a , can be thought of as additional arguments (in particular, an instance dictionary) that are implicitly provided when the GHC finds values ​​for you.

To emphasize this point, I'm going to write quantifiers as /\ a -> to mimic the lambda syntax, and write class constraints as regular arguments.

The abundants_perfects_deficients type written in this way is /\a -> Integral a -> ([a],[a],[a]) , and your initial attempt failed mainly because you tried to match the pattern by function result with two arguments . In many cases, the GHC automatically shuffles these implicit arguments to do something differently, but here it’s clear that it isn’t - to get any result from abundants_perfects_deficients you first need to apply it to both arguments, getting a monomorphic result, which then snapped using a template. Even if the template only binds one value and the rest _ , the GHC still needs to enter authentication of the template itself, so although it seems that additional arguments can be unloaded into a single linked identifier, this fails for the same reason as snapping all three at the same time.

To associate the three polymorphic values ​​with the pattern, you will need additional arguments inside, instead, providing richants_perfects_deficients type type (/\a -> Integral a -> [a], /\a -> Integral a -> [a], /\a -> Integral a -> [a]) . This requires the ImpredicativeTypes extension , which has some checkered past and which I still fear.

Much of what touches you is that the GHC is not smart enough to figure out the “obvious” things, such as the floating implicit type and constraint arguments, based only on use in a specific part of the binding. Given how much magic he already does behind the scenes, that doesn't bother me too much.:]

The simplest solution is to simply link all three separately, using the select function to extract individual elements. This suggests that the binding at the top level is polymorphic, with implicit arguments that it receives implicitly passed along with abundants_perfects_deficients , and the projection function simply discards the other three after matching the (now monomorphic) pattern.

+7
source
 abundants,perfects,deficients :: Integral a => [a] (abundants,perfects,deficients) = abundants_perfects_deficients 

Try:

 fst3 (a,_,_) = a snd3 (_,a,_) = a thd3 (_,_,a) = a abundants,perfects,deficients :: Integral a => [a] abundants = fst3 . abundants_perfects_deficients perfects = snd3 . abundants_perfects_deficients deficients = thd3 . abundants_perfects_deficients 
+3
source

fromIntegral may be useful:

 Prelude> :t fromIntegral fromIntegral :: (Num b, Integral a) => a -> b 
+1
source

Probably a bit offtopic, but anyway.

Your factors function is incorrect (try calculating factors 28 ;)

Here's a different approach to the problem:

 classifieds = map (\n -> (n, compare n (sum $ factors n))) [1..] perfects = map fst $ filter ((== EQ) . snd) classifieds abundants = map fst $ filter ((== GT) . snd) classifieds deficients = map fst $ filter ((== LT) . snd) classifieds 
+1
source

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


All Articles