LINUX.ORG.RU

[template haskell] как всё-таки его готовить?


0

1

Как, к примеру, решить такую задачу - есть бинарное дерево и набор функций:

tree'path'...

где вместо ... - последовательность букв 'l' и 'r' которые означают соответсвенно левую ветвь и правую:

tree'path'lrlr

это доступ к элементу по пути left->right->left->right.

tree'path'lrlr = tree'path'l . tree'path'r . tree'path'l . tree'path'r

Как можно нагенерировать таких функций (допустим до пути к 20-кратному уровню вложенности, всего 38 функций)? А то неохота прописывать их вручную.

★★★★

А вариант

tree'path [L,R,L,R]
тебя тоже не устраивает?

Resorting to Template Haskell is admitting defeat. Do it only if you really have a defeat to admit.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

тебя тоже не устраивает?

Устраивает, вполне. Но мне нужно именно такое API как я описал. И потом хотелось бы увидеть его просто из интереса к тому как пользоваться TH - а то примеры на haskell.org как-то не доходят. Например Data.Data (или Data.Generics) может строить произвольный код (для gfold) функции средствами TH, как я понимаю expression для определения функции это такой же expression как stringE или tupleE, соответственно генерировать в нём ещё имя функции - и всё. По идее это должно быть очень просто.

quasimoto ★★★★
() автор топика
Ответ на: комментарий от quasimoto

expression для определения функции это такой же expression как stringE или tupleE, соответственно генерировать в нём ещё имя функции - и всё.

Точнее

runQ [d| tree'path'lrlr = tree'path'l . tree'path'r . tree'path'l . tree'path'r |]

>

[ValD (VarP tree'path'lrlr) -- < сюда подставить
               -- v и сюда последовательность InfixE
      (NormalB (InfixE (Just (VarE Main.tree'path'l))
                       (VarE GHC.Base..)
                       (Just (InfixE (Just (VarE Main.tree'path'r))
                                     (VarE GHC.Base..)
                                     (Just (InfixE (Just (VarE Main.tree'path'l))
                                                   (VarE GHC.Base..)
                                                   (Just (VarE Main.tree'path'r)))))))) []]
quasimoto ★★★★
() автор топика
Ответ на: комментарий от quasimoto

Но мне нужно именно такое API как я описал.

Не нужно.

Например Data.Data (или Data.Generics) может строить произвольный код (для gfold) функции средствами TH, как я понимаю

??? Какое отношение Data.Data имеет к TH?

Miguel ★★★★★
()
Ответ на: комментарий от quasimoto

Do it only if you really have a defeat to admit.

Да, я реально хочу увидеть как оно работает :)

Это немножко разные вещи.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

Не нужно.

Ага, это своеобразный способ решить задачу - не решать её?

??? Какое отношение Data.Data имеет к TH?

Мне рассказывали, что TH используется в Data.Generics. По крайней мере GHC его использует для автоматической генерации инстансов из deriving, в том числе для Data, Typeable.

quasimoto ★★★★
() автор топика
Ответ на: комментарий от quasimoto

Ага, это своеобразный способ решить задачу - не решать её?

Извини, я не верю, что кому-то нужен API из 2^20 функций вместо одной.

Мне рассказывали, что TH используется в Data.Generics. По крайней мере GHC его использует для автоматической генерации инстансов из deriving, в том числе для Data, Typeable.

Э-э-э... то есть, TH используется где-то в исходниках GHC? Допустим. В самих Data.Data и Data.Generics - как-то слабо верю.

Miguel ★★★★★
()

>Как можно нагенерировать таких функций (допустим до пути к 20-кратному уровню вложенности, всего 38 функций)? А то неохота прописывать их вручную.

38? =) Не.... нужно 2^20 :3

Waterlaz ★★★★★
()
Ответ на: комментарий от Waterlaz

38? =) Не.... нужно 2^20 :3

Ну элементарная же комбинаторика:

tree'path[x_1, x_2, ..., x_20]
x_i = l | r

того 2*20 = 40, 2 из которых примитивные, остальные выражаются через них компзиции:

tree'path = compose over (tree'path'l, tree'path'r) by [x_1, x_2, ..., x_20]

(дерево бинарное, кстати, в начале поста написано).

quasimoto ★★★★
() автор топика
Ответ на: комментарий от quasimoto

т.е. нужно только по фиксированному уровню вложенности.

Наверно, всё это очень секретные вещи :)

quasimoto ★★★★
() автор топика
Ответ на: комментарий от quasimoto

Гм. Кхем. Не хочешь, для начала, подучить комбинаторику?

Хинт: посчитай ручками, сколько функций нужно для доступа до уровня 4. Нет, не 8.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

сколько функций нужно для доступа до уровня 4

2^4 общим счётом, я опять чего-то напутал.

Но вопрос был не об этом. Ладно, я пожалуй ещё раз почитаю повнимательней примеры на haskell wiki.

quasimoto ★★★★
() автор топика
Ответ на: комментарий от quasimoto

Хм, если следовать логике первого поста - 8-битовым байтом кодируется 16 чисел :) Т.е. мне нужно генерировать совсем много функций, точно не в ручную их писать.

quasimoto ★★★★
() автор топика
Ответ на: комментарий от quasimoto

> Т.е. мне нужно генерировать совсем много функций, точно не в ручную их писать.

