FORTRAN计算机英语,functional-fortran: FORTRAN,亦译为福传,是英文"FORmula TRANslator"的缩写,译为“公式翻译器”,它是世界上最早出现的计算机高级程...

functional-fortran

Functional programming for modern Fortran.

badge.svg

functional-fortran.svg

Getting started

Get the code

git clone https://github.com/wavebitscientific/functional-fortran

cd functional-fortran

Build with fpm

This project supports the Fortran Package Manager (fpm).

fpm build --release

fpm test

You can also use it as a dependency in your existing fpm package.

Just add functional-fortran to your fpm.toml:

[dependencies]

[dependencies.functional]

git = "https://github.com/wavebitscientific/functional-fortran"

Build with CMake

Alternatively, you can build functional-fortran with CMake:

mkdir build

cd build

cmake ..

make

ctest

Or just drop-in the source file

functional-fortran is a single-file library.

Just grab src/functional.f90 and build it however you want.

Use it

Start using functional-fortran in your code by including the module:

use functional

Why functional-fortran?

While not designed as a purely functional programming language,

modern Fortran goes a long way by letting the programmer

use pure functions to encourage good functional discipline,

express code in mathematical form, and minimize bug-prone mutable state.

This library provides a set of commonly used tools in functional

programming, with the purpose to help Fortran programmers

be less imperative and more functional.

What's included?

The following functions are provided:

arange returns a regularly spaced array

complement returns a set complement of two arrays

empty returns an empty array

filter filters an array using a logical input function

foldl recursively left-folds an array using an input function

foldr recursively right-folds an array using an input function

foldt recursively tree-folds an array using an input function

head returns the first element of an array

init returns everything but the last element

insert inserts an element into an array, out-of-bound safe

intersection returns a set intersection of two arrays

iterfold iteratively reduces an array using an input function

last returns the last element of an array

limit limits a scalar or array by given lower and upper bounds

map maps an array with an input function

set returns a set given input array

reverse returns array in reverse order

sort is a recursive quicksort using binary tree pivot

split returns first or second half of an array

subscript is an out-of-bound safe implementation of vector subscript

tail returns everything but the first element

unfold unfolds an array with an input function

union returns a set union of two arrays

All of the above functions are compatible with the standard Fortran 2008 kinds:

int8, int16, int32, int64, real32, real64, real128,

complex(real32), complex(real64), and complex(real128).

Further, these functions (and their corresponding operators)

are compatible with character strings:

complement, empty, head, init, intersection, insert,

last, reverse, set, sort, split, tail, and union.

Functions that operate on one or two arguments are also available as

unary or binary operators, respectively. These are:

.complement., .head., .init., .intersection., .last.,

.reverse., .set., .sort., .tail., and .union..

Example usage

Array functions

arange is used to generate evenly spaced arrays,

given start and end values as input arguments:

write(*,*)arange(1,5)

12345

arange works with real numbers as well:

write(*,*)arange(1.,5.)

1.000000002.000000003.000000004.000000005.00000000

Third argument to arange (optional) is the increment,

which defaults to 1 if not given:

write(*,*)arange(1,15,3)

1471013

Negative increments work as expected:

write(*,*)arange(3,1,-1)

321

We can use floating-point increments:

write(*,*)arange(1.,1.5,0.1)

1.000000001.100000021.200000051.299999951.399999981.50000000

If start is greater than end and increment is positive,

arange returns an empty array:

write(*,*)arange(5,1)

Use empty to generate a zero-length array of any Fortran standard

kind:

write(*,*)size(empty(1))

0

which may be useful to initialize accumulators, for example

see the implementation of set intersection in this library.

head returns the first element of the array:

write(*,*)head([1,2,3])

1

tail returns everything but the first element of the array:

write(*,*)tail([1,2,3])

23

Similarly, last returns the last element of the array:

write(*,*)last([1,2,3])

3

init returns everything but the last element of the array:

write(*,*)init([1,2,3])

12

Subscript an array at specific indices:

write(*,*)subscript([1,2,3,4,5],[3,4])

34

Unlike the Fortran 2008 vector subscript, the subscript function is out-of-bounds safe,

i.e. subscripting out of bounds returns an empty array:

write(*,*)subscript([1,2,3],[10])

We can prepend, append, or insert an element into an array using insert:

! insert a 5 at position 0 to prepend:

write(*,*)insert(5,0,[1,2,3])

