Frage

Im folgenden Snippet können Sie meine beiden Collatz -Funktionen sehen, die ich in Haskell geschrieben habe. Für die rekursive Anwendung habe ich Klammern im ersten Beispiel (Collatz) verwendet, um den richtigen Vorrang zu erhalten.

Da ich gerade die Funktionsanwendung mit $ gelernt habe, habe ich versucht, die Funktion (Collatz ') mit diesem Ding neu zu schreiben. Ich stoße jedoch auf den folgenden Fehler:

Konnte nicht mit dem erwarteten Typ [a] gegen den abgeleiteten Typ "a1 -> [a1] im zweiten Argument von "(:)" übereinstimmen, nämlich "Collatz" im ersten Argument von "($)", nämlich `n: collatz '' im Ausdruck: n: collatz '$ n` div` 2

collatz :: (Integral a) => a -> [a]

collatz 1 = [1]

collatz n | even n    = n : collatz (n `div` 2)
          | otherwise = n : collatz (n * 3 + 1)

collatz' :: (Integral a) => a -> [a]

collatz' 1 = [1]

collatz' n | even n    = n : collatz' $ n `div` 2
           | otherwise = n : collatz' $ n * 3 + 1

Für mich nahm es seltsam, dass dies nicht funktioniert hat. Also habe ich ein ähnliches Beispiel ausprobiert, das funktioniert hat:

True : [even $ 3 `div` 3]

Ich würde es schätzen, wenn jemand einen Blick darauf werfen und mir sagen könnte, was ich falsch mache.

War es hilfreich?

Lösung

$ hat dann einen geringeren Vorrang : (und auch alles andere) also analysiert Ihre Funktion als

(n : collatz') $ (n `div` 2)

Dies führt zu Ihrem Typfehler. Das zweite Argument von : Erwartet eine Liste, aber Sie übergeben stattdessen die Collatz -Funktion.

Wenn Sie die Klammer um den 3N+1 -Teil noch vermeiden möchten, können Sie so etwas wie das Folgende tun

(n:) . collatz' $ n `div` 2
n : (collatz' $ n `div` 2)

Obwohl diese nicht unbedingt sauberer sind als das Original. Falls Sie sich fragen, die (n:) Im ersten Beispiel ist ein syntaktischer Zucker für \x -> n : x

Andere Tipps

Da andere erklärt haben, was das Problem ist, stellte ich fest, dass ich erklären werde, wie Sie dies selbst herausfinden können. (Einen Mann beibringt, fischen und so weiter ...)

Beachten Sie diesen Teil der Fehlermeldung:

Im ersten Argument von '($)' 'nämlich' n: collatz '' '

Das ist der Hinweis darauf zu bemerken, dass dies ein Vorrangproblem ist. GHC sagt dir das n : collatz' wurde als erstes Argument von analysiert $, während Sie erwarteten, dass das erste Argument gerecht ist collatz'.

Zu diesem Zeitpunkt stehe ich normalerweise GHCI ab und überprüfe die Priorität :info Befehl:

> :info :
data [] a = ... | a : [a]   -- Defined in GHC.Types
infixr 5 :
> :info $
($) :: (a -> b) -> a -> b   -- Defined in GHC.Base
infixr 0 $

Es heißt, dass die Voraussetzung von : ist 5, während der Vorrang von $ ist 0, was erklärt, warum die : ist bindend "enger" als die $.

: bindet stärker als $. In Betracht ziehen

Prelude> let f x = [x]
Prelude> 1 : f 2
[1,2]
Prelude> 1 : f $ 2

<interactive>:1:5:
    Couldn't match expected type `[a0]' with actual type `t0 -> [t0]'
    In the second argument of `(:)', namely `f'
    In the expression: 1 : f
    In the expression: 1 : f $ 2

Beachten Sie den "Ausdruck" 1 : f vom Parser gefunden; es sieht (1 : f) $ 2 statt 1 : (f $ 2).

Wie @missingno sagte, handelt es sich um ein Vorrangproblem. Sie könnten es so umschreiben

collatz' n | even n    = n : (collatz' $ n `div` 2)
           | otherwise = n : (collatz' $ n * 3 + 1)

Aber das kauft dich offensichtlich nicht viel, weil du immer noch Klammern hast.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top