и сразу возникает вопрос, а не поплохеет ли программе, если в ней будут лишний миллион ненужных функций, и далее — а позволяет ли template haskell лениво инстациировать шаблоны (как в с++), чтобы из этого миллиона были инстанциированы только реально употребленные функции?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

а не поплохеет ли программе, если в ней будут лишний миллион ненужных функций

Компилятору точно поплохеет.

а позволяет ли template haskell лениво инстациировать шаблоны (как в с++)

В C++ код шаблона целиком находится в хедере. Только поэтому он может «инстанцироваться лениво». В Haskell компилится всё. Так что - нет, в этом смысле - не получится.

Miguel ★★★★★
()
Ответ на: комментарий от quasimoto

Т.е. мне нужно генерировать совсем много функций, точно не в ручную их писать.

Вот дурной. Я тебе первым комментом написал, как оно должно выглядеть. Это и будет «не вручную».

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

> В C++ код шаблона целиком находится в хедере. Только поэтому он может «инстанцироваться лениво». В Haskell компилится всё. Так что - нет, в этом смысле - не получится.

не совсем так

никто не мешает в объектнике вместе со скомпиленой функцией хранить че-то типа ее исходника (емнип это и происходит при кое-каких оптимизациях жцц)

что же касается template haskell, то подозреваю что он действительно не умеет ленивую инстанциацию шаблонов, но интересно знать точно

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от quasimoto

>Хм, если следовать логике первого поста - 8-битовым байтом кодируется 16 чисел :)

А если подумать? =)

Waterlaz ★★★★★
()
Ответ на: комментарий от quasimoto

[code] module Main where import Test import Test2

infixl 9 +++ f1 +++ f2 = let f x = f1 $ '-' : f2 x in f

main = putStrLn $ go_lll +++ go_llr +++ go_lrl +++ go_lrr +++ go_rll +++ go_rlr $ «»

---------------------------------------------- module Test2 where import Test

genI [ x:y:[z] | x <- «lr», y <- «lr», z <- «lr»]

---------------------------------------------- {-# LANGUAGE TemplateHaskell #-} module Test where

import Control.Monad import Language.Haskell.TH

left x = 'l':x right x = 'r':x

genL' ('r':[]) = Just $ VarE 'right genL' ('l':[]) = Just $ VarE 'left genL' (x:xs) = Just $ InfixE (genL' [x]) (VarE '(.)) (genL' xs)

genL f = let name = mkName $ «go_» ++ f in let (Just exp) = genL' f in [ValD (VarP name) (NormalB exp) []]

genI i = return $ join $ map genL i [/code]

Грязно, но работает. Хаскель не знаю, TH - тем более, потратил на просмотр примеров по TH 15 минут. По-моему, это можно сделать по-лучше.

anonymous
()
Ответ на: комментарий от anonymous

oops

module Main where
import Test
import Test2

infixl 9 +++  
f1 +++ f2 = let f x = f1 $ '-' : f2 x in f 

main = putStrLn $ go_lll +++ go_llr +++ go_lrl +++ go_lrr +++ go_rll +++ go_rlr $ ""

------------------------------------------------ 
module Test2 where
import Test

genI  [ x:y:[z] | x <- "lr", y <- "lr", z <- "lr"]

------------------------------------------------
{-# LANGUAGE TemplateHaskell #-}
module Test where

import Control.Monad
import Language.Haskell.TH

left x = 'l':x
right x = 'r':x

genL' ('r':[]) = Just $ VarE 'right
genL' ('l':[]) = Just $ VarE 'left
genL' (x:xs) =   Just $ InfixE (genL' [x]) (VarE '(.)) (genL' xs)

genL f = let name = mkName $ "go_" ++ f in let (Just exp) = genL' f in [ValD (VarP name) (NormalB exp) []]

genI i = return $ join $ map genL i

anonymous
()
Ответ на: комментарий от www_linux_org_ru

Это ваше «ленивое инстанцирование» делает функциональный язык шаблонов с++ нечистым и слабопредсказуемым. Да и вообще, задача в топике не для шаблонов совсем.

balodja ★★★
()
Ответ на: комментарий от Miguel

Я тебе первым комментом написал, как оно должно выглядеть.

Ну это понятно. Просто надо учесть - есть старый lisp-like, fortran-like стиль когда иногда приходится делать много похожих функций каждая из которых довольно проста (как пример c{[a|d]+}r). Это в более позднее время появилась возможность писать более общие алгоритмы в терминах ФВП (эти [L,R,L,R], например, можно обработать рекурсивно) или дописывать компилятору процедуры трансляции чтобы более тяжёлый (обычно) общий алгоритм приблизился в производительности к простым функциям (которых пачка). Вот, на самом деле я думаю что TH мало используют - потому что на вопрос «а как сделать то-то» следует ответ «а не нужно это делать», тогда как обычно (когда речь идёт о чём-то более практикуемом, но о TH) можно ожидать ответ «делать вот так [код], но не нужно - лучше так [другой код]».

quasimoto ★★★★
() автор топика
Ответ на: oops от anonymous

Грязно, но работает. Хаскель не знаю, TH - тем более, потратил на просмотр примеров по TH 15 минут. По-моему, это можно сделать по-лучше.

Спасибо.

quasimoto ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.