当前位置:网站首页>Ramda's little-known side

Ramda's little-known side

2022-06-24 16:49:00 Lin Group

Before we check Ramda Documents when , I often see some " strange " Type signature and usage of :

" strange " Type signature of :

(Applicative f, Traversable t) => (a → f a) → t (f a) → f (t a)

Some functions " strange " Usage of :

// R.ap can also be used as S combinator // when only two functions are passed 
R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA'

these " strange " Behind the dot of Ramda behind " deeper " The design of the first floor , This article will explain this , And explain the general functional programming theory behind it .

Ramda The familiar side

Ramda Often treated as Lodash The other one of " more FP" Alternative library for .

be relative to Lodash, Ramda The advantages of ( One of ) It's about Coriolis and data last The convenient pipeline programming brought by the design of (pipe).

Take a simple code comparison example :

Ramda:

const myFn = R.pipe (
  R.fn1,
  R.fn2 ('arg1', 'arg2'),
  R.fn3 ('arg3'),
  R.fn4
)

Lodash:

const myFn = (x, y) => {
  const var1 = _.fn1 (x, y)
  const var2 = _.fn2 (var1, 'arg1', 'arg2')
  const var3 = _.fn3 (var2, 'arg3')
  return _.fn4 (var3)
}

An excerpt from this example Stackoverflow The answer on

Ramda The little-known side of type signature

stay Ramda Of API In the document , The syntax for type signatures is somewhat " strange ":

addNumber → Number → Number

We combine Ramda The Coriolis rule of , A little speculation , You can convert this function to TypeScript The definition of :

export function add(a: number, b: number): number;

export function add(a: number): (b: number) => number;

OK, What then? Ramda Documents of are not used directly TypeScript Express the type of function ?

In fact, the above example has partially answered this question -- Because it's more concise .

Actually Ramda The type signature in the document uses Haskell The grammar of , Haskell As a functional programming language , Its grammar can express the meaning of corrilization very succinctly , By contrast , TypeScript The overloaded expression of is more bloated .

Of course , Use Haskell The significance of the type signature of is not limited to this , Let's look at other " strange " The function type of :

ap[a → b] → [a] → [b] Apply f => f (a → b) → f a → f b (r → a → b) → (r → a) → (r → b)

Combine with... In the document demo:

R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6]

R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"] 

// R.ap can also be used as S combinator 
// when only two functions are passed 
R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA'

[a → b] → [a] → [b] We understand , It's Cartesian product .

(r → a → b) → (r → a) → (r → b) We can understand , Is the concatenation of two functions .

Apply f => f (a → b) → f a → f b It's a little hard to understand , Grammar is a little strange , Let's translate it into TypeScript grammar :

:), ok , This type cannot be simply translated into TypeScript, because :

TypeScript No support will be made. type constructor As a type parameter .

for instance :

type T<F> = F<number>;

The error information is as follows :

Type 'F' is not generic.

In type signature F Is a type constructor , Both and Array Same Return the type of the type .

However , TypeScript There is no way to declare " A type parameter is a type constructor ".

As in the example type T<F> = F<number>; in , We can't tell TypeScript, there F Is a type constructor , So when will number Pass in F When , It's a mistake .

OK, We assume that TypeScript Statement of support " A type parameter is a type constructor ", Let's take a look at Apply f => f (a → b) → f a → f b How to translate :

type AP = <F extends Appy, A, B>(f: F<((a: A) => B)>) => (fa: F<A>) => F<B>;

there F It can be understood as a kind of Context , This type signature can be simply understood as :

Wrap a in context function Take out , Then wrap another in context value Take out , After calling the function , Wrap the return value of the function back into the context and return .

there Context It's a general term for , For example, we can make it special (specialize) by Promise :

type AP = <A, B>(f: Promise<((a: A) => B)>) => (fa: Promise<A>) => Promise<B>;  
  
const ap: AP = (f) => fa => f.then(ff => fa.then(ff));

ap Or say Apply As a common abstraction in functional programming , It has important learning significance , But its abstract parsing is beyond the scope of this article , Here we only focus on What is it? , Not for the moment Why? .

that , (r → a → b) → (r → a) → (r → b) And Apply f => f (a → b) → f a → f b What's the relationship ?

They are half brothers , (r → a → b) → (r → a) → (r → b) It's right Apply f => f (a → b) → f a → f b The specificity of , As we are to Promise It's like that .

The function can also be a Context ?

The answer is yes , We can take a unary function a -> b Understood as a " A wrapped in context b, Just to get this b, You need to first pass in a a.

To reduce grammar noise , Let's see first Haskell Yes ap The definition of :

instance Applicative ((->) r) where
    (<*>) f g x = f x (g x)

Replace with TypeScript The implementation of the , We will Promise The example of , obtain :

type F<A> = (a: any) => A;

type AP = <A, B>(f: F<((a: A) => B)>) => (fa: F<A>) => F<B>;  
  
const ap: AP = f => fa => {  
    return (r) => f(r)(fa(r));  
}

alike , We get Apply Be specific to Array The implementation of the :

type AP = <A, B>(f: Array<((a: A) => B)>) => (fa: Array<A>) => Array<B>;

const ap: AP = f => fa => {
	return f.flatMap(ff => fa.map(ff));
};

in summary , We can come to a conclusion :

ap Type signature of [a → b] → [a] → [b] and (r → a → b) → (r → a) → (r → b) yes Apply f => f (a → b) → f a → f b The specificity of .

But why Ramda Design like this

This article focuses on " What is it? ", as for " Why? ", Let's save this for the next article ?. Let's talk about it again .

原网站

版权声明
本文为[Lin Group]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/175/202206241644367449.html