It is possible to generalize any functions in haskell

Is there a function in haskell that generalizes both functions possibly?

For example, I imagine a function like this:

generalizedFunc :: SOMETHING m => b -> (a -> b) -> m a -> b
generalizedFunc valForError f value = ...

Working with it in ghci will look like this:

> generalizedFunc "bye" (\_ -> "hello") (Just 3)
"hello"
> generalizedFunc "bye" (\_ -> "hello") Nothing
"bye"
> generalizedFunc "bye" (\_ -> "hello") (Right 3)
"hello"
> generalizedFunc "bye" (\_ -> "hello") (Left "error")
"bye"

Note: Tom Ellis points out well that this is not a generalization of Either, but rather a specialization.

+4
source share
2 answers

Yes. What you are looking for Data.Foldable. It generalizes foldr(for lists) to any type of algebraic data:

Data.List.foldr     :: (a -> b -> b) -> b     ->   []       a -> b
maybe               :: b -> (a -> b)          ->   Maybe    a -> b
either              :: (a -> c) -> (b -> c)   ->   Either a b -> c
---
Data.Foldable.foldr :: Foldable t
                    => (a -> b -> b) -> b     ->   t        a -> b

Your code will change from generalizedFunc "bye" (\_ -> "hello")to foldr (\_ _ -> "hello") "bye". Make sure you tell the compiler what you mean foldrby Data.Foldable; see module documentation.

, Foldable (Either a) GHC, .

+5

, , , .

, generic-church. . , -

{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Data.Church

data Nat = Z | S Nat

instance ChurchRep Nat

, Nat , Foldable.

GHCi -

*> (toChurch Z) 'a' (const 'b')
  'a'
*> (toChurch $ S Z) 'a' (const 'b')
  'b'

foldr

*> fromChurch (\a b -> a) :: Nat
  Z
*> fromChurch (a b -> b Z) :: Nat
  S Z

catamorphisms/folds , generic-church ( Real Soon Now). , , , Nat

type Nat' = forall c. c -> (Nat -> c) -> c

, generalFunc

generalFunc , maybe. toChurchP, generic-church-0.2, 5 , . , cabal update:)

{-# LANGUAGE DeriveGeneric, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, ScopedTypeVariables #-}
module So where
import Data.Church
import GHC.Generics
import Data.Proxy

-- Generalize of const. Allows us to use more than just Either
-- for gmaybe
class GConst a r where
  gconst :: r -> a
instance GConst r' r => GConst (a -> r') r where
  gconst r = const (gconst r)
instance GConst r r where
  gconst = id

gfail :: forall a e s e' r. 
          (ChurchRep a, GConst e' e, Church a r ~ (e' -> s -> r)) =>
           e -> s -> a -> r
gfail e s a = toChurchP (Proxy :: Proxy r) a (gconst e :: e') s

, gconst , , e. -

> gfail id (const 'a') $ Left 'b'
  'b'

-XIncoherentInstances (eek!). , , either, maybe.

, - .

*So> gfail True id (Just False)
False
*So> gfail True (id :: Bool -> Bool) Nothing
True
*So> gfail 'a' (const 'b') (Left ())
'a'
*So> gfail 'a' (const 'b') (Right ())
'b'
*So> :set -XDeriveGeneric
*So> data MyMaybe = Fail | Yay Int deriving (Show, Generic)
*So> instance ChurchRep MyMaybe
*So> gfail 'a' (const 'b') (Yay 1)
'b'
+3

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


All Articles