Krautkanal.com

Veröffentlicht am 2016-01-05 17:54:20 in /prog/

/prog/ 8253: Haskell

kuldarkalvik Avatar
kuldarkalvik:#8253

Hallo Schlaubernd, ich versuche gerade, mir Haskell beizubringen.

Ich möchte eine Funktion schreiben, die die Summe einer Liste bildet - Bei Zahlen die gewöhnliche Summe, bei boolschen Werten das logische "Und".

Rufe ich meine Funktion auf mit
>summe [True, True, True, False]
kommt korrekterweise
>False
heraus. Rufe ich sie aber mit einer [Int] auf, kommt ein Fehler:

Main> summe [1,2,3]
ERROR - Unresolved overloading
*** Type : (Num a, S a) => a
*** Expression : summe [1,2,3]

Ich dachte erst, das Problem sei die Rekursion, aber auch das Entfernen dieser liefert den gleichen Fehler. Kannst du mir sagen, wo mein Fehler liegt?

t. Dummbernd

Auch: Finde Haskell recht spaßig. Warum ist es nicht wirklich verbreitet?

tusharvikky Avatar
tusharvikky:#8255

Glaube es liegt daran, dass Haskell nicht weiß, welchen Typ du meinst, wenn du "1" schreibst. Das könnte ja ein Int sein, aber z.B. auch ein Float oder ein Integer.

Ich glaube, du könntest es lösen, wenn du entweder instance S Int bzw. instance S Float durch instance S Num ersetzt, oder indem du den Typ beim Aufrufen fest vorgibst (summe[(1::Int), (2::Int), (3::Int)]).

Könnte aber auch völliger Unsinn sein, was ich hier erzähle.

t. nur sehr wenig Kenntnisse in Haskell

karlkanall Avatar
karlkanall:#8256

Hab schon auf /b nicht verstanden was OP will. Er pfostiert einen Schirmknall wo alles geht und jammert dann über einen Fehler.

saulihirvi Avatar
saulihirvi:#8257

>>8255
Es funktioniert, wenn ich hinter dem Array den Typ angebe (z.B. summe [1,2,3]::Float)
Mit "Num" werde ich es nochmal probieren, danke für den Tipp!

>>8256
Aber es funktioniert ja nicht alles.

llun Avatar
llun:#8261

>>8257
Läuft jetzt?

Würde übrigens empfehlen, summe über foldr zu implementieren, da du im Wesentlichen einen Fold machst. Spart dir ein klein wenig Code.

crhysdave Avatar
crhysdave:#8263

Haskell-Bernd reportiert ein.

>>8255
Deine Erklärung stimmt soweit. Zahlen-Literale haben zunächst mal nur die Eigenschaft, eines Typs der Typklasse Num zu sein. Daher weiß der Compiler erstmal nicht, was OP mit [1,2,3] meint.

Leider kannst Du nicht mal so eben instance S Num schreiben. Guck mal auf StackOverflow nach "Constraint is no smaller than the instance head".

>>8253
OP, was Du da bastelst ist im Wesentlichen Deine eigene Version der Funktion mconcat aus Data.Monoid. Vielleicht möchtest Du ja das hier https://hackage.haskell.org/package/base-4.8.1.0/docs/Data-Monoid.html lesen. Hier siehst Du auch, wie newtype-Wrapper verwendet werden, um das oben genannte Problem "Constraint is no smaller than the instance head" zu umgehen.

Um das konkret zu illustrieren:
Main> import Data.Monoid
Main> mconcat [Sum 1, Sum 2, Sum 3]
Sum {getSum = 6}
Main> mconcat [All True, All False]
All {getAll = False}

Ich hoffe, das hilft Dir einigermaßen weiter.

jonkspr Avatar
jonkspr:#8264

>>8261
Ja, funktioniert jetzt.

Der korrekte foldr-Ausdruck wäre
>foldr (+) 0 [1,2,3]
bzw.
>foldr (+) 0.0 [1.1,2.2,3.3]
, oder?
In der Funktion also jeweils
>summe [] = 0
>summe xs = foldr (+) 0 xs

Bin mir im Umgang mit foldr noch sehr unsicher.

>>8263
Danke für deine ausführliche Erklärung! Ich habe nur keine Ahnung, was ich mit Monoiden machen soll, ich denke, ich werde darauf zurückkommen, wenn ich etwas erfahrener in Haskell bin.
Wofür benutzt du Haskell?

creartinc Avatar
creartinc:#8266

>>8264
>summe [] = 0
>summe xs = foldr (+) 0 xs

foldr ist so definiert:
>foldr f z [] = z
>foldr f z (x:xs) = f x (foldr f z xs)

Es kann also auch mit der leeren Liste umgehen, deshalb musst du das nicht extra abfangen. Die zweite Zeile reicht.

Ansonsten denke ich deine Ausdrücke passen so. (Hab aber ewig kein Haskell benutzt.)

n_tassone Avatar
n_tassone:#8274

>>8264
Keine Ursache. Die Lösung von >>8266 ist sicherlich auch erstmal einfacher. Ich hatte auf Grund Deiner ursprünglichen Fragestellung den Eindruck, dass Du eher nach Monoiden auf der Suche bist als nach fold. Wie auch immer.

