Má Haskell budoucnost?

v

Re:Má Haskell budoucnost?
« Odpověď #255 kdy: 16. 05. 2016, 21:28:52 »
Nepřipadá mi, že by to umělo retry, jak je použito v tom příkladu výše? Pletu se?
Nepleteš se, retry to neumí, ale zkus přijmout, že retry i případný timeout je naprosto minoritní funkcionalita, kterou si snadno doděláš. Trochu jsem si s tím v C++ hrál a zajímalo by mě, jestli tohle dokážeš napsat stejně elegantně a abstraktně i v Haskellu? Uznávám, že je to trochu školometský příklad:
Kód: [Vybrat]
#include <string>
#include <thread>
#include <iostream>

template<typename T>
class ThreadSafeClass
{
public:
    ThreadSafeClass() : m_value(T()) {}

    T get() const {
        return m_value;
    }

    ThreadSafeClass& operator += (const T value) {
        __transaction_relaxed { m_value += value; }
        return *this;
    }

private:
    T m_value;
};


template<typename T>
void updateThread(ThreadSafeClass<T>& tsc, const T value)
{
    for (int i = 0; i < 100; ++i) {
        tsc += value;
    }
}


int main()
{
    ThreadSafeClass<int> safeInt;
    ThreadSafeClass<double> safeDouble;
    ThreadSafeClass<std::string> safeString;

    std::thread t1([&]{updateThread(safeInt, 1);});
    std::thread t2([&]{updateThread(safeInt, 2);});
    std::thread t3([&]{updateThread(safeDouble, 1.0);});
    std::thread t4([&]{updateThread(safeDouble, 2.0);});
    std::thread t5([&]{updateThread(safeString, std::string("A"));});
    std::thread t6([&]{updateThread(safeString, std::string("B"));});

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
    t6.join();

    std::cout << safeInt.get() << std::endl;
    std::cout << safeDouble.get() << std::endl;
    std::cout << safeString.get() << std::endl;

    return 0;
}
Obecná třída pro thread safe operaci + nad libovolným datovým typem (včetně stringu), máš to kompletní i s testem. Pokud vím, v Haskellu to musí být TVar? V C++ žádné takové omezení není, může to být libovolná proměnná.
TVar je vlastně ekivalent toho vašeho ThreadSafeClass, s rozdílem, že TVar nemá chybu ve čtení ve čtení hodnoty a je možné na obsah použít libovolnou operaci, ne jen +


gamer

Re:Má Haskell budoucnost?
« Odpověď #256 kdy: 16. 05. 2016, 21:37:36 »
TVar je vlastně ekivalent toho vašeho ThreadSafeClass, s rozdílem, že TVar nemá chybu ve čtení ve čtení hodnoty a je možné na obsah použít libovolnou operaci, ne jen +
Můžeš sem dát kód v Haskellu, který pro libovolný datový typ podporující operaci + přičtě něco ve více threadech a bude používat STM?

v

Re:Má Haskell budoucnost?
« Odpověď #257 kdy: 16. 05. 2016, 22:02:13 »
TVar je vlastně ekivalent toho vašeho ThreadSafeClass, s rozdílem, že TVar nemá chybu ve čtení ve čtení hodnoty a je možné na obsah použít libovolnou operaci, ne jen +
Můžeš sem dát kód v Haskellu, který pro libovolný datový typ podporující operaci + přičtě něco ve více threadech a bude používat STM?
vyšlo mi to takhle:
Kód: [Vybrat]
import Control.Concurrent.Async
import Control.Concurrent.STM