5123

! insert a 5 at position 4 to append:

write(*,*)insert(5,4,[1,2,3])

1235

! insert a 2 at position 2:

write(*,*)insert(2,2,[1,3,4])

1234

split can be used to return first or second half of an array:

! return first half of the array

write(*,*)split(arange(1,5),1)

12

! return second half of the array

write(*,*)split(arange(1,5),2)

345

The above is useful for recursive binary tree searching or sorting,

for example, see the implementation of sort in this library.

sort returns a sorted array in ascending order:

real::x(5)

callrandom_number(x)

write(*,*)x

0.9975595470.5668246750.9659153220.7479276660.367390871

write(*,*)sort(x)

0.3673908710.5668246750.7479276660.9659153220.997559547

Use reverse to sort in descending order:

write(*,*)reverse(sort(x))

0.9975595470.9659153220.7479276660.5668246750.367390871

The limit function can be used to contrain a value of a scalar

or an array within a lower and upper limit, for example:

! limit a scalar (5) within bounds 1 and 4

write(*,*)limit(5,1,4)

4

! flipping the bounds works just as well

write(*,*)limit(5,4,1)

4

limit also works on arrays:

write(*,*)limit(arange(0,4),1,3):

11233

More functional: map, filter, fold, unfold

map has the same functionality as pure elemental functions,

but can be used to apply recursive functions to arrays, for example:

purerecursiveintegerfunctionfibonacci(n)result(fib)

integer,intent(in)::n

if(n==0)then

fib=0

elseif(n==1)then

fib=1

else

fib=fibonacci(n-1)+fibonacci(n-2)

endif

endfunctionfibonacci

write(*,*)map(fibonacci,[17,5,13,22])

1597523317711

filter returns array elements that satisfy a logical filtering function.

For example, we can define a function that returns .true. when input is an

even number, and use this function to filter an array:

purelogicalfunctioneven(x)

integer,intent(in)::x

even=.false.

if(mod(x,2)==0)even=.true.

endfunctioneven

write(*,*)filter(even,[1,2,3,4,5])

24

Functions can be chained together into pretty one-liners:

write(*,*)filter(even,map(fibonacci,arange(1,10)))

2834

functional-fortran also provides left-, right-, and tree-fold functions,

foldl, foldr, and foldt, respectively. These functions recursively

consume an array using a user-defined function, and return a resulting scalar.

For simple examples of sum and product functions using folds, we can define

the following addition and multiplication functions that operate on scalars:

purerealfunctionadd(x,y)

real,intent(in)::x,y

add=x+y

endfunctionadd

purerealfunctionmult(x,y)

real,intent(in)::x,y

mult=x*y

endfunctionmult

We can then calculate the sum and product of an array by "folding" the

input using the above-defined functions and a start value

(second argument to fold*):

! left-fold an array using add to compute array sum

write(*,*)foldl(add,0.,arange(1.,5.))

15.0000000

! left-fold an array using mult to compute array product

write(*,*)foldl(mult,1.,arange(1.,5.))

120.000000

The above is a trivial example that re-invents Fortran intrinsics

as a proof of concept. Intrinsic functions should of course be used

whenever possible.

foldl, foldr, and foldt return the same result if the user-defined

function is associative. See the Wikipedia page on fold for more information.

iterfold is an iterative (non-recursive) implementation of foldl

that is provided for reference.

Opposite to fold*, unfold can be used to generate an array

based on a start value x, and a function f, such that

the resulting array equals [x, f(x), f(f(x)), f(f(f(x))), ... ].

For example:

purerealfunctionmultpt1(x)

real,intent(in)::x

multpt1=1.1*x

endfunctionmultpt1

write(*,*)unfold(multpt1,[1.],5)

1.000000001.100000021.210000041.331000091.46410012

Set functions: set, union, intersection, complement

Function set returns all unique elements of an input array:

write(*,*)set([1,1,2,2,3])

123

Common functions that operate on sets, union,

intersection, and complement, are also available:

! unique elements that are found in either array

write(*,*)union([1,2,2],[2,3,3,4])

1234

! unique elements that are found in both arrays

write(*,*)intersection([1,2,2],[2,3,3,4])

2

! unique elements that are found first but not in second array

write(*,*)complement([1,2,2],[2,3,3,4])

1

Contributing

Please submit a bug report or a request for new feature

here.

Further reading

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值