P
provability of the statement “if provable P
, then P
true” is possible only in the case of provability of the statement P
.loeb
is one of those functions on Haskele that looks charming, crazy, simple and complex at the same time.loeb
function: loeb :: Functor f => f (fa -> a) -> fa loeb x = go where go = fmap ($ go) x
loeb :: Functor f => f (fa -> a) -> fa
::
, then we’ll write restrictions on the parameters to the fat arrow ( =>
) - I’ll explain it a little bit below until it matters. And finally - the types themselves:f (fa -> a) -> fa
, look how close the record is to the Loeb theorem: loeb :: Functor f => f (fa -> a) -> fa loeb x = go where go = fmap ($ go) x
where
is a service one and makes it possible to define an internal function.f (x, y, z) = ...
, in Haskell they write only fxyz = ...
loeb
function is a function of one argument
and it is determined through the function go
.go
defined by the Functor and the function fmap
. The fmap
function itself is a generalization of the map
function for lists and is defined as follows: class Functor f where fmap :: (a -> b) -> fa -> fb
f
will be polymorphic in the function fmap
.fmap
is a function of two arguments - (a -> b)
and fa
, the output is type fb
.(a -> b)
is a function of one argument, taking some value as an input (generally we call this type a
, it can be any — for example, a string, a number, or a file) and the output is also some or a type (we denote it by b
, remembering that b
in particular may be a
).fa
- can be understood as a kind of complex value depending on a
and it will be easier to understand if you read as f(a)
fmap
applies the function to the value through f
, and, as a rule, it is so. instance Functor [] where fmap = map
fmap
function fmap
completely analogous to the map
function. Well, the map
function already all imperatives know, this application of the function to all the members of the list. In Haskell, it is determined very simply: map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = fx : map f xs
x : xs
, notice the letter s
, in English, this means the plural, they say many x
-s in xs
) and return another list, where we use the function for the head, and tail we recursively apply our described function.map
function map
, but do not fully understand how fmap = map
can be done - everything is quite simple, replace f
with []
fmap :: (a -> b) -> [] a -> [] b
fmap :: (a -> b) -> [a] -> [b]
go = fmap ($ go) x
$
Is an ordinary function-operator, called an applicative function and is determined elementarily: ($) :: (a -> b) -> a -> b f $ x = fx
loeb
function using lambda expressions: loeb :: Functor f => f (fa -> a) -> fa loeb x = go where go = fmap (\z -> z go) x
\z -> z go
means that the lambda function (a slash resembles the Greek letter lambda - λ
) from one variable z
, and the arrow ->
read like =
loeb
doing?loeb
calculates the result in terms of itself, but this is more crazy than what you felt when you first heard about recursion.loeb
use for? Where is it useful? For example, you can make a spreadsheet (like Exel) for a list functor - []: xs :: [a] xs = [...] fs :: [[a] -> a] fs = [...] rs :: [a] rs = [ f xs | f <- fs ] -- r = f xs
xs :: [a]
. And we have a list of functions that collapse the lists to values, fs :: [[a] -> a]
. We take and for each function from the list we apply to the list of elements, thus obtaining a new value r
. Collect all r
in the list rs
. [ f xs | f <- fs ]
rs
from the list of xs
values and the list of fs
functions.xs
values, and use rs
instead. In other words, the function f
is applied to the list of results, which itself generates! fs :: [[a] -> a] fs = [...] rs :: [a] rs = [ f rs | f <- fs ]
rs
is calculated in terms of itself. You can combine both functions to not have your own definitions of fs
, and they will be just the rs
parameter: rs fs = [ f (rs fs) | f <- fs ]
rs = loeb
loeb
function takes a list of functions, and calculates a list of results that it generates, and applies itself to the list just generated. Strange? Check? Ringed? I bet no!loeb
fs = [ const 1 , succ . (!! 0) , succ . (!! 1) , succ . (!! 2) ]
const a _ = a
is a function of two variables, which always returns the value of the first, succ x = inc
increment for numbers (more precisely, this is a generalization of the increment for any enumerated values), (!!)
is the function of pulling the n
element from the list , (.)
- functional composition of 2 functions, first applies the right function, then the left one, in our case, first pulls an element from the list, then increments.const 1
we have the first element, and it always returns 1, after that you can get the value of the second element - succ . (!! 0)
succ . (!! 0)
, and further along the chain - the third, fourth and fifth. > loeb fs [1,2,3,4]
fs = [ succ . (!! 1) , succ . (!! 3) , succ . (!! 0) , const 1 ] > loeb fs [3,2,4,1]
import Data.Array import Data.List import Control.Monad import Text.Printf loeb :: Functor f => f (fa -> a) -> fa loeb x = go where go = fmap ($ go) x -- e = val 0 -- val = const -- , (10 %) vat ix = (* 0.1) . (! ix) -- sum' ixs = \arr -> foldl' (\acc ix -> acc + arr ! ix) 0 ixs spreadsheet = listArray ((0,0), (4,4)) -- Prices | VAT | Effective prices + total [ val 1, vat (0,0), sum' [(0,i) | i <- [0..1]], e, e , val 3, vat (1,0), sum' [(1,i) | i <- [0..1]], e, e , val 5, vat (2,0), sum' [(2,i) | i <- [0..1]], e, e , val 2, vat (3,0), sum' [(3,i) | i <- [0..1]], e, e , e, e, sum' [(i,2) | i <- [0..3]], e, e ] printArr :: Array (Int, Int) Double -> IO () printArr arr = forM_ [0..4] $ \i -> do forM_ [0..4] $ \j -> printf "%4.1f " (arr ! (i,j)) printf "\n" main = printArr $ loeb spreadsheet
1.0 0.1 1.1 0.0 0.0 3.0 0.3 3.3 0.0 0.0 5.0 0.5 5.5 0.0 0.0 2.0 0.2 2.2 0.0 0.0 0.0 0.0 12.1 0.0 0.0
val
), in the second column we have taxes of what is left, in the third column the effective price, and below the total sum of all effective prices. Now you can see, order and buy everything! Magic! :-)moeb
functionmoeb
is the result of the game with the definition of the loeb
function: what if we want to abstract from the fmap
. For starters, this will make the signature under the function just crazy! -- [m]oeb = multi-loeb :-) moeb :: (((a -> b) -> b) -> c -> a) -> c -> a moeb fx = go where go = f ($ go) x
loeb
, it will only be a special case of moeb
: loeb = moeb fmap
moeb
function moeb
that it can be used? id :: a -> a id x = x
moeb id x = id ($ moeb id x) x = ($ moeb id x) x = x (moeb id x) -- , fix -- fix f = f (fix f) fix = moeb id
moeb
is a generalization of the fix
function.moeb
parameters, such as traverse
and foldMap
, but I still don’t know why you can use it for something useful.Source: https://habr.com/ru/post/203800/
All Articles