http://learnyousomeerlang.com/content
Заметки о тестировании, программировании и прочий "поток сознания", который жалко писать "в стол"
суббота, 28 октября 2017 г.
пятница, 27 октября 2017 г.
Вопрос. Haskell
По итогам:
http://programmingmindstream.blogspot.ru/2017/10/haskell-vs-count.html?m=1
А как length/count (количество элементов списка) на Haskell реализовано?
Так:
Count [] = 0
Count ( _ : xs ) = 1 + Count xs
?
Или можно как-то эффективнее?
http://programmingmindstream.blogspot.ru/2017/10/haskell-vs-count.html?m=1
А как length/count (количество элементов списка) на Haskell реализовано?
Так:
Count [] = 0
Count ( _ : xs ) = 1 + Count xs
?
Или можно как-то эффективнее?
четверг, 26 октября 2017 г.
Haskell vs мои скрипты. Count & Map
Integer def List:Count
List in aList
aList Match (
List:[]
0
( List:Make: _ Tail )
( 1 + Tail call.me )
) // aList Match
; // List:Count
// что тут делать с "длинной рекурсией"
// - пока не очень понятно,
// возможно стоит сделать Count
// "хранимым членом"
Тогда так:
Integer def List:Count
List in aList
aList Match (
List:[]
0
( List:Make: _ Tail Count )
(
If ( Count .IsValid ) then
Count
Else
( 1 + Tail call.me )
)
) // aList Match
; // List:Count
List def List:Map
List in aList
Lambda in aLambda
aList Match (
List:[]
List:[]
( List:Make: Head Tail )
List:Make:
^@( Head aLambda do )
^@( Tail aLambda call.me )
) // aList Match
; // List:Map
Ну и вызов:
List:Make 1 List:Make 2 List:Make 3 List:Make 4 List:Make 5 List:[]
// строим список [ 1 2 3 4 5 ]
IsOdd
// отбираем нечётные
List:Map
( ToString + ' ' )
// тут приводим к строке и добавляем пробел
List:Map
List:For:
// перебирается список
Print
// печатаем каждый элемент
Напечатано:
1 3 5
Ну и вызов:
List:Make 1 List:Make 2 List:Make 3 List:Make 4 List:Make 5 List:[]
// строим список [ 1 2 3 4 5 ]
IsOdd
// отбираем нечётные
List:Map
List:Count
Print
// печатаем List:Count
Напечатано:
3
Пока выглядит вроде некузяво.
Но у меня же скрипты изначально императивные. И ОПЗ (обратная польская запись).
Но идею я вроде понял. Там строится граф/дерево разбора выражений в узлах которого записывается либо значение, либо ссылка на функцию (возможно со связанными параметрами, и не факт, что со всеми).
Если это значение, то выражение - вычислено полностью.
Если ссылка на функцию, то вычислено не полностью.
Тут и проявляется "ленивость".
Когда в узле вычисляется функция, то в узел записывается результат вычисления вместо ссылки на функцию.
Тут проявляется кеширование результатов. Ранее вычисленные функции - больше не вычисляются. А представляются значениями записанными в узлах графа/дерева.
Ну и код на Haskell:
xs = 1 : map (*2) xs
Выглядит так:
List def xs
List:Make:
1
( call.me ( 2 * ) List:Map )
; // List:Map
Я честно скажу - не проверял, но должно сработать.
Завтра проверю.
Бесконечной рекурсии там точно не будет.
При вызове xs.
Она сконструирует список:
1 : reference to expression ( xs ( 2 * ) List:Map )
А вот применится ли Map к правильному значению - вопрос пока открыт.
Возможно Map будет применяться не к xs, а к 1 ВСЕГДА.
Тут вопрос пока открыт. Надо проверить.
Возможно надо написать так:
List def xs
List:Make:
1
( Result ( 2 * ) List:Map )
; // List:Map
Есть и такой вариант. И он (как мне кажется) - ближе к истине.
Ибо call.me - это ссылка на функцю, а Result - это уже вычисленное значение.
Тонкая грань.
Или так:
List def xs
List VAR myResult
List:Make:
1
( myResult ( 2 * ) List:Map )
>>> myResult
myResult
; // List:Map)
Хотя и это можно скрыть за "синтаксическим сахаром".
List in aList
aList Match (
List:[]
0
( List:Make: _ Tail )
( 1 + Tail call.me )
) // aList Match
; // List:Count
// что тут делать с "длинной рекурсией"
// - пока не очень понятно,
// возможно стоит сделать Count
// "хранимым членом"
Тогда так:
Integer def List:Count
List in aList
aList Match (
List:[]
0
( List:Make: _ Tail Count )
(
If ( Count .IsValid ) then
Count
Else
( 1 + Tail call.me )
)
) // aList Match
; // List:Count
List def List:Map
List in aList
Lambda in aLambda
aList Match (
List:[]
List:[]
( List:Make: Head Tail )
List:Make:
^@( Head aLambda do )
^@( Tail aLambda call.me )
) // aList Match
; // List:Map
Ну и вызов:
List:Make 1 List:Make 2 List:Make 3 List:Make 4 List:Make 5 List:[]
// строим список [ 1 2 3 4 5 ]
IsOdd
// отбираем нечётные
List:Map
( ToString + ' ' )
// тут приводим к строке и добавляем пробел
List:Map
List:For:
// перебирается список
// печатаем каждый элемент
Напечатано:
1 3 5
Ну и вызов:
List:Make 1 List:Make 2 List:Make 3 List:Make 4 List:Make 5 List:[]
// строим список [ 1 2 3 4 5 ]
IsOdd
// отбираем нечётные
List:Map
List:Count
// печатаем List:Count
Напечатано:
3
Пока выглядит вроде некузяво.
Но у меня же скрипты изначально императивные. И ОПЗ (обратная польская запись).
Но идею я вроде понял. Там строится граф/дерево разбора выражений в узлах которого записывается либо значение, либо ссылка на функцию (возможно со связанными параметрами, и не факт, что со всеми).
Если это значение, то выражение - вычислено полностью.
Если ссылка на функцию, то вычислено не полностью.
Тут и проявляется "ленивость".
Когда в узле вычисляется функция, то в узел записывается результат вычисления вместо ссылки на функцию.
Тут проявляется кеширование результатов. Ранее вычисленные функции - больше не вычисляются. А представляются значениями записанными в узлах графа/дерева.
Ну и код на Haskell:
xs = 1 : map (*2) xs
Выглядит так:
List def xs
List:Make:
1
( call.me ( 2 * ) List:Map )
; // List:Map
Я честно скажу - не проверял, но должно сработать.
Завтра проверю.
Бесконечной рекурсии там точно не будет.
При вызове xs.
Она сконструирует список:
1 : reference to expression ( xs ( 2 * ) List:Map )
А вот применится ли Map к правильному значению - вопрос пока открыт.
Возможно Map будет применяться не к xs, а к 1 ВСЕГДА.
Тут вопрос пока открыт. Надо проверить.
Возможно надо написать так:
List def xs
List:Make:
1
( Result ( 2 * ) List:Map )
; // List:Map
Есть и такой вариант. И он (как мне кажется) - ближе к истине.
Ибо call.me - это ссылка на функцю, а Result - это уже вычисленное значение.
Тонкая грань.
Или так:
List def xs
List VAR myResult
List:Make:
1
( myResult ( 2 * ) List:Map )
>>> myResult
myResult
; // List:Map)
Хотя и это можно скрыть за "синтаксическим сахаром".
среда, 25 октября 2017 г.
ToDo. Сделать глобальную writeonly "переменную" _
Сделать глобальную writeonly "переменную" _
WriteOnly _
Туда можно писать, но нельзя читать.
Это аналог devNull.
Это нужно для pattern matching'а.
Update. Сделал.
WriteOnly _
Туда можно писать, но нельзя читать.
Это аналог devNull.
Это нужно для pattern matching'а.
Update. Сделал.
ToDo. Сделать match вместо RULES
Сделать match:
Чтобы вместо:
VAR head
VAR tail
RULES
( aList Empty == )
Empty
( aList .ConstructedWith: List )
(
aList .getValues ( @ head @ tail )
head : tail
)
DEFAULT
aList
>>> Result
;
Или:
VAR head
VAR tail
RULES
( aList .ConstructedWith: Empty )
Empty
( aList .ConstructedWith: List )
(
aList .getValues ( @ head @ tail )
head : tail
)
DEFAULT
aList
>>> Result
;
Написать:
Match aList
( Empty : Empty )
( matched List ( head tail ) : ( head : tail ) )
( Default : aList )
>>> Result
;
Чтобы можно было pattern matching делать.
И переменные (head и tail в нашем случае) определялись в нужном контексте.
Или даже так:
Match aList
( Empty ? Empty )
( matched List head tail ? ( head : tail ) )
( matched Join head tail ? ( head : tail ) )
( Default ? aList )
>>> Result
;
Или даже так:
Match aList
( Empty ? Empty )
( List head tail ? ( head : tail ) )
( Join head tail ? ( head : tail ) )
( Default ? aList )
>>> Result
;
Чтобы вместо:
VAR head
VAR tail
RULES
( aList Empty == )
Empty
( aList .ConstructedWith: List )
(
aList .getValues ( @ head @ tail )
head : tail
)
DEFAULT
aList
>>> Result
;
Или:
VAR head
VAR tail
RULES
( aList .ConstructedWith: Empty )
Empty
( aList .ConstructedWith: List )
(
aList .getValues ( @ head @ tail )
head : tail
)
DEFAULT
aList
>>> Result
;
Написать:
Match aList
( Empty : Empty )
( matched List ( head tail ) : ( head : tail ) )
( Default : aList )
>>> Result
;
Чтобы можно было pattern matching делать.
И переменные (head и tail в нашем случае) определялись в нужном контексте.
Или даже так:
Match aList
( Empty ? Empty )
( matched List head tail ? ( head : tail ) )
( matched Join head tail ? ( head : tail ) )
( Default ? aList )
>>> Result
;
Или даже так:
Match aList
( Empty ? Empty )
( List head tail ? ( head : tail ) )
( Join head tail ? ( head : tail ) )
( Default ? aList )
>>> Result
;
Haskell. Pattern matching
checkIP :: IPAddress -> String
checkIP (IPv4 address) = "IPv4 is '" ++ address ++ "'."
checkIP IPv4Localhost = "IPv4, localhost."
checkIP (IPv6 address) = "IPv6 is '" ++ address ++ "'."
checkIP IPv6Localhost = "IPv6, localhost."
Очень глубоко на самом деле.Я давно о подобном думал. А решение оказывается "лежало на поверхности".
вторник, 24 октября 2017 г.
Data 1. Haskell vs мои скрипты
data List = List a List | []
Выглядит так:
Data List
Constructor List (
Anonim ANY
Anonim List
) // List
Constructor [] ()
; // List
Или с именами полей:
Data List
Constructor List (
Named ANY Head
Named List Tail
) // List
Constructor [] ()
; // List
Или в операторном виде:
Data List
Constructor List (
Left Anonim ANY // параметр слева
Anonim List // параметр справа
) // List
Constructor [] ()
; // List
Тогда конструктор List вызывается так:
1 List 2 List []
Строит:
[ 1 2 ]
О! Я понял как pattern matching сделать.
В общем я могу сделать head:tail вместо .Split Head Tail.
aList .Split Head Tail
Можно сделать так (под капотом):
MATCH List:Make ( Head Tail )
Тут говорим, что надо применить pattern matching к конструктору List:Make и положить результаты в ( Head Tail )
А потом MATCH можно спрятать в и вычислять его в зависимости от того с какой стороны от знака равно (=) находится List:Make.
Учитывая, что "экземпляр объкта" знает про конструктор, которым он был создан, то выражение:
MATCH List:Make ( Head Tail )
можно переписать:
MATCH ( Head Tail )
LIST FUNCTION f
LIST IN aList
ANY VAR Head
LIST VAR Tail
aList .Split Head Tail
LIST:Make 1 Map ( 2 * ) Tail
>>> Result
; // f
Можно переписать так:
LIST FUNCTION f
LIST IN aList
ANY VAR Head
LIST VAR Tail
MATCH aList ( Head Tail )
LIST:Make 1 Map ( 2 * ) Tail
>>> Result
; // f
LIST FUNCTION f
LIST IN aList
ANY VAR Head
LIST VAR Tail
MATCH aList
[]
[]
( Head Tail )
( LIST:Make 1 Map ( 2 * ) Tail )
; // MATCH
>>> Result
; // f
Выглядит так:
Data List
Constructor List (
Anonim ANY
Anonim List
) // List
Constructor [] ()
; // List
Или с именами полей:
Data List
Constructor List (
Named ANY Head
Named List Tail
) // List
Constructor [] ()
; // List
Или в операторном виде:
Data List
Constructor List (
Left Anonim ANY // параметр слева
Anonim List // параметр справа
) // List
Constructor [] ()
; // List
Тогда конструктор List вызывается так:
1 List 2 List []
Строит:
[ 1 2 ]
О! Я понял как pattern matching сделать.
В общем я могу сделать head:tail вместо .Split Head Tail.
aList .Split Head Tail
Можно сделать так (под капотом):
MATCH List:Make ( Head Tail )
Тут говорим, что надо применить pattern matching к конструктору List:Make и положить результаты в ( Head Tail )
А потом MATCH можно спрятать в и вычислять его в зависимости от того с какой стороны от знака равно (=) находится List:Make.
Учитывая, что "экземпляр объкта" знает про конструктор, которым он был создан, то выражение:
MATCH List:Make ( Head Tail )
можно переписать:
MATCH ( Head Tail )
Тогда навскидку:
LIST IN aList
ANY VAR Head
LIST VAR Tail
aList .Split Head Tail
LIST:Make 1 Map ( 2 * ) Tail
>>> Result
; // f
Можно переписать так:
LIST FUNCTION f
LIST IN aList
ANY VAR Head
LIST VAR Tail
MATCH aList ( Head Tail )
LIST:Make 1 Map ( 2 * ) Tail
>>> Result
; // f
Или даже так:
LIST IN aList
ANY VAR Head
LIST VAR Tail
MATCH aList
[]
[]
( Head Tail )
( LIST:Make 1 Map ( 2 * ) Tail )
; // MATCH
>>> Result
; // f
Или так:
LIST FUNCTION f
LIST IN aList
MATCH aList
[]
[]
( ANY VAR Head
LIST VAR Tail
Head Tail )
( LIST:Make 1 Map ( 2 * ) Tail )
; // MATCH
>>> Result
; // f
LIST IN aList
MATCH aList
[]
[]
( ANY VAR Head
LIST VAR Tail
Head Tail )
( LIST:Make 1 Map ( 2 * ) Tail )
; // MATCH
>>> Result
; // f
Подписаться на:
Комментарии (Atom)