Was Du mit Monoiden machen sollst: die Typklasse Monoid umfasst Typen, für die man (sinnvoll) mit einer assoziativen binären Operation verknüpfen kann. Diese Operation nennen wir mal mappend. Wie der Name schon suggeriert, ist die Idee hier, dass man Monoid-Objekte irgendwie "aneinanderhängt". Das ist ein sehr generisches Konstrukt und daher zu allerlei Dingen gut. Du kannst beispielsweise die Funktion (++) auf Listen betrachten. Jede Liste ist von der Typklasse Monoid und mappend ist für Listen schlicht (++). Demnach ist [1,2] `mappend` [3] auch [1,2,3]. Jetzt kann man das natürlich auch auf andere Typen. Jetzt fragst Du Dich vielleicht: was soll ich damit - da kann ich ja auch gleich (++) nehmen. Stimmt. Aber was wäre, wenn Du vielleicht keine Listen, sondern Maybe [Int] konkatenieren wollen würdest? Hier gibt es mehrere Möglichkeiten. Eine davon wäre, die Tatsache zu nutzen, dass Maybe [Int] auch eine Monoid-Instanz hat. Die Konkatenation läuft so wie Du erwarten würdest: Nothing `mappend` Just [1] ergibt Just [1], Just [1] `mappend` Just [2,3] ergibt [1,2,3]. Die Verwendung der korrekten Typklasse erlaubt es Dir also, Deine Funktionen so generisch zu halten, dass Du und andere sie später auch in anderem Kontext wiederverwenden können. Es gibt noch weitere lustige Monoid-Instanzen - ein paar davon siehst Du in meinem Beitrag oben (>>8263).

Ich kann mir einfach nicht verkneifen, Dich (für später?) darauf hinzuweisen, dass Die Funktion fold und Monoide über die Typklasse Foldable einen interessanten Berührungspunkt haben.

Haskell benutze ich für meine Projekte - für berufliche (manchmal) wie für private (öfter). Gerade wenn es etwas ist, bei dem mir die Abwesenheit von Laufzeitfehlern wichtig ist, weiß ich Haskell zu schätzen. Könnte ich besser programmieren, so würde ich wohl auch in anderen Sprachen weniger fehlerhaften Code produzieren ;)

to_soham Avatar
to_soham:#8275

>>8274

> Jetzt kann man das natürlich auch auf andere Typen.
Streich das.

>Just [1] `mappend` Just [2,3] ergibt [1,2,3].
Ich meinte: ergibt Just [1,2,3].

sunshinedgirl Avatar
sunshinedgirl:#8358

Haskell ist eine großartige Sprache. Bernd hat sie leider erst vor 2 Jahren gefunden.. mittlerweile hält Bernd sogar eine fortgeschrittenen-Vorlesung an der Uni drüber :p

Was du eigentlich haben willst ist die generische Monoid-Faltung:

> foldr mappend mempty

Problem bei Zahlen/Matrizen/anderen Mathe-Sachen ist halt: Hier gibt es 2 mögliche Monoid-Instanzen: einmal mit (+) und 0 und mit (*) und 1 - daher ist keine global definiert.
Bei Bool, Listen, Bäumen etc. macht die aber das richtige.

Wichtig sind halt auch noch die Regeln:

> mempty `mappend` a = a
> a `mappend` mempty = a
> (a `mappend` b) `mappend` c = a `mappend` (b `mappend` c)

--

Wenn du dir ein paar weitere Typklassen ansehen willst, empfiehlt Bernd: Functor, Monoid, Eq, Ord, Show.. Wenn du die verstanden hast, dann kannst du weitergehen zu den etwas schwerereren: Applicative, Alternative, Monad (und die zillionen Monad-Instanzen wie Maybe, List, State, Reader, Writer, ...), MonadPlus, Foldable, Traversable.

Wenn du ganz Tapfer bist dann kannst du auch noch in Fix, Free, Cofree, Contravariant, Bifunctor, Profunctor, Bazaar, Comonad (in verschiedenen Varianten wie CoState, CoReader, CoWriter, ...) etc. reinschauen.. aber da wird es dann sehr Kategorien-Theoretisch (aber man verwendet die trotzdem noch im Code).

Und das ist erst der Anfang :) *hust**hust*Yoneda-Lemma*hust**hust*

Ein Großartige Welt der Abstraktion wartet da.. wo man nachher nur noch 2-3 magische Codezeilen schreibt und der Rest in den Abstraktionen hängt und IMMER ordentlich funktioniert :)

vikashpathak18 Avatar
vikashpathak18:#8360

>>8358
> mittlerweile hält Bernd sogar eine fortgeschrittenen-Vorlesung an der Uni drüber :p

Gibt es eventuell Slides/Übungsmaterial von der besagten Vorlesung?

turkutuuli Avatar
turkutuuli:#8488

>>8360
Wird wahrscheinlich aus Nacktmachierungsgründen nicht gepostet werden.

Aber würde von besagtem Bernd sehr gerne Literatur- oder Vorlesungstipps entgegennehmen.

nerrsoft Avatar
nerrsoft:#8489

>>8488
Bernd würde hier generischerweise "Learn You a Haskell For Great Good" und "Real World Haskell" empfehlen.

Neuste Fäden in diesem Brett: