LINUX.ORG.RU

[haskell] полугруппы нулей и единиц

 


0

4

Пусть есть полугруппа с двусторонней единицей, левыми нулями и правыми нулями. Допустим, нам уже вторую неделю известен хаскелл, посему можно выдавить следущий фекалокод (первое приближение, видимо, неверное полностью).

import Prelude hiding ((*))

data SGelement = SGe     -- two-sided identity element
               | SGr     -- right zero element
               | SGl     -- left zero element

instance Show SGelement where
  show SGe = "1"
  show SGr = "0r"
  show SGl = "0l"

(*) :: SGelement -> SGelement -> SGelement
SGl * _ = SGl
_ * SGr = SGr
SGe * x = x
x * SGe = x
_ * _ = error "*>: undefined behavior"

Дескать, определили классик SGelement (sg - semigroup), дата-объектиками которого может быть только либо двусторонняя единица, левый ноль или правый ноль. Иное нас не интересует. Ну и определили операцию (пускай, умножение) над этими элементиками.

> SGe Main.* SGr
0r
it :: SGelement

Ого, круто, умножили единицу на правый ноль, получили правый ноль. Удивительно.

> SGr Main.* SGr
0r
it :: SGelement

Ого, круто, умножили правый ноль на правый ноль, получили правый ноль. Непонятно только, какой из двух. То есть, с данным убогим классиком однозначно идентифицировать какой из правых нулей получился в результате, нельзя. А получился, очевидно, второй.

К чему это всё?

Допустим, есть полугруппа левых нулей с единицей, состоящая из трёх элементов, L = {e,l1,l2}. Есть полугруппа правых нулей без единицы, состоящая из двух элементов, R = {r1,r2}.

Рассмотрим их прямое произведение A = LxR = { (e;r1), (l1;r1), (l2;r1), (e;r2), (l1;r2), (l2;r2) }.

Как для каждого элемента x из A найти A*x? Допустим, для (e;r1):

(e;r1) * (e;r1) =  (e;r1)
(l1;r1) * (e;r1) =  (l1;r1)
(l2;r1) * (e;r1) =  (l2;r1)
(e;r2) * (e;r1) =  (e;r1)
(l1;r2) * (e;r1) =  (l1;r1)
(l2;r2) * (e;r1) =  (l2;r1)

Иными словами, (e,r1) можно представить как некоторое отображение из A в A с помощью поэлементного соответствия. То есть, (1,2,3,4,5,6) * (e,r1) = (1,2,3,1,2,3).

Вопрос - если для (e,r1) мы получили (1,2,3,1,2,3), то как получить ответы для остальных элементов A?

Допустим, даже получится всё это нахардкодить. 6 элементов ещё немного. А если потребуется подсчитать перестановочки для произведения аналогичных десятиэлементных полугрупп?

Подытоживая. Чувствуется, что можно очень ловко и нативно описать данную структуру. Но пока не представляю как. С радостью бы научился как надо.

★★

Последнее исправление: dmitry_malikov (всего исправлений: 1)

Что-то вроде такого:

data L = E | L1 | L2 deriving ( Eq, Show )
data R = R1 | R2 deriving ( Eq, Show )

ls :: [L]
ls = [E, L1, L2]

rs :: [R]
rs = [R1, R2]

(×) :: [a] -> [b] -> [(a, b)]
a × b = concat [[(x, y) | x <- a] | y <- b]

(∙) :: Eq a => (a, b') -> (a, b) -> (a, b)
x ∙ y = if fst x == fst y then y else (fst x, snd y)

-- > let prod = ls × rs
-- > prod
-- [(E,R1),(L1,R1),(L2,R1),(E,R2),(L1,R2),(L2,R2)]
-- > map (∙ head prod) prod
-- [(E,R1),(L1,R1),(L2,R1),(E,R1),(L1,R1),(L2,R1)]
quasimoto ★★★★
()

Любой левый ноль равен любому правому нулю. Так что не пойдёт с самого начала.

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

Теперь представим, что у нас L - стоэлементное. Как быть в таком случае?

Как определить ADT со ста конструкторами? Можно тупо взять числа, или поиграть в псевдо-зависимые типы (Fin). С прямым произведением понятно - будет [1 .. 100] × [1 .. 2], например. Я просто не вполне представляю что такое (∙) («для каждого элемента x из A найти A*x»), но её тип всё равно будет Eq a => (a, b') -> (a, b) -> (a, b), типом a * x = map (∙ x) a будет Eq a => [(a, b')] -> (a, b) -> [(a, b)], так что как-то они пишутся (в зависимости от того что нужно).

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

Алсо,

-- |
-- Consider a term @a@ of a type (forall t. [t]) as a set, so that |a| = length(a).
-- 
import Prelude hiding ( (^) )
import Data.Maybe
import Data.List

-- | The cartesian power of a set @a@.
-- 
-- If |a| = n then |a ^ m| = n ^ m.
-- 
(^) :: [t] -> Int -> [[t]]
a ^ 0 = [[]]
a ^ n = [x:ys | x <- a, ys <- a ^ (n - 1)]

-- | All the different binary operations that can be defined on a set @a@.
-- 
-- If |a| = n then |magmas(n)| = n ^ (n ^ 2).
-- 
magmas :: Eq t => [t] -> [t -> t -> t]
magmas a = map (curry . op) $ a ^ length ops
  where
    op rs x = rs !! fromJust (elemIndex x ops) -- fromJust!
    ops = [(x, y) | x <- a, y <- a] -- length ops = length a ^ 2

-- | All the different associative binary operations that can be defined on a set @a@.
-- 
-- if |a| = n then |semigroups(n)| <= n ^ (n ^ 2).
-- 
semigroups :: Eq a => [a] -> [a -> a -> a]
semigroups a = filter assoc $ magmas a
  where
    assoc f = and [(x `f` y) `f` z == x `f` (y `f` z) | x <- a, y <- a, z <- a]

pPrint :: [t] -> [t -> t -> t] -> [[(t, t, t)]]
pPrint a fs = [[(x, y, f x y) | x <- a, y <- a] | f <- fs]

pPrintMagmas :: Eq t => [t] -> [[(t, t, t)]]
pPrintMagmas a = pPrint a $ magmas a

pPrintSemigroups :: Eq t => [t] -> [[(t, t, t)]]
pPrintSemigroups a = pPrint a $ semigroups a

-- > pPrintMagmas []
-- [[]]
-- > pPrintMagmas [1]
-- [[(1,1,1)]]
-- > pPrintMagmas [1,2]
-- [[(1,1,1),(1,2,1),(2,1,1),(2,2,1)],[(1,1,1),(1,2,1),(2,1,1),(2,2,2)],[(1,1,1),(1,2,1),(2,1,2),(2,2,1)],[(1,1,1),(1,2,1),(2,1,2),(2,2,2)],[(1,1,1),(1,2,2),(2,1,1),(2,2,1)],[(1,1,1),(1,2,2),(2,1,1),(2,2,2)],[(1,1,1),(1,2,2),(2,1,2),(2,2,1)],[(1,1,1),(1,2,2),(2,1,2),(2,2,2)],[(1,1,2),(1,2,1),(2,1,1),(2,2,1)],[(1,1,2),(1,2,1),(2,1,1),(2,2,2)],[(1,1,2),(1,2,1),(2,1,2),(2,2,1)],[(1,1,2),(1,2,1),(2,1,2),(2,2,2)],[(1,1,2),(1,2,2),(2,1,1),(2,2,1)],[(1,1,2),(1,2,2),(2,1,1),(2,2,2)],[(1,1,2),(1,2,2),(2,1,2),(2,2,1)],[(1,1,2),(1,2,2),(2,1,2),(2,2,2)]]
-- > length $ pPrintMagmas [1,2]
-- 16
-- > length $ pPrintMagmas [1,2,3]
-- 19683
-- > pPrintSemigroups []
-- [[]]
-- > pPrintSemigroups [1]
-- [[(1,1,1)]]
-- > pPrintSemigroups [1,2]
-- [[(1,1,1),(1,2,1),(2,1,1),(2,2,1)],[(1,1,1),(1,2,1),(2,1,1),(2,2,2)],[(1,1,1),(1,2,1),(2,1,2),(2,2,2)],[(1,1,1),(1,2,2),(2,1,1),(2,2,2)],[(1,1,1),(1,2,2),(2,1,2),(2,2,1)],[(1,1,1),(1,2,2),(2,1,2),(2,2,2)],[(1,1,2),(1,2,1),(2,1,1),(2,2,2)],[(1,1,2),(1,2,2),(2,1,2),(2,2,2)]]
-- > length $ pPrintSemigroups [1,2]
-- 8
-- > length $ pPrintSemigroups [1,2,3]
-- 113
quasimoto ★★★★
()
Ответ на: комментарий от aedeph

нет бы порадоватся за человека. Абстрактная алгебра это тебе не по сцене скакать под фанеру.

bga_ ★★★★
()
Ответ на: комментарий от quasimoto
(×) ∷ [a] → [b] → [(a, b)]
a × b = [ (x, y) | y ← b, x ← a ]

С (∙) я не совсем согласен. Но в целом, то, что нужно.

И да, у Вас операторы типа (×) (∙) забиндены как-то? Неудобно же копировать каждый раз.

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

И да, у Вас операторы типа (×) (∙) забиндены как-то?

Скорей всего он набирает их с compose key.

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

Ну… В иксах есть модификаторы ввода различного уровня. Если я правильно понимаю, shift — модификатор второго уровня. Модификатор третьего уровня (у меня правый alt) позволяет вводить • при помощи восьмёрки, а × — при помощи x. А вот со стрелочками сложнее.

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

И да, у Вас операторы типа (×) (∙) забиндены как-то?

Кастомный input method в Emacs - C-x RET C-\ tex RET (http://www.artofproblemsolving.com/Wiki/index.php/LaTeX:Symbols) или C-x RET C-\ agda RET (http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Docs.UnicodeInput).

Для второго нужно добавить:

(load-file
 (let ((coding-system-for-read 'utf-8))
   (concat (file-name-directory
            (shell-command-to-string "~/.cabal/bin/agda-mode locate"))
           "agda-input.el")))

в ~/.emacs.

Ещё можно сделать:

(setq haskell-font-lock-symbols 'unicode)

для haskell-mode и включить -XUnicodeSyntax.

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

К сожалению, для емакса даже музыкальной растяжки пальцев не всегда хватает.

http://www.haskell.org/haskellwiki/Unicode-symbols#Vim - что-то про Vim есть.

Вообще, ни разу не видел пакета на хаскеле в котором бы использовались такие украшения (вот в агде такое любят), так что это скорее для примеров больше, в коде обычно plain ASCII.

quasimoto ★★★★
()

Какая жирнота.

С.КОРЗУН: «В сети появилась информация, что сводное от работы время вы проводите за чтением технической литературы и программированием на функциональных и динамических языках программирования».

Д.МАЛИКОВ: Я даже не знаю, что это такое. Я получаю в «Твиттер» очень много подобных сообщений, но это «клон». Я бы с удовольствием, но у меня не так много талантов, к сожалению, а технического нет совсем.

http://echo.msk.ru/programs/korzun/830052-echo/

anonymous
()

Когда тебя забанят, реквестирую твое перерождение под filip_kircoreoff, arkadiy_ukupnik.

anonymous
()

Почему в шоу-бизнесе так много маководов?

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

а мне еще можно iosif_kobzon для программирования на фаортранах, коболах и адах :3

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