Re[6]: Для чего нужно лямбда-исчисление?
От: vdimas Россия  
Дата: 26.08.24 21:39
Оценка:
Здравствуйте, Privalov, Вы писали:

P>То есть сломали обратную совместимость?


Не, старый код компиллируется.


V>>Будь моя воля, я бы голосовал за шлифовку и выпуск современных стандартов этого легендарного языка с последующим возвращением его в "обойму" мейнстрима.

P>У Фортрана (того, на котором я работал) я вижу один недостаток: отсутствие зарезервированных слов. Иногда это приводило к весьма забавным эффектам.
P>Ну да, у него динамических структур данных не хватало. Приходилось выкручиваться.

Там много чего раздражало с т.з. современных компиляторов и наработанных практик.

Стоит пройтись по современному Фортрану, ИМХО, это весьма вкусный язык в последних версиях:
https://cyber.dabamos.de/programming/modernfortran/control-structures.html
https://wg5-fortran.org/N2201-N2250/N2212.pdf

Просто примеры (в т.ч. для остальных коллег):
Arithmetic if
if (x * y) 100, 200, 300

is equivalent to:
if (e < 0) goto 100
if (e == 0) goto 200
goto 300


Logical if
if (x * y < 0) y = 1


Block if
if (a == 0) then
    exit
else if (a < 0) then
    b = 0
else
    b = b + a
end if


Expressional if
b = (a > 0.0 ? a : 0.0)

В том числе это работает для ссылочных типов данных, например, для inout-параметров ф-ий:
call some_sub(a > 0 ? a : b > 0 ? b : c)
...
subroutine some_sub(x)
real, intent(inout) :: x

Т.е., в подпрограмму some_sub будет подана ссылка на a, b или c.

Select switch
select case (grade)
    case ('A')
        print *, 'Excellent!'

    case ('B', 'C')
        print *, 'Well done'

    case default
        print *, 'Invalid grade'
end select

В том числе сравнение в диапазонах:
select case (marks)
    case (91:100)
        print *, 'Excellent!'

    case (81:90)
        print *, 'Very good!'

    case (71:80)
        print *, 'Well done!'

    case (:40)
        print *, 'Better try again!'

    case default
        print *, 'Invalid marks'
end select


Наследование структур, типобезопасные указатели на базовую структуру, информация о типах:
type :: vec_type
    real :: x, y
end type vec_type

type, extends(vec_type) :: vec3_type
    real :: z
end type vec3_type

type, extends(vec3_type) :: color_type
    integer :: color
end type color_type

type(vec_type),   target  :: v
type(vec3_type),  target  :: v3
type(color_type), target  :: c
class(vec_type),  pointer :: ptr

v  = vec_type(1.0, 2.0)
v3 = vec3_type(1.0, 2.0, 3.0)
c  = color_type(0.0, 1.0, 2.0, 9)

! Point to either v, v3, or c:
ptr => c

select type (a => ptr)
    class is (vec_type)
        print *, a%x, a%y

    type is (vec3_type)
        print *, a%x, a%y, a%z

    type is (color_type)
        print *, a%x, a%y, a%z, a%color
end select


Implied do
(имеется ввиду т.н. "подразумеваемая" разновидность цикла do)
integer :: values(10) = [ (i * 2, integer :: i = 1, 10) ]

Массив values будет содержать 2, 4, ..., 20

do concurrent
integer :: i
real    :: a(100)

do concurrent (i = 1:size(a))
    a(i) = sqrt(i**i)
end do


Для вычисления в параллель итогов используется reduce(function, variable)
integer :: i
real :: a, x(n)

a = 0.
do concurrent (i = 1:n) reduce(+:a)
    a = a + x(i)**2
end do

Вместо '+' могла быть некая пользовательская ф-ия.

Enumeration types
enumeration type :: colour
    enumerator :: red, orange, green
end type

type(colour) light

if (light==red) ...

An enumerator may be accessed as an ‘enumeration constructor’ through its position in the type
declaration. For example colour(2) has the value orange. This allows the enumerators to be
accessed in a do loop such as:

do i = 1,3
  light = colour(i)
:
end do

select case (light)
case (red)
:
case (orange:green)
:
end select


Для целей интероперабельности с Си есть такая форма:
enum, bind(c) :: season
    enumerator :: spring=5, summer=7, autumn, winter
end enum

type(season) my_season, your_season

my_season = spring
your_season = autumn+1 ! winter


Импорт внешних ф-ий
! usleep.f90
module posix
    use, intrinsic :: iso_c_binding
    private

    public :: c_usleep

    interface
        ! int usleep(useconds_t useconds)
        function c_usleep(useconds) bind(c, name='usleep')
            import :: c_int, c_int32_t
            implicit none
            integer(kind=c_int32_t), value :: useconds
            integer(kind=c_int)            :: c_usleep
        end function c_usleep
    end interface
end module posix

program main
    use :: posix
    integer :: i, rc, t

    t = 500 * 1000 ! 500 milliseconds

    do i = 1, 10
        print '("zzz ...")'
        rc = c_usleep(t)
    end do
end program main


Юникод
! unicode.f90
program main
    use, intrinsic :: iso_fortran_env, only: output_unit
    implicit none
    integer, parameter :: ucs2 = selected_char_kind('ISO_10646')
    character(kind=ucs2, len=:), allocatable :: str

    str = ucs2_'Unicode character: \u263B'

    open (output_unit, encoding='utf-8')
    print '(a)', str
end program main


ООП: https://cyber.dabamos.de/programming/modernfortran/object-oriented-programming.html
Препроцессор: https://cyber.dabamos.de/programming/modernfortran/preprocessor.html


Еще видел реализацию Фортрана в LLVM и wasm, которая предлагает так же синтаксис одновременного объявления и присвоения значений переменным, что делает код еще более выразительным.

Есть атомарные операции, есть указатели (но с "осторожной" адресной арифметикой, что оставляет меньше простора для ошибок), есть активная работа над языком.

Причём, я вижу сплошной здравый смысл, натурально "с языка снимают" — что раздражало в Фортране всю дорогу, то сейчас и причёсывают. ))

Плюс возможность установить дефлотный режим 'implicit none' для компилятора, чтобы еще больше почистить сырцы.
При этом легаси код можно компилять с опцией 'implicit'.

В общем, там много ума не надо, чтобы увидеть, как это стоит делать по-уму.
Отредактировано 26.08.2024 21:54 vdimas . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.