incrementTVar v k = atomically (modifyTVar' v (+ k))

tVarIncrementingProcess v k = sequence (replicate 100 (incrementTVar v k))

main = do
v0 <- newTVarIO 0 :: IO (TVar Integer)
p0 <- async (tVarIncrementingProcess v0 10)
wait p0

gamer

Re:Má Haskell budoucnost?
« Odpověď #258 kdy: 16. 05. 2016, 22:29:20 »
Kód: [Vybrat]
v0 <- newTVarIO 0 :: IO (TVar Integer)
p0 <- async (tVarIncrementingProcess v0 10)
Tohle bude fungovat i pro string? Nebo nějaký jiný typ, pro který má smysl sčítat (vektor, matice...)? Co dělám blbě?
Kód: [Vybrat]
    v0 <- newTVarIO "" :: IO (TVar String)
    p0 <- async (tVarIncrementingProcess v0 "A")

Kód: [Vybrat]
    No instance for (Num String)
      arising from a use of `tVarIncrementingProcess'
    Possible fix: add an instance declaration for (Num String)
    In the first argument of `async', namely
      `(tVarIncrementingProcess v0 "A")'
    In a stmt of a 'do' block:
      p0 <- async (tVarIncrementingProcess v0 "A")
    In the expression:
      do { v0 <- newTVarIO "" :: IO (TVar String);
           p0 <- async (tVarIncrementingProcess v0 "A");
           wait p0 }

Re:Má Haskell budoucnost?
« Odpověď #259 kdy: 16. 05. 2016, 22:33:19 »
Kód: [Vybrat]
v0 <- newTVarIO 0 :: IO (TVar Integer)
p0 <- async (tVarIncrementingProcess v0 10)
Tohle bude fungovat i pro string? Nebo nějaký jiný typ, pro který má smysl sčítat (vektor, matice...)? Co dělám blbě?
Kód: [Vybrat]
    v0 <- newTVarIO "" :: IO (TVar String)
    p0 <- async (tVarIncrementingProcess v0 "A")

Kód: [Vybrat]
    No instance for (Num String)
      arising from a use of `tVarIncrementingProcess'
    Possible fix: add an instance declaration for (Num String)
    In the first argument of `async', namely
      `(tVarIncrementingProcess v0 "A")'
    In a stmt of a 'do' block:
      p0 <- async (tVarIncrementingProcess v0 "A")
    In the expression:
      do { v0 <- newTVarIO "" :: IO (TVar String);
           p0 <- async (tVarIncrementingProcess v0 "A");
           wait p0 }

Vzdyt ti to ta chybova hlaska rika - String neni instance Num. Retezeni stringu ostatne neni v Haskellu + ale ++


gamer

Re:Má Haskell budoucnost?
« Odpověď #260 kdy: 16. 05. 2016, 22:34:41 »
Vzdyt ti to ta chybova hlaska rika - String neni instance Num. Retezeni stringu ostatne neni v Haskellu + ale ++
OK, jak to teda mám v Haskellu napsat, aby to fungovalo s libovolným datovým typem? V C++ to jde.

v

Re:Má Haskell budoucnost?
« Odpověď #261 kdy: 16. 05. 2016, 22:41:17 »
Vzdyt ti to ta chybova hlaska rika - String neni instance Num. Retezeni stringu ostatne neni v Haskellu + ale ++
OK, jak to teda mám v Haskellu napsat, aby to fungovalo s libovolným datovým typem? V C++ to jde.
záleží co od toho vlastně chcete, jaký problém tím chcete vyřešit, řetězce se nesčítají, ale řetězí, taky můžete použít mappend, ale to je zase něco jiného, nebo těm vláknům rovnou předat funkci, kterou chcete aplikovat

gamer

Re:Má Haskell budoucnost?
« Odpověď #262 kdy: 16. 05. 2016, 22:53:41 »
záleží co od toho vlastně chcete, jaký problém tím chcete vyřešit, řetězce se nesčítají, ale řetězí, taky můžete použít mappend, ale to je zase něco jiného, nebo těm vláknům rovnou předat funkci, kterou chcete aplikovat
No já bych chtěl obecné řešení na sčítání datových typů, které se sčítat umí. Jsem ochoten smířit se s tím, že string se v Haskellu sčítat neumí. Co třeba vektor, šlo by to? Neznám tu správnou syntaxi v Haskellu, něco takového by fungovalo?
Kód: [Vybrat]
import Data.Vector
main = do
    let v1 = fromList [0, 0]
    let v2 = fromList [1, 1]
    v0 <- newTVarIO v1 :: IO (TVar Data.Vector)
    p0 <- async (tVarIncrementingProcess v0 v2)
    wait p0

v

Re:Má Haskell budoucnost?
« Odpověď #263 kdy: 16. 05. 2016, 22:57:53 »
záleží co od toho vlastně chcete, jaký problém tím chcete vyřešit, řetězce se nesčítají, ale řetězí, taky můžete použít mappend, ale to je zase něco jiného, nebo těm vláknům rovnou předat funkci, kterou chcete aplikovat
No já bych chtěl obecné řešení na sčítání datových typů, které se sčítat umí. Jsem ochoten smířit se s tím, že string se v Haskellu sčítat neumí. Co třeba vektor, šlo by to? Neznám tu správnou syntaxi v Haskellu, něco takového by fungovalo?
Kód: [Vybrat]
import Data.Vector
main = do
    let v1 = fromList [0, 0]
    let v2 = fromList [1, 1]
    v0 <- newTVarIO v1 :: IO (TVar Data.Vector)
    p0 <- async (tVarIncrementingProcess v0 v2)
    wait p0
pro použití funcke (+) musíte mít nadefinovanou pro daný type třídu Num (ve skutečnosti nemusíte, ale slušní lidi to tak dělají)
já jsem ji pro vás napsal pro String :D
Kód: [Vybrat]
{-# LANGUAGE FlexibleInstances #-}
instance Num [Char] where
(+) = (++)
(*) _ _ = error "na tohle je už dneska moc hodin"
abs = id
signum _ = ":-)"
fromInteger = show
negate = reverse
asi to není problém pro žádný typ, ale někdy to moc nedává smysl

gamer

Re:Má Haskell budoucnost?
« Odpověď #264 kdy: 16. 05. 2016, 23:16:48 »
pro použití funcke (+) musíte mít nadefinovanou pro daný type třídu Num (ve skutečnosti nemusíte, ale slušní lidi to tak dělají)
já jsem ji pro vás napsal pro String :D
Kód: [Vybrat]
{-# LANGUAGE FlexibleInstances #-}
instance Num [Char] where
(+) = (++)
(*) _ _ = error "na tohle je už dneska moc hodin"
abs = id
signum _ = ":-)"
fromInteger = show
negate = reverse
asi to není problém pro žádný typ, ale někdy to moc nedává smysl
To je to řešení, které jsem hledal, díky. Připadá mi to teda trochu jako hack, ale budiž, když to bude fungovat... C++ mi z toho vychází líp, nemusím takové opičárny dělat, stačí aby se ten objekt uměl sčítat. Třeba pro vektor bez obalovací classy, která se nelíbila:
Kód: [Vybrat]
#include <string>
#include <thread>
#include <iostream>
#include <boost/numeric/ublas/vector.hpp>

template<typename T>
void updateThread(T& base, const T& value)
{
    for (int i = 0; i < 100; ++i) {
        __transaction_relaxed { base += value; }
    }
}

int main()
{
    boost::numeric::ublas::vector<double> v1(2);
    boost::numeric::ublas::vector<double> v2(2);

    std::thread t1([&]{updateThread(v1, v2);});
    std::thread t2([&]{updateThread(v1, v2);});

    t1.join();
    t2.join();

    return 0;
}
Líbí se mi to víc, než definovat Num v Haskellu.

andy

Re:Má Haskell budoucnost?
« Odpověď #265 kdy: 16. 05. 2016, 23:18:35 »
No já bych chtěl obecné řešení na sčítání datových typů, které se sčítat umí. Jsem ochoten smířit se s tím, že string se v Haskellu sčítat neumí. Co třeba vektor, šlo by to? Neznám tu správnou syntaxi v Haskellu, něco takového by fungovalo?
Umí se sčítat všechny typy, co jsou Num. Základní seznam je tady: http://hackage.haskell.org/package/base-4.8.2.0/docs/Prelude.html#t:Num
Pak existuje forma "sčítání" Monoid (operátor <> z Data.Monoid). Ten je základně definovaný pro tyhle typy: http://hackage.haskell.org/package/base-4.8.2.0/docs/Data-Monoid.html, je definovaný i pro čísla, ale přes newtype Sum a Product, protože obojí je Monoid a je potřeba si zvolit.

Oni haskellisti když definují typeclassy, tak typicky vymýšlejí nějaké zákony, které by ta TypeClass měla splňovat, aby se na to dalo spolehnout a ty funkce, které závisí např. na "Num" dávaly rozumné výsledky pro jakýkoliv typ Num, který do ní vleze. Což pro string úplně nefunguje (co String krát String?). Takže na práci se stringama mají jinou typeclass. Ale není problém si definovat vlastní typeclass s vlastníma funkcema třeba takhle:
Kód: [Vybrat]
class Scitej a where
  .+. :: a -> a -> a
instance Scitej Int where
  .+. = +
instance Scitej String where
  .+. = ++

incrementTVar :: Scitej a => TVar a -> a -> STM ()
incrementTVar v k = atomically (modifyTVar' v (.+. k))


Citace
Nepleteš se, retry to neumí, ale zkus přijmout, že retry i případný timeout je naprosto minoritní funkcionalita, kterou si snadno doděláš.
No úplně minoritní není, protože prakticky jediný způsob, jak to dodělat, je udělat nějakou condition variable, která globálně při výstupu z transakce pošle signál.
Další věc je, že v Haskellu jediný způsob, jak přistupovat k těmhe proměnným, je v "atomically" bloku. V C++ nikoliv. Takže když ti někdo v kódu změní ta data mimo "transakci", tak hodně štěstí s hledáním chyb...
Citace
Kód: [Vybrat]
import Data.Vector
main = do
    let v1 = fromList [0, 0]
    let v2 = fromList [1, 1]
    v0 <- newTVarIO v1 :: IO (TVar Data.Vector)
    p0 <- async (tVarIncrementingProcess v0 v2)
    wait p0
Tak otázka je, co myslíte tady pod pojmem sčítání. Vector má Monoid (tzn. <>, aneb append). Ale mohl byste si to definovat třeba jako:
Kód: [Vybrat]
instance Scitej a => Scitej (Vector a) where
    .+. = Data.Vector.zipWith (+)
A teď  to bude fungovat na vektor s jakýmkoliv obsahem, jehož obsah je instancí Scitej.

andy

Re:Má Haskell budoucnost?
« Odpověď #266 kdy: 16. 05. 2016, 23:22:58 »
Citace
C++ mi z toho vychází líp, nemusím takové opičárny dělat, stačí aby se ten objekt uměl sčítat
Tak jen tak ze srandy - vector je v haskellu typ, který může obsahovat cokoliv (ne jen čísla). Něco jako vector v C++. Vector v C++ se IMO neumí standardně sčítat. Jak složité bude donutit vector v C++, aby se uměl sčítat, pokud se jeho prvky umí sčítat?

v

Re:Má Haskell budoucnost?
« Odpověď #267 kdy: 16. 05. 2016, 23:25:17 »
pro použití funcke (+) musíte mít nadefinovanou pro daný type třídu Num (ve skutečnosti nemusíte, ale slušní lidi to tak dělají)
já jsem ji pro vás napsal pro String :D
Kód: [Vybrat]
{-# LANGUAGE FlexibleInstances #-}
instance Num [Char] where
(+) = (++)
(*) _ _ = error "na tohle je už dneska moc hodin"
abs = id
signum _ = ":-)"
fromInteger = show
negate = reverse
asi to není problém pro žádný typ, ale někdy to moc nedává smysl
To je to řešení, které jsem hledal, díky. Připadá mi to teda trochu jako hack, ale budiž, když to bude fungovat... C++ mi z toho vychází líp, nemusím takové opičárny dělat, stačí aby se ten objekt uměl sčítat. Třeba pro vektor bez obalovací classy, která se nelíbila:
Kód: [Vybrat]
#include <string>
#include <thread>
#include <iostream>
#include <boost/numeric/ublas/vector.hpp>

template<typename T>
void updateThread(T& base, const T& value)
{
    for (int i = 0; i < 100; ++i) {
        __transaction_relaxed { base += value; }
    }
}

int main()
{
    boost::numeric::ublas::vector<double> v1(2);
    boost::numeric::ublas::vector<double> v2(2);

    std::thread t1([&]{updateThread(v1, v2);});
    std::thread t2([&]{updateThread(v1, v2);});

    t1.join();
    t2.join();

    return 0;
}
Líbí se mi to víc, než definovat Num v Haskellu.
ale ten můj prvotní kód je pro typy co se dají sčítat!
naopak ten váš kód není, vždyť pro sčítání platí a+b=b+a, platí to u toho vašeho?

gamer

Re:Má Haskell budoucnost?
« Odpověď #268 kdy: 16. 05. 2016, 23:33:24 »
No úplně minoritní není, protože prakticky jediný způsob, jak to dodělat, je udělat nějakou condition variable, která globálně při výstupu z transakce pošle signál.
Ne, jde to udělat i bez condition variable, stačí počkat nějaký čas a potom to zkusit znovu. Pokud mi nevadí, že na nějakou dobu uspím thread, tak je to řešení.

Další věc je, že v Haskellu jediný způsob, jak přistupovat k těmhe proměnným, je v "atomically" bloku. V C++ nikoliv. Takže když ti někdo v kódu změní ta data mimo "transakci", tak hodně štěstí s hledáním chyb...
Když ty data schovám do nějaké třídy, tak je zvenku nikdo nezmění.

Tak otázka je, co myslíte tady pod pojmem sčítání. Vector má Monoid (tzn. <>, aneb append). Ale mohl byste si to definovat třeba jako:
Myslel jsem sčítání normálního matematického vektoru: https://en.wikipedia.org/wiki/Euclidean_vector#Addition_and_subtraction

gamer

Re:Má Haskell budoucnost?
« Odpověď #269 kdy: 16. 05. 2016, 23:37:08 »
ale ten můj prvotní kód je pro typy co se dají sčítat!
naopak ten váš kód není, vždyť pro sčítání platí a+b=b+a, platí to u toho vašeho?
Aha, rigidní matematik... Doporučuju nechat veřejně zostudit všechny tvůrce programovacích jazyků, kteří si dovolili pro operaci spojení řetězců použit operátor +, protože se těžce provili proti a+b=b